API reference

API surface

Capability, authority, and protocol map for the complete generated endpoint reference.

The generated endpoint reference is the exhaustive inventory of the 370 operations registered by the engine. It is generated from the production Go route registrations; a route change makes the documentation check fail until the OpenAPI file is regenerated.

This page is the map: which family owns a capability, who may call it, and which guide explains the end-to-end task. It deliberately does not duplicate every method and path from the generated reference.

Authentication classes

ClassCredentialMain surfaces
Publicnone/, /healthz, /readyz, RFC 9728 metadata, personal-connection OAuth hops
Tenantmachine or end-user OAuth2 tokencompatibility APIs, datasets, projects, models, usage, readiness
User-ownedend-user OAuth2 tokenconversations, memories, personal connections, agent runs, skills
Organization administratorend-user token with engine-held org-adminlimits, guardrails, model grants, teams, integrations, webhooks, organization connectors
Applicationapplication credential with application-adminself-service signup, which models the application offers its tenants, the application's own model pricing, its own revenue report, the default spend caps of the organizations it owns, its guardrail policy, the chat model its memory infrastructure runs on, and the skill catalog it curates for its tenants
Platform administratoroperator OAuth2 token, admin session, or break-glass Basicapplications, organizations, identity, platform connectors, pricing, audit, setup backup
Billing serviceBILLING_TOKENPOST /v1/billing/topups only
Memory serviceMEMORY_TOKENinternal embeddings and reranking only

An application credential is neither a tenant nor a platform administrator: it reaches no organization's data, and platform-admin is stripped from every token a tenant authorization server mints. Its surfaces are therefore self-scoped — the credential names the application, and no path carries an application id.

