API Reference (OpenAPI and examples)
Version française : ../../fr/guides/api-reference.md
This page is the entry point of the API reference of the Navin Platform. It explains the two APIs, where their reference lives on the documentation site and in the repository, how to authenticate, and how errors, pages, retries and traces work. Who: developers and integrators.
The two APIs
| API | What it serves | Prefix | Credential | Reference on the documentation site | Source of the reference |
|---|---|---|---|---|---|
| Control Plane API | tenants and projects, identities and access, agents and runs, models and the LLM gateway, knowledge, tools and MCP, governance, security, FinOps; every portal screen, SDK and CLI command goes through it | /v1 | OIDC token, portal session or API key eai_... | /api/control-plane | docs/api/openapi-v1.json |
| Navin Manager API | the infrastructure of the platform: hosts, clusters, services, high availability, backups, restores and disaster recovery | /api/v1 of the Navin Manager | manager API token nmt_... | /api/manager | navin-manager/docs/api/manager-openapi.json |
On the documentation site, open /api/control-plane for the Control Plane API and /api/manager for the Navin
Manager API. In this repository, read the Control Plane API route by route and the
Navin Manager SDKs and CLI for the Navin Manager API. In the portal, Developer portal >
API reference links to the /docs, /redoc and /openapi.json of your Control Plane and shows its version.
When the documentation is enabled on a Control Plane server, the server itself serves the reference at /redoc,
the interactive console at /docs and the machine contract at /openapi.json.
Sources of truth
The published OpenAPI schema is docs/api/openapi-v1.json, generated from the FastAPI app by services/control-plane/src/eai/api_openapi.py (a breaking change is refused). The request surface is docs/api/control-plane-v1.requests.json and the route by route description docs/api/control-plane-v1.md. The JSON Schema contracts live in contracts/v1.
cd services/control-plane
.venv/bin/python -m eai.api_openapi --check
.venv/bin/python -m eai.api_surface --check
The Navin Manager schema navin-manager/docs/api/manager-openapi.json is written from the server by
tools/manager/openapi.py, and its Python, TypeScript and Go clients are generated from it by
tools/manager/gen_sdks.py.
Authentication
The tenant of a Control Plane call always comes from the credential, never from the request body.
| Credential | Header | Typical caller |
|---|---|---|
| OIDC access token issued by Keycloak | Authorization: Bearer <token> | users of the portal, SDKs and CLI after a sign in |
Portal session eais_... opened by POST /v1/auth/login | Authorization: Bearer eais_... | local accounts |
API key eai_... | X-API-Key: eai_... or Authorization: Bearer eai_... | scripts, CI pipelines, back end services |
Navin Manager API token nmt_... | Authorization: Bearer nmt_... on the Navin Manager API | automation of the infrastructure |
The Navin Manager also accepts X-NM-On-Behalf-Of: <user> from a token that holds auth:delegate; any other caller
gets 403 on_behalf_of_forbidden.
Examples
List the contracts (GET /v1/contracts), validate a manifest (POST /v1/contracts/{name}/validate), start a run (POST /v1/agents/{agent_id}/runs) and read its steps (GET /v1/runs/{run_id}/steps).
curl -H "X-API-Key: $EAI_API_KEY" https://ai.acme.example/v1/contracts
curl -X POST -H "X-API-Key: $EAI_API_KEY" -H 'Content-Type: application/json' \
-d @agent.json https://ai.acme.example/v1/contracts/agent-manifest/validate
First calls
-
Check who you are. The answer proves the credential works and shows the tenant, roles and scopes the server resolved from it.
curl -H "X-API-Key: $EAI_API_KEY" https://ai.acme.example/v1/meExpected result: 200 with your principal.
If it fails: 401
unauthenticated(no credential), 401invalid_api_keyor 401api_key_revoked. -
Check the API version. GET /v1/meta gives the server version and the API version; a client written for
/v1expectsv1.curl -H "X-API-Key: $EAI_API_KEY" https://ai.acme.example/v1/metaExpected result:
api_versionisv1.If it fails: another value means the server and your client do not speak the same major version.
-
Read a list page by page. List routes return
{"items": [...], "next_cursor": "..."}; sendlimit(default 50, maximum 500) andcursor=<next_cursor>for the next page, untilnext_cursorisnull.curl -H "X-API-Key: $EAI_API_KEY" "https://ai.acme.example/v1/runs?limit=50"Expected result: a page of runs and a
next_cursor.If it fails: 400
invalid_cursormeans a damaged cursor; never decode or build it. -
Retry a creation safely. Send an
Idempotency-Keyheader (1 to 200 characters): a retry with the same key and body returns the stored answer withIdempotency-Replayed: true. Long creations also returnOperation-IdandOperation-Location, followed with GET /v1/operations/{operation_id}.Expected result: one resource created, whatever the number of retries.
If it fails: 409
idempotency_conflict(same key, another body) or 409operation_in_progress(the first request still runs). -
Correlate a call. Send your own
X-Request-Idand a W3Ctraceparent; the response carriesX-Request-Id, the error envelope repeats it, and the audit events carry the same trace id.Expected result: GET /v1/audit/correlations finds every event of the call chain.
If it fails: an
X-Request-Idwith characters outside letters, digits and. _ : -is replaced by a generatedreq_<hex>id.
Errors
Every error follows the error envelope with code, message, message_i18n (en, fr), details and request_id; the SDKs turn it into typed errors (see the SDK guides Python, TypeScript, Go).
{"error": {"code": "forbidden", "message": "...", "message_i18n": {"en": "...", "fr": "..."},
"details": {"required_roles": ["tenant_admin"]}, "request_id": "req_..."}}
The language of message follows the Accept-Language header (en or fr, default en). The Navin Manager API
keeps the same envelope {error: {code, message, message_i18n, details}}.
Troubleshooting
| Status | Code | Cause | Fix |
|---|---|---|---|
| 400 | invalid_request | invalid value | read details, fix the value |
| 400 | invalid_cursor | damaged pagination cursor | restart from the first page |
| 401 | unauthenticated | no credential | send a token or an API key |
| 401 | invalid_api_key, api_key_revoked | wrong or revoked key | create or rotate the key (POST /v1/api-keys/{key_id}/rotate) |
| 403 | forbidden | role or scope missing | ask for the role in details.required_roles |
| 404 | not_found | resource absent or in another tenant | check the identifier and the credential |
| 409 | conflict, idempotency_conflict, operation_in_progress | duplicate, key reuse or state conflict | read details, retry with a new key or later |
| 413 | payload_too_large | body over the size limit | send at most details.max_bytes |
| 422 | validation_error | body or parameters do not match the schema | read details.errors (loc, msg, type) |
| 429 | rate_limited | rate limit reached | wait Retry-After seconds |
| 502 | authz_backend_error | the authorization backend could not answer (fail closed) | check OpenFGA and OPA |
| 503 | service_unavailable | a dependency is down | check the platform status |
Next steps
- Control Plane API: every route, with its request and its answer.
- Navin Manager SDKs and CLI: the Navin Manager API from Python, TypeScript, Go and the CLI.
- ExecutionContext Reference and ActionContext Reference.
- Developer portal: the living documentation in the portal.