Chapter 3
Well-designed APIs are the foundation of interoperable document systems, enabling secure, efficient, and developer-friendly access to document services across agencies, platforms, and applications.
The WIA-SOCIAL Public Document standard adopts RESTful (Representational State Transfer) architecture as the primary API paradigm. REST leverages standard HTTP methods and status codes, resulting in intuitive APIs that developers can understand without extensive documentation. Resources are identified by URLs, operations are specified by HTTP methods (GET, POST, PUT, DELETE), and representations can be negotiated based on client needs.
REST's stateless nature simplifies scaling—each request contains all information needed for processing, allowing requests to be served by any server in a cluster. Caching is built into HTTP semantics, enabling massive performance improvements through proxy caches and CDNs. The uniform interface constraint promotes simplicity and consistency across different document types and agencies.
Resources are identified by hierarchical URLs reflecting logical relationships. Collection resources represent groups of documents (/api/documents), while item resources represent specific documents (/api/documents/{id}). Sub-resources capture nested relationships (/api/documents/{id}/verification-history). Query parameters filter collections (/api/documents?type=passport&status=active).
GET /api/v2/documents
→ List all accessible documents (paginated)
GET /api/v2/documents/{documentId}
→ Retrieve specific document
GET /api/v2/documents/{documentId}/versions
→ List all versions of a document
GET /api/v2/documents/{documentId}/versions/{versionId}
→ Retrieve specific version
POST /api/v2/documents
→ Create new document
PUT /api/v2/documents/{documentId}
→ Update document (replace)
PATCH /api/v2/documents/{documentId}
→ Partially update document
DELETE /api/v2/documents/{documentId}
→ Revoke/cancel document
POST /api/v2/documents/{documentId}/verify
→ Verify document authenticity
GET /api/v2/documents?type=passport&status=active&issuedAfter=2024-01-01
→ Search with filters
HTTP methods have well-defined semantics that APIs should respect. GET retrieves resources without side effects and can be cached. POST creates new resources or performs operations that don't fit other methods. PUT replaces entire resources. PATCH updates specific fields. DELETE removes or revokes resources. HEAD and OPTIONS support discovery and CORS preflight. Proper method usage enables clients to make assumptions about behavior and allows infrastructure to apply appropriate policies.
| HTTP Method | Purpose | Idempotent | Safe |
|---|---|---|---|
| GET | Retrieve resource | Yes | Yes |
| POST | Create resource, execute operation | No | No |
| PUT | Replace entire resource | Yes | No |
| PATCH | Partial update | No* | No |
| DELETE | Remove/revoke resource | Yes | No |
| HEAD | Get metadata without body | Yes | Yes |
| OPTIONS | Discover supported methods | Yes | Yes |
Public documents contain sensitive personal data requiring robust access controls. The API implements a multi-layered security model combining authentication (proving identity), authorization (determining permissions), and audit logging (recording access).
OAuth 2.0 provides the authentication framework, supporting multiple flows for different client types. Authorization code flow suits web applications, offering secure token exchange through back-channel communication. Client credentials flow serves system-to-system integration. Device flow enables authentication on input-constrained devices. OpenID Connect extends OAuth 2.0 with standardized identity claims, providing user information alongside access tokens.
Tokens are issued with limited lifetime (typically 15-60 minutes for access tokens) and specific scopes defining allowed operations. Refresh tokens enable obtaining new access tokens without re-authentication. Token revocation allows immediate access removal when needed. The authorization server validates credentials and issues tokens; resource servers validate tokens and enforce scopes.
1. Client → Authorization Server: Authorization request
GET /oauth/authorize?
response_type=code&
client_id=gov-portal&
redirect_uri=https://portal.gov.ee/callback&
scope=read:documents write:documents&
state=xyz123
2. User authenticates and consents
3. Authorization Server → Client: Authorization code
302 https://portal.gov.ee/callback?code=AUTH_CODE&state=xyz123
4. Client → Authorization Server: Token request
POST /oauth/token
{
"grant_type": "authorization_code",
"code": "AUTH_CODE",
"redirect_uri": "https://portal.gov.ee/callback",
"client_id": "gov-portal",
"client_secret": "SECRET"
}
5. Authorization Server → Client: Access token
{
"access_token": "eyJhbGciOiJSUzI1NiIs...",
"token_type": "Bearer",
"expires_in": 3600,
"refresh_token": "refresh_token_here",
"scope": "read:documents write:documents"
}
6. Client → API: Authenticated request
GET /api/v2/documents/DOC-123
Authorization: Bearer eyJhbGciOiJSUzI1NiIs...
Authorization decisions are based on roles assigned to users and systems. Citizens can access their own documents. Issuing officials can create and sign documents. Verifiers can check document authenticity. Auditors can review access logs. System administrators manage users and configurations. Roles can be hierarchical (senior officials inherit junior permissions) and can be scoped to specific agencies or document types.
For fine-grained authorization, ABAC evaluates policies based on attributes of the user, resource, action, and environment. Policies might specify that "users can access documents where they are the subject" or "verification is allowed only from government IP addresses during business hours." ABAC enables expressing complex requirements that RBAC cannot capture, though at the cost of increased policy management complexity.
| Role | Permissions | Scope | Authentication |
|---|---|---|---|
| Citizen | Read own documents, request issuance | Self only | e-ID, username/password + MFA |
| Issuing Official | Create, sign, issue documents | Specific document types | Government PKI certificate |
| Verifier | Verify document authenticity | All document types | API key, OAuth client credentials |
| System Admin | User management, system configuration | System-wide | Admin certificate + MFA |
| Auditor | Read audit logs, generate reports | Agency or system-wide | Auditor certificate |
| Emergency Access | Override restrictions (break-glass) | Case-by-case approval | Multi-party authorization |
APIs evolve over time as requirements change and new capabilities are added. Versioning strategies manage this evolution while minimizing disruption to existing clients.
The WIA-SOCIAL standard recommends including the major version number in the URL path (/api/v1/, /api/v2/). This approach makes the version explicit and easily discoverable. Different versions can be deployed and scaled independently. Clients can upgrade to new versions at their own pace. Deprecated versions can be phased out with clear timelines.
Within a major version, changes should be backward compatible. Adding optional fields is safe. Adding new endpoints is safe. Loosening validation is safe. However, removing fields, tightening validation, changing response formats, or altering semantics breaks compatibility and requires a new major version. Careful API design minimizes breaking changes, reducing the frequency of major version increments.
When introducing breaking changes, the old version must remain available for a transition period (typically 12-24 months for government APIs). Deprecation warnings appear in response headers, documentation, and developer communications. During the deprecation period, both versions operate in parallel. After the deadline, the old version is shut down. Critical security fixes may be backported to deprecated versions during the transition period.
v1.0 Launch: 2023-01-01
- Initial release
v1.1 Launch: 2023-06-01
- Add vaccination certificate support (backward compatible)
- Add /api/v1/documents/{id}/qr-code endpoint
v2.0 Launch: 2024-01-01
- Change authentication to OAuth 2.0 (breaking change)
- Restructure error responses (breaking change)
- v1 enters deprecation (12-month transition period)
v2.1 Launch: 2024-06-01
- Add biometric data endpoints (backward compatible)
v1.0 Shutdown: 2025-01-01
- v1 APIs no longer available
- All clients must use v2+
Rate limiting protects API infrastructure from abuse and ensures fair resource allocation across clients. Limits are expressed as requests per time window (e.g., 100 requests per minute, 10,000 per day). Different tiers can apply to different client types—citizens might have lower limits than government agencies.
APIs communicate rate limit status through standard headers. X-RateLimit-Limit indicates the maximum requests allowed. X-RateLimit-Remaining shows how many requests remain in the current window. X-RateLimit-Reset specifies when the limit resets. Clients can use these headers to implement intelligent backoff, avoiding unnecessary retry attempts.
When limits are exceeded, systems can respond in several ways. Hard limiting returns HTTP 429 (Too Many Requests) and rejects the request. Soft limiting queues requests for delayed processing. Adaptive limiting adjusts thresholds based on system load. Cost-based limiting assigns different weights to different operations, charging more for expensive operations like document creation versus simple verification.
| Client Type | Per-Minute Limit | Daily Limit | Burst Allowance |
|---|---|---|---|
| Unauthenticated | 10 | 100 | No |
| Citizen (Authenticated) | 60 | 1,000 | 20 requests |
| Third-Party App | 120 | 10,000 | 40 requests |
| Government Agency | 600 | 100,000 | 200 requests |
| Internal Systems | 1,200 | Unlimited | 500 requests |
Comprehensive error handling helps developers diagnose issues quickly and build robust applications. The API uses standard HTTP status codes supplemented with structured error responses containing actionable details.
2xx codes indicate success (200 OK, 201 Created, 204 No Content). 4xx codes indicate client errors—400 Bad Request for invalid input, 401 Unauthorized for missing authentication, 403 Forbidden for insufficient permissions, 404 Not Found for nonexistent resources, 409 Conflict for conflicting operations, 429 Too Many Requests for rate limiting. 5xx codes indicate server errors—500 Internal Server Error for unexpected failures, 503 Service Unavailable during maintenance.
Error responses include machine-readable error codes, human-readable messages, and additional details to aid troubleshooting. Error codes are scoped to avoid conflicts (DOC_NOT_FOUND, DOC_INVALID_SIGNATURE, AUTH_EXPIRED_TOKEN). Messages provide context. Details might include field-level validation errors, suggested corrections, or links to documentation.
HTTP/1.1 400 Bad Request
Content-Type: application/json
{
"error": {
"code": "DOC_VALIDATION_FAILED",
"message": "Document validation failed",
"details": [
{
"field": "subject.dateOfBirth",
"error": "Date cannot be in the future",
"value": "2026-12-31",
"constraint": "must be <= current date"
},
{
"field": "issuer.signerId",
"error": "Signer not authorized for this document type",
"value": "12345",
"hint": "Only officials with role 'birth_registrar' can issue birth certificates"
}
],
"timestamp": "2025-01-15T10:30:45Z",
"traceId": "7d4e5f6g-1234-5678-90ab-cdef12345678",
"documentation": "https://docs.wia.social/errors/DOC_VALIDATION_FAILED"
}
}
Collections can contain thousands or millions of documents, requiring pagination to keep responses manageable. The API supports multiple pagination styles and comprehensive filtering to help clients find specific documents efficiently.
Cursor-based pagination provides stable iteration even when the underlying dataset changes. Each page response includes a cursor pointing to the next page. Clients use this cursor in subsequent requests. This approach works well for infinite scrolling and avoids the "skipped results" problem that affects offset-based pagination when items are inserted or deleted during iteration.
For cases requiring random page access (e.g., showing page numbers), offset and limit parameters provide traditional pagination. Offset specifies how many items to skip, limit specifies how many to return. This approach is simpler but less efficient for large offsets and can produce inconsistent results if data changes between requests.
Query parameters enable filtering collections by document type, status, date ranges, and other attributes. Field selection allows clients to request only needed fields, reducing bandwidth. Full-text search finds documents containing specific terms. Faceted search returns counts of matches per category, useful for building search UIs with refinement options.
Cursor-based pagination:
GET /api/v2/documents?limit=50
→ Returns first 50 documents + next cursor
GET /api/v2/documents?limit=50&cursor=eyJpZCI6MTIzNH0
→ Returns next 50 documents
Offset-based pagination:
GET /api/v2/documents?offset=0&limit=50
→ Returns documents 1-50
GET /api/v2/documents?offset=50&limit=50
→ Returns documents 51-100
Filtering:
GET /api/v2/documents?type=passport&status=active&issuedAfter=2024-01-01
Field selection:
GET /api/v2/documents?fields=id,type,issuedDate,status
Search:
GET /api/v2/documents?q=Smith&type=birth-certificate
Effective caching dramatically improves API performance and reduces server load. HTTP provides built-in caching mechanisms that APIs should leverage through appropriate headers and design patterns.
Cache-Control headers specify caching policies. Public content can be cached by any intermediate proxy. Private content should only be cached by the client browser. Max-age specifies how long content remains fresh. No-cache requires revalidation before using cached content. No-store prohibits caching entirely for sensitive data.
ETags (entity tags) enable conditional requests. The server includes an ETag header containing a hash or version identifier in responses. Clients include If-None-Match headers with ETags in subsequent requests. If the resource hasn't changed, the server returns 304 Not Modified without a body, saving bandwidth. Last-Modified and If-Modified-Since headers provide similar functionality using timestamps.
Different resources have different caching characteristics. Document content rarely changes after issuance, allowing aggressive caching (hours or days). Document status might change (revocation), requiring shorter cache times (minutes). Real-time verification must bypass caches entirely. APIs should set appropriate cache durations based on change frequency and consistency requirements.