Why API standards matter more than frameworks
Teams can change UI weekly. APIs change slowly—because they’re contracts. Once partners, mobile apps, or external clients depend on your API, every inconsistency becomes a support ticket and every breaking change becomes an outage.
A strong API standard gives you:
faster frontend/mobile development
fewer “edge-case bugs”
safer retries (especially payments and disbursements)
easier observability and debugging
cleaner partner integrations
1) Resource naming and endpoint structure
Use nouns, not verbs
Good:
GET /v1/clientsGET /v1/loans/{loan_id}POST /v1/payments
Avoid:
GET /getClientsPOST /createLoan
Actions: use sub-resources or action endpoints
Some actions aren’t simple CRUD, especially in FinTech:
POST /v1/loans/{id}/approvePOST /v1/loans/{id}/rejectPOST /v1/disbursements
Keep actions consistent: approval-like actions always use POST, and always log who did it.
2) Response shapes: keep them consistent
A consistent response envelope makes clients simple.
Success example
{
"data": {
"id": "loan_123",
"status": "approved"
},
"meta": {
"request_id": "req_9c2f1"
}
}
List example
{
"data": [
{ "id": "loan_123" },
{ "id": "loan_124" }
],
"meta": {
"request_id": "req_9c2f1",
"pagination": {
"cursor": "eyJpZCI6IjEyNCJ9",
"has_more": true
}
}
}
Keep your meta.request_id everywhere—debugging becomes dramatically faster.
3) Versioning and breaking changes
Prefer explicit versioning for public APIs
For external consumers, URL versioning is simple:
/v1/.../v2/...
What counts as a breaking change?
Breaking:
renaming fields
changing field types
removing an endpoint/field
changing meaning of values (e.g., status enum)
Non-breaking:
adding new optional fields
adding new endpoints
expanding enum values (if clients are resilient)
Deprecation discipline
If you must change:
announce + give timeline (e.g., 60–90 days)
support both versions during transition
add response headers like
Deprecationor a custom warning header for clients
4) Idempotency: the FinTech “must-have”
In real networks, clients retry requests. If your API is not idempotent, retries can cause:
double payments
duplicate disbursements
duplicated records
inconsistent states
Where you need it most
payments
disbursements
refunds
any “create” endpoint that triggers money or irreversible actions
How idempotency works
Client sends:
Idempotency-Key: <unique-key>
Server:
stores the key + endpoint + tenant + request hash
stores the response for that key
returns the same response for the same key
Idempotency response behavior
first request creates and returns result
repeated requests with same key return exact same result
if payload differs with same key → return a clear error
5) Error format: one shape everywhere
Most “API pain” is error inconsistency. Fix it with one standard format.
Error response example
{
"error": {
"code": "VALIDATION_ERROR",
"message": "Please correct the highlighted fields.",
"fields": {
"nid": "NID must be 10–17 digits",
"dob": "Date of birth is required"
}
},
"meta": {
"request_id": "req_9c2f1"
}
}
Suggested error codes (simple)
VALIDATION_ERROR(400)UNAUTHORIZED(401)FORBIDDEN(403)NOT_FOUND(404)CONFLICT(409)RATE_LIMITED(429)SERVER_ERROR(500)
Keep them stable. Clients will build logic around them.
6) Pagination: offset vs cursor
Offset pagination (simple, small datasets)
easy to implement (
page=2&per_page=20)can be inconsistent if new rows are inserted
Cursor pagination (recommended for large lists)
stable and performant
requires stable sorting (e.g., by
created_at+id)good for timelines, transactions, audit logs
Rule of thumb: if the list can get big (transactions, logs), use cursor.
7) Observability: make API debugging easy
Always return request IDs
generate
request_idat gateway or app levelinclude it in every response
log it with errors and slow requests
Log the API contract events
For critical endpoints:
who called (user/service)
what tenant
result
duration
error codes
This enables fast incident response and supports compliance needs.
API “baseline standard” template (copy)
Base path: /v1
Naming:
- nouns for resources
- action endpoints for approvals
Responses:
- { data, meta: { request_id, pagination? } }
Errors:
- { error: { code, message, fields? }, meta: { request_id } }
Idempotency:
- required for money-impacting POSTs
- store key + request hash + response
- reject same key with different payload
Pagination:
- cursor for large lists
- offset for small lists
Common mistakes (and fixes)
Different error formats per endpoint → standardize one error shape
No idempotency on payments → add Idempotency-Key behavior
Silent breaking changes → version + deprecate properly
Offset pagination on huge lists → switch to cursor
No request_id → add it for support/debugging
Closing
APIs scale when they are predictable. If clients can rely on stable versions, safe retries, and consistent errors, integrations become easier, support load drops, and releases become less risky.
If you want, OSCORP can help you implement:
a consistent API contract
idempotency for critical endpoints
pagination and error standards
documentation + examples for frontend/partners