Build with the DFO / API
API conventions
These conventions apply to the Search, Datasets, and Graph APIs in this guide.
Base URL
The API is served from the DFO website's address, and every route sits under /api/v1.
https://developmentfinance.org
The same routes also answer at /api without the version. Links that the API returns in a response use that form.
Use JSON request bodies and send Content-Type: application/json for requests with a body.
Versioning
Datasets requests and responses use schema_version: 1. Search responses also carry schema_version: 1. The Graph API has its own response shapes, which GET /api/v1/graph/schema publishes.
GET /api/v1/datasets/capabilities reports live Datasets formats, input kinds, feature flags, limits, and a capability version. Treat capability values as deployment data.
When the graph does not declare a facet default, the Datasets API uses dfo/facet-policy/most-observations version 1 as its deployment fallback.
Discover routes and contracts
| Route | Use |
|---|---|
GET /api/{search,datasets,graph}/healthz | Check that an API is available and identify its build. |
GET /api/{search,datasets,graph}/capabilities | Read deployment capabilities and limits. |
GET /api/v1/search/schema | Read Search request and response schemas. |
GET /api/v1/search/catalogue | Read available data and example questions. |
GET /api/v1/datasets/schema | Read Datasets request and response schemas. |
GET /api/v1/graph/schema | Read Graph request and response schemas. |
POST /api/v1/graph/nodes | Read several graph nodes in one request. |
GET /codes/{code} | Read the registry entry for a problem code. |
GET /openapi.json | Read the OpenAPI document. |
GET /docs | Open the interactive API documentation. |
Trace headers
Application responses carry x-dfo-trace-id, except shared-cacheable responses. Include this identifier when reporting a problem. Search diagnostics and problem-details bodies carry the same trace identifier.
x-dfo-commit identifies the application build that answered the request. Server-Timing reports request timing where the response can carry it.
Problem details
Application-level non-2xx responses use application/problem+json with RFC 9457 fields and DFO extensions. A response has at least these fields:
{
"type": "/codes/request_invalid",
"title": "Bad Request",
"status": 400,
"detail": "Request body is invalid.",
"code": "request_invalid",
"trace_id": "...",
"capability_version": "...",
"retryable": false
}
pointer identifies the invalid location in a request body when available. alternatives, issues, cause, constraint_id, and ceiling details appear for the error types that define them. Branch on code and use retryable to decide whether to retry the same request.
Responses generated by infrastructure outside the application can use a different body.
Status codes
| Status | Meaning |
|---|---|
200 | Request completed. Search can still report candidates, no_data, or unsupported in a part. |
202 | A Datasets operation is running. Poll the URL in operation.poll. |
400 or 422 | Request validation or a request that cannot be satisfied. Read the problem code and pointer. |
404 | The requested graph node, spec, snapshot, or operation is unknown. |
410 | A snapshot is revoked or its artifacts are no longer servable. |
500, 502, 503, or 504 | The application could not complete the request. Check retryable. |
A Datasets 503 that reports a full instance carries Retry-After in seconds. Wait at least that long before you retry.
Graph limits
GET /api/v1/graph/capabilities reports the current Graph request and identifier limits. Read it before generating large resolver or node batches.
Next
How to resolve a question documents Search outcomes. How to get a dataset documents asynchronous operations and snapshot retention.