All /v1/* routes require one of these credentials except /v1/connect/start and /v1/connect/callback. /.well-known/oauth-protected-resource is also public. The engine serves no sign-in route of its own: clients authenticate against the identity provider directly and present the token here.

Capability map

FamilySurface prefixesAuthorityTask documentation
System/, /healthz, /readyz, /v1/readiness, /v1/mepublic or tenantHealth and observability, Authentication
Compatibility/v1/models, /v1/chat/completions, /v1/messages, /v1/reranktenant; internal rerank uses memory serviceOpenAI SDK, Anthropic SDK, OpenAI parameter compatibility
Datasets/v1/datasets/*, /v1/me/storagetenant; mutations follow ownership and grants; /v1/me/storage requires an end user and no roleDatasets and RAG
Projects/v1/projects/*tenant; mutations follow ownership and grantsProjects
Widgets/v1/widgets/*, /v1/sources/{id}/widgetsend user; private to the creator in one organization, org-admin included — no sharingBuild a widget over a source, Widgets and sources
Sources/v1/sources/*end user; private to the creator in one organization, org-admin included — no sharingBuild a widget over a source, Widgets and sources
Conversations and memory/v1/conversations/*, /v1/memory/*, /v1/memories/*, /v1/instructions*end user; reading memory settings needs no role, writing them requires org-admin; /v1/instructions is each person's own response preferences, with a billable /v1/instructions/previewConversations and memory
Agents and runs/v1/agents/*, /v1/runs/*end user; management follows agent ownershipAgents and runs
Surfaces a run answered with/v1/surfaces/*, /v1/conversations/{id}/surfacesthe revision's owner only, for every role; a stranger's revision is 404 and a stranger's thread lists nothingAgents and runs
Skills/v1/skills/*end user; the application catalog plus the caller's own uploads and hash-bound enablementsConversations and memory
Knowledge-agent run budget/v1/agents/knowledge/policy, /v1/admin/agents/knowledge/policy, /v1/application/agents/knowledge/policyorg-admin, platform admin, or an application credentialDatasets and RAG
Teams/v1/teams/*members may read; org-admin mutatesTeams and sharing
Organizations/v1/onboarding/*, /v1/orgs, /v1/org/members*, /v1/org/directory/members, /v1/org/invitations, /v1/org/machine-credentials*end user creates; org-admin manages membership and machine credentials; /v1/org/directory/members needs only an enrolled member; /v1/onboarding/signups is application-credentialOrganizations
Automation/v1/schedules/*, /v1/schedule-events, /v1/webhook-*tenant; endpoint management requires org-adminSchedules and webhooks
Personal connections/v1/integrations/*, /v1/connections/*org-admin manages integrations; owners manage connectionsEmail connections
External MCP/v1/mcp-servers/*org-admin registers; users attach; /v1/mcp-servers/catalog is the member-safe readMCP integrations
Deeplinq MCP/mcptenantMCP integrations
Models and connectors/v1/connectors/*, /v1/org/connectors/*, /v1/model-grants/*platform or org-admin, by prefixConnectors
Billing and limits/v1/usage*, /v1/me/usage, /v1/me/usage/tokens, /v1/limits*, /v1/billing/*tenant, org-admin, or billing service; both /v1/me/usage* reads require an end user and no roleCredits and limits
Application models/v1/application/models*application credential; self-scoped, the credential names the applicationModels and pricing
Application pricing/v1/application/pricing*application credential; self-scoped, the credential names the applicationCredits and limits
Application usage/v1/application/usageapplication credential; self-scoped, the credential names the applicationCredits and limits
Application organizations/v1/application/orgsapplication credential; external applications only, for an organization that already exists at their own identity providerBring your own identity provider
Application spend limits/v1/application/orgs/{id}/limitsapplication credential; the credential names the application, and the organization must belong to itCredits and limits
Application memory model/v1/application/memory-modelapplication credential; self-scoped, the credential names the applicationConversations and memory
Application knowledge-agent policy/v1/application/agents/knowledge/policyapplication credential; self-scoped, the credential names the applicationDatasets and RAG
Application skills/v1/application/skills*application credential; self-scoped, the credential names the applicationConversations and memory
Application widget-data erasures/v1/application/widget-data-erasures*application credential; asks the engine to erase one of the application's own closed accounts' widgets and sourcesAccount-closure erasure
Guardrails/v1/guardrails/*, /v1/admin/guardrails/*, /v1/application/guardrailsorg-admin, platform admin, or an application credentialGuardrails
Protected resource metadata/.well-known/oauth-protected-resourcepublic; RFC 9728 pointer to the identity providerAuthentication
Platform administration/v1/admin/*platform adminApplications, Organizations, Members

The embedded console's browser-only /admin/api/* backend is intentionally not part of the public API contract. It is a same-origin BFF for the shipped console, not an integration surface.

Pagination

Inventory routes use opaque keyset cursors. Unless an endpoint says otherwise:

  • omitted limit uses that surface's default;
  • a value below 1, above 100, or non-integer is 400, naming the 1–100 bound;
  • pass next_cursor back unchanged and do not parse, compare, or synthesize it.

Out-of-range used to clamp silently (a value above 100 truncated to 100 with no signal it happened) rather than reject. Every list surface now answers the same way: a value outside 1–100 is a 400, not a silently-truncated 200.

Some provider-backed tools use their own opaque cursor field, such as page_token. Treat it with the same opacity rule.

Strict query parameters

Every list endpoint rejects a query key outside its own accepted set with 400 {"error":{"type":"invalid_request","field":"<key>","message":"…"}} naming it, rather than ignoring it. A misspelled or misremembered parameter name is a client bug, not a silent no-op — GET /v1/admin/orgs?external_org_ref=… (the wrong name; it's ref) used to fall through to the unfiltered listing and answer with the first organization in sort order. There is no alias for a wrong name: the 400 teaches the correct one instead of quietly accepting both. Each endpoint's accepted set is its own — see that endpoint's entry in the generated reference rather than assuming every list shares the same limit/cursor pair (/v1/conversations takes limit alone; /v1/admin/orgs also takes ref and status; /v1/models, /v1/model-grants, and /v1/mcp-servers take no query parameters at all).

Conditional updates and idempotency

  • Knowledge-agent policy updates return a strong ETag and require If-Match; missing is 428, stale or malformed is 412.
  • Dataset and project grant writes are upserts. A create returns 201; an update or no-op repeat returns 200 and remains audited.
  • Do not retry any other mutating request unless its endpoint or task guide explicitly states that replay is safe.

Idempotency-Key — supported routes

These routes read and honor Idempotency-Key; every one is also marked on its own entry in the generated reference with whether the header is required or optional there. Every other route answers 400 naming the header rather than silently accepting and ignoring it — see below.

RouteRequired?
POST /v1/billing/topupsRequired
POST /v1/admin/orgs/{id}/creditsOptional — omitted, every call credits
POST /v1/schedulesOptional — omitted, every call creates a schedule
POST /v1/schedules/{id}/runRequired
POST /v1/sourcesRequired
POST /v1/sources/{id}/versionsRequired
POST /v1/sources/{id}/versions/{version}/restoreRequired
POST /v1/sources/{id}/documentsRequired
PUT /v1/sources/{id}/documents/{document}Required
DELETE /v1/sources/{id}/documents/{document}Required
POST /v1/widgetsRequired
POST /v1/widgets/{id}/draftConditional — required only when the body sets from_revision_id; an ordinary resume needs no key
POST /v1/widgets/{id}/draft/publishRequired
POST /v1/widgets/{id}/draft/update-sourceRequired
POST /v1/widgets/{id}/draft/messagesRequired
POST /v1/widgets/{id}/refreshRequired
POST /v1/widgets/{id}/viewsRequired
POST /v1/application/widget-data-erasuresOptional — the body's operation_id is the real key; if sent, the header must equal it exactly

On every route above except the application widget-data-erasure route, the same shape holds — same key and the same input is a true replay that returns the original result unchanged; same key and different input is a 409 refusal that leaves whatever the first call did untouched — but the exact 409 body and what counts as "the same input" both differ by family. Branch on type (and code, where present), not on message text.

Credit-ledger routes (POST /v1/billing/topups, POST /v1/admin/orgs/{id}/credits) compare the raw request body bytes with SHA-256:

409 {"error":{"type":"idempotency_key_reuse","message":"Idempotency-Key was already used with a different request body"}}

A successful replay also sets an Idempotent-Replayed: true response header, following Stripe's convention for telling a deduped replay apart from a fresh write. Neither route enforces a length limit on the header — only "present" is checked (required on top-ups, optional on the credit grant). Retry with the identical bytes. The comparison is over the raw body, not a canonicalized or re-parsed form of it — a re-serialized but semantically equivalent payload (different key order, different whitespace, 25000000 vs 25000000.0) is a different body and hits the 409 above. (Stripe's own idempotency check compares request parameters, not raw bytes — this engine's raw-byte comparison on these two routes is a deliberate, stricter choice.)

Widget and source routes raise a conflict carrying the same code as a distinct field, not a type of its own:

409 {"error":{"type":"conflict","code":"idempotency_key_reuse","message":"…"}}

(the message is fixed prose per resource — "widget changed or preview is no longer current" for every widget route, "this key was used for different input" for sources — not a description of what changed). Each route compares only the specific fields that decide its outcome, at most 200 bytes on the key itself: a source creation compares name; a version upload compares the file's own content and filename (never literal request bytes — the multipart boundary differs on every request even for an identical file); a version restore compares which historical version id is being restored, independent of expected_source_revision; a widget creation compares source_id/name/model; publish compares expected_revision/preview_execution_id; update-source compares expected_revision/source_version_id (the DRAFT's revision, not the widget's — see Widgets and sources); a draft message compares expected_revision/text/decision; a view compares base_execution_id/parameters. POST /v1/widgets/{id}/refresh takes no body, so a replay with the same key always matches — but the key is not scoped to this route alone. Draft open/restore, update-source, a draft message, a view and refresh share ONE receipt table per widget, so reusing a key already used for a different one of those five is still the conflict above. POST /v1/widgets (create) and .../draft/publish each keep their own separate key column and are unaffected by a key already used on any of the other five, or on each other. Each route's own entry in the generated reference states its exact comparison.

Schedule routes raise the same conflict type with no code field at all:

409 {"error":{"type":"conflict","message":"Idempotency-Key reused with a different request"}}

POST /v1/schedules compares a hash of the request body after it is parsed and re-encoded — not the literal bytes sent — so an unrelated formatting difference collapses to the same hash while a changed field does not. POST /v1/schedules/{id}/run takes no body, so a replay with the same key always matches; a key already used for a different schedule's run is the conflict above.

Sending Idempotency-Key to any other native /v1 route answers 400 naming the header — {"error":{"type":"invalid_request","field":"Idempotency-Key","message":"…"}} — instead of silently ignoring it. A retried POST /v1/datasets with the same key, for example, is not deduplicated: each call creates a new dataset, and the engine now says so up front rather than leaving that gap to be discovered by trial and error. Support for further routes is tracked on the product roadmap, not shipped.

Exception: the OpenAI-compatible (POST /v1/chat/completions) and Anthropic-compatible (POST /v1/messages, POST /v1/messages/count_tokens) routes are exempt from that 400 — a drop-in SDK or proxy targeting either dialect may attach Idempotency-Key out of habit, and the engine tolerates it there rather than breaking compatibility. Neither route deduplicates on it: each call still processes independently.

Error and correlation contract

Native routes return a typed JSON error. OpenAI- and Anthropic-compatible routes use their protocol's envelope. Common statuses are:

StatusMeaning
400Invalid request or a user-owned route called without an end user
401Missing, expired, invalid, unbound, or wrongly scoped OAuth2 token
402Credit balance or hard spend limit exhausted
403Authenticated but not entitled; retired credential schemes also end here
404Missing resource, or a forbidden resource whose existence is concealed
409State, uniqueness, or identity-binding conflict
412Conditional update used a stale or invalid entity tag
413Request body exceeds the transport or feature limit
428Required conditional header is absent
429Authentication, capacity, rate, or concurrency limit reached
502Upstream provider or configured collaborator failed
503Required configured capability is unavailable

Every response carries an engine-generated X-Request-ID. Preserve it in support telemetry; it correlates the response with provider calls, billing, audit, conversation persistence, and structured logs.

Deliberate service boundaries

  • /v1/embeddings and /v1/rerank are internal memory-service surfaces, not general tenant embedding or reranking APIs.
  • /v1/billing/topups records settled payment outcomes; Deeplinq does not process the payment itself.
  • /mcp exposes a read-only Deeplinq server. Tenant-registered external MCP servers are managed separately under /v1/mcp-servers/*.
  • Hosted login and OAuth callback routes are browser hops. They return redirects and cookies, not API tokens in JSON bodies.

On this page