Standards-aligned, consent-respecting API for social protection data exchange.
OpenSPP API V2 provides a modern, secure REST API for accessing OpenSPP registry data. It is designed for:
- G2P Connect / DCI compliance - Follows international social protection interoperability standards
- Consent-based access - All data access requires explicit consent from registrants
- External identifiers - Never exposes internal database IDs
- Namespace URIs - Uses globally unique URIs for all identifier types
- Source tracking - Tracks data provenance per ADR-008
All resources are identified by external identifiers with namespace URIs:
{
"identifier": [
{
"system": "urn:gov:ph:psa:national-id",
"value": "PH-123456789"
}
]
}Client credentials flow with JWT tokens:
# Get token
curl -X POST http://localhost:8069/api/v2/spp/oauth/token \
-H "Content-Type: application/json" \
-d '{
"grant_type": "client_credentials",
"client_id": "your-client-id",
"client_secret": "your-client-secret"
}'
# Use token
curl http://localhost:8069/api/v2/spp/Individual/urn:gov:ph:psa:national-id|PH-123 \
-H "Authorization: Bearer YOUR_TOKEN"Every API response is filtered based on:
- Active consent from the registrant
- Consent scope (which fields can be accessed)
- API client scope (which operations are permitted)
If no consent exists, only minimal data (identifier) is returned.
Uses spp.vocabulary.code for coded values:
# Gender is Many2one to spp.vocabulary.code, NOT a string
gender_id.namespace_uri # "urn:iso:std:iso:5218"
gender_id.code # "2"
gender_id.display # "Female"All data created/updated via API is tracked:
partner.source_system # "urn:openspp:api-client:client-123"
partner.collection_method # "api"
partner.last_update_system # "urn:openspp:api-client:client-123"-
Install dependencies:
pip install pyjwt
-
Install the module via Odoo Apps or command line:
odoo -i spp_api_v2
-
JWT secret is automatically generated on module install. To customize:
Key: spp_api_v2.jwt_secret Value: <secure random string>Generate a custom secret:
python -c "import secrets; print(secrets.token_urlsafe(64))" -
Create API client:
- Go to Configuration > API V2 > API Clients
- Create new client
- Copy client_id and client_secret
- Add scopes (individual:read, individual:create, etc.)
POST /oauth/token- Get access token
GET /metadata- Get capability statement (public)
GET /Individual/{identifier}- Read by identifierGET /Individual- Search individualsPOST /Individual- Create individualPUT /Individual/{identifier}- Update individual
GET /Group/{identifier}- Read by identifierGET /Group- Search groupsPOST /Group- Create groupPUT /Group/{identifier}- Update group
This module implements several Architecture Decision Records (ADRs):
- ADR-007: Namespace URIs for Identifiers
- ADR-008: Source Tracking and Provenance
- ADR-009: Terminology System (Vocabulary)
See docs/architecture/decisions/ for full ADR documentation.
Tier 3 - Technical Privileges:
API V2: Read- Read access to API configurationAPI V2: Write- Modify access to API configurationAPI V2: Create- Create new API clients
Tier 2 - User-Facing Groups:
API V2 Viewer- View API clients and consentsAPI V2 Officer- Manage consentsAPI V2 Manager- Full API configuration control
spp_api_v2.jwt_secret- JWT signing secret (auto-generated on install)spp_api_v2.token_expiration- Token lifetime in seconds (default: 3600)
- Rate limiting: The
rate_limit_per_minuteandrate_limit_per_dayfields on API clients are defined but not enforced. Rate limiting middleware will be added in a future release.
spp_api_v2/
├── models/ # Odoo models (API client, consent, etc.)
├── schemas/ # Pydantic schemas for API resources
├── services/ # Business logic (mapping, search, consent)
├── routers/ # FastAPI routers (endpoints)
├── middleware/ # JWT authentication
├── security/ # Access rights
├── data/ # Config and endpoint registration
└── views/ # UI views
IndividualService- CRUD and mapping for Individual resourceGroupService- CRUD and mapping for Group resourceSearchService- Search parameter parsing and executionConsentService- Consent filtering and access control
Tests are located in the tests/ directory. Run with:
odoo -i spp_api_v2 --test-enable --stop-after-initIf you see "JWT secret not configured", set it in System Parameters:
Settings > Technical > Parameters > System Parameters
Key: spp_api_v2.jwt_secret
Value: <your-secret-key>
If API returns only identifier, check:
- Does an active consent exist for this registrant/client?
- Is the consent scope correct for the resource type?
- Has the consent expired?
API expects identifiers in format: {namespace_uri}|{value}
Example: urn:gov:ph:psa:national-id|PH-123456789
LGPL-3
- OpenSPP.org
- Newlogic Impact Lab
- Documentation: https://docs.openspp.org
- Issue Tracker: https://github.com/openspp/openspp-modules/issues