API V2 Overview
Contents
API V2 Overview#
For: developers
An introduction to OpenSPP's REST API — its design philosophy, base URL, and the core principles that shape every endpoint.
Prerequisites#
Familiarity with REST APIs and HTTP
Ability to issue HTTP requests (curl, Python
requests, JavaScriptfetch, etc.)An OpenSPP deployment with
spp_api_v2installed
What is API V2?#
OpenSPP API V2 is a modern REST API that provides programmatic access to social protection registry data. It enables:
Interoperability with G2P Connect, DCI, and national identity systems
Consent-based data sharing with field-level privacy controls
Extensibility for module-specific fields (farmer registry, disability, etc.)
Scale to 50M+ registrants with acceptable performance
Standards alignment using FHIR-inspired patterns
Why V2?#
API V2 completely replaces the legacy XML-RPC API with modern standards:
Feature |
V1 (XML-RPC) |
V2 (REST) |
|---|---|---|
Authentication |
Basic auth |
OAuth 2.0 |
Data format |
XML |
JSON |
Identifiers |
Database IDs |
External IDs (UUIDs) |
Privacy |
No consent |
Field-level consent |
Discovery |
None |
Capability statement |
Batch ops |
No |
Transaction bundles |
Base URL#
The API base URL depends on your deployment:
https://{your-domain}/api/v2/spp
For local development, the default is:
http://localhost:8069/api/v2/spp
Core Principles#
1. External Identifiers Only#
Never expose internal database IDs. All resources use external identifiers:
// ❌ WRONG - Database ID exposed
{
"id": 12345,
"name": "Maria Santos"
}
// ✅ CORRECT - External identifier
{
"identifier": [
{
"system": "urn:gov:ph:psa:national-id",
"value": "PH-123456789"
}
],
"name": {
"given": "Maria",
"family": "Santos"
}
}
2. Namespace URIs#
All coded values use URN namespaces for unambiguous identification:
Type |
Example |
|---|---|
National ID |
|
Gender (ISO 5218) |
|
Relationship |
|
Extension |
|
3. Consent by Default#
All data access requires either:
Explicit consent from the registrant, OR
Legal basis documented in the API client configuration
See Consent Management for details.
4. Fail Closed#
When in doubt (missing consent, ambiguous permissions), the API denies access and returns minimal data.
Authorization stack#
Every request passes through three layers in order (see ADR-022):
Authentication — JWT token validated against the API client record
Scope enforcement — endpoint checks that the client has the required
resource:actionscope (e.g.,individual:read)Consent filtering — response fields are filtered based on registrant consent and the client's legal basis
Authorization is enforced at the application layer, not through Odoo record rules — API clients are not Odoo users. See Authentication for scope details and Consent Management for the filtering rules.
FHIR-Inspired Patterns#
OpenSPP API V2 adopts these patterns from FHIR without full compliance:
Capability Statement (Metadata)#
Discover what the API supports (no authentication required):
GET /api/v2/spp/metadata
Response:
{
"name": "OpenSPP API",
"version": "2.0.0",
"resources": {
"Individual": {
"operations": ["read", "search", "create", "update", "patch"],
"search_params": ["identifier", "name", "birthdate", "gender", "address", "group"]
},
"Group": {
"operations": ["read", "search", "create", "update", "patch"],
"search_params": ["identifier", "name", "type", "member"]
},
"Program": {
"operations": ["read", "search"],
"search_params": ["identifier", "name", "status", "type", "targetType"]
},
"ProgramMembership": {
"operations": ["read", "search", "create", "update"],
"search_params": ["beneficiary", "program", "status"]
}
},
"extensions": [
{
"url": "urn:openspp:extension:farmer",
"module": "spp_farmer_registry",
"applies_to": ["Individual"],
"fields": ["farmSize", "farmSizeUnit", "primaryCrop"]
}
],
"authentication": {
"type": "oauth2",
"token_endpoint": "/api/v2/spp/oauth/token",
"grant_types": ["client_credentials"]
},
"docs": "/api/v2/spp/docs"
}
Extension modules (Entitlement, Cycle, GIS, etc.) add their resources to this response when installed.
Bundle Transactions#
Create multiple related resources atomically:
POST /api/v2/spp/$batch
All operations succeed or all fail (rollback).
CodeableConcept#
Represent coded values with their vocabulary:
{
"gender": {
"coding": [
{
"system": "urn:iso:std:iso:5218",
"code": "2",
"display": "Female"
}
],
"text": "Female"
}
}
Available Resources#
Resource |
Description |
Endpoint |
|---|---|---|
Individual |
Person in the registry |
|
Group |
Household or other group |
|
Program |
Social protection program |
|
ProgramMembership |
Enrollment in a program |
|
Consent |
Data sharing consent |
|
See API Resources for complete documentation.
Extension Resources#
Additional resources are available through extension modules:
Resource |
Module |
Description |
|---|---|---|
Entitlement |
|
Cash and in-kind entitlements |
Cycle |
|
Program cycle management |
Product |
|
Product catalog |
ServicePoint |
|
Service point registry |
ChangeRequest |
|
Change request workflow |
Simulation |
|
Program simulation and scenarios |
GIS |
|
Geospatial queries |
Data |
|
Variable value push/pull |
Install the corresponding module to enable each resource.
Quick Start#
1. Register Your Application#
Contact your OpenSPP administrator to register your application and receive:
Client ID
Client secret
Authorized scopes
2. Get an Access Token#
curl -X POST https://{your-domain}/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"
}'
Response:
{
"access_token": "eyJhbGciOiJIUzI1NiIs...",
"token_type": "Bearer",
"expires_in": 86400,
"scope": "individual:read individual:search"
}
3. Make Your First Request#
curl https://{your-domain}/api/v2/spp/Individual/urn:gov:ph:psa:national-id|PH-123456789 \
-H "Authorization: Bearer YOUR_TOKEN"
Response:
{
"type": "Individual",
"identifier": [
{
"system": "urn:gov:ph:psa:national-id",
"value": "PH-123456789"
}
],
"name": {
"given": "Maria",
"family": "Santos"
},
"birthDate": "1985-03-15",
"gender": {
"coding": [
{
"system": "urn:iso:std:iso:5218",
"code": "2",
"display": "Female"
}
]
}
}
Python Example#
import requests
BASE_URL = "https://{your-domain}/api/v2/spp" # Replace with your deployment URL
# Get token
token_response = requests.post(
f"{BASE_URL}/oauth/token",
json={
"grant_type": "client_credentials",
"client_id": "your-client-id",
"client_secret": "your-client-secret"
}
)
token = token_response.json()["access_token"]
# Fetch individual
headers = {"Authorization": f"Bearer {token}"}
individual = requests.get(
f"{BASE_URL}/Individual/urn:gov:ph:psa:national-id|PH-123456789",
headers=headers
)
print(individual.json())
Rate Limiting#
API requests are rate-limited per client:
Endpoint |
Default per minute |
Default per day |
|---|---|---|
General API |
30 |
5,000 |
OAuth token |
5 per IP |
50 per IP |
Rate limits are configurable per API client. When exceeded, the API returns 429 Too Many Requests with Retry-After and X-RateLimit-* headers.
API Versioning#
The API version is in the URL path: /api/v2/spp/...
Major version changes indicate breaking changes. Minor updates are backward-compatible.
Response headers indicate the exact API version:
X-API-Version: 2.0.0
Common mistakes#
Getting 401 Unauthorized?
Check that your access token hasn't expired (tokens last 24 hours by default). Request a new token.
Getting 403 Forbidden?
Your API client may not have the required scopes, or the registrant hasn't consented to data sharing. Check consent status in response headers:
X-Consent-Status: no_consent
Getting empty/minimal responses?
The API may be filtering fields due to consent restrictions. Use the X-Consent-Scope header to see what's allowed.
Rate limit errors?
Your client has exceeded rate limits. Check headers:
X-RateLimit-Limit: 30
X-RateLimit-Remaining: 0
X-RateLimit-Reset: 45
Retry-After: 45
What's next#
Authentication - OAuth 2.0 setup and token management
External Identifiers - Working with external IDs
API Resources - Complete resource documentation
Search and Filtering - Advanced search and filtering
Batch Operations - Batch and transaction operations
See also#
G2P Connect Protocol - Social protection interoperability
FHIR HTTP Interactions - HTTP patterns we adopt
OAuth 2.0 RFC 6749 - OAuth standard
openspp.org