Not Organic / Integration guides
API reference
A route and capability map for the gateway, with the implementation limits that matter to callers.
Account and access
| Endpoint | Required capability | Purpose |
|---|---|---|
GET /healthz | None | Store readiness; 200 or 503. |
POST /v1/auth/token/exchange | Product assertion | Exchange once for a 300-second token. |
POST /v1/public/token | Code + PKCE | Public-client token exchange. |
GET /v1/account | Authenticated | Account details for the token owner. |
GET /v1/models | Authenticated | Enabled aliases; not an upstream health check. |
GET /v1/wallet | wallet:read | Available credits and account balance. |
GET /v1/usage | usage:read | Usage records; optional limit. |
POST /v1/billing/checkout | billing:checkout | Hosted checkout URL. |
“Authenticated” means DPoP authorization is still required even when no additional capability is checked. Routes are account-scoped; a client cannot select another account by sending a DID in the body.
Organizations, seats and shared billing
All organization routes require DPoP-bound user tokens plus the listed capability and a live organization role. Administration uses personal control-plane tokens and needs no product seat. An organization token can administer only its own org. Organizational management capabilities are enabled explicitly for the first-party portal and trusted product assertions; they are not added to the public-client global allowlist.
| Endpoint | Capability | Behavior |
|---|---|---|
GET /v1/organizations | orgs:read | List active memberships, products and live seat counts. |
POST /v1/organizations | orgs:manage | Body {name}; atomically creates org, owner membership, billing account and wallet. |
GET /v1/organizations/:id | orgs:read | Active members can read their organization and products. |
GET /v1/organizations/:id/members | orgs:read | Owner/admin member list, including removed memberships. |
POST /v1/organizations/:id/invitations | members:manage | Owner/admin; {role, email?}. Returns a seven-day invitation token once; only hashes persist. Sends no email. |
POST /v1/org-invitations/accept | orgs:manage | {token}; accepts as authenticated DID. Email never authorizes or links identity. |
PUT /v1/organizations/:id/members/:membershipId | members:manage | Owner/admin; {role}. Last-owner protection applies. |
DELETE /v1/organizations/:id/members/:membershipId | members:manage | Owner/admin; removal revokes all assigned org seats. |
GET /v1/organizations/:id/products | orgs:read | List product entitlements and counts. |
PUT /v1/organizations/:id/products/:product | products:manage | Owner/billing; enable a product. |
DELETE /v1/organizations/:id/products/:product | products:manage | Owner/billing; disable and revoke its seats. |
PUT /v1/organizations/:id/products/:product/max-seats | products:manage | Owner/billing; {maxSeats: integer|null}; lowering a cap never evicts current seats. |
DELETE /v1/organizations/:id/products/:product/max-seats | products:manage | Owner/billing; clear the optional cap. |
GET /v1/organizations/:id/seats?product=… | orgs:read | Optional product filter. Members see their own seats; management roles see all. |
PUT /v1/organizations/:id/products/:product/seats/:membershipId | seats:manage | Owner/admin; idempotent assignment unless capped or billing is past due. |
DELETE /v1/organizations/:id/products/:product/seats/:membershipId | seats:manage | Owner/admin; idempotent revocation. |
GET /v1/organizations/:id/access?product=… | orgs:read | Live decision for current user: allowed, reason and versions. Denials are 200 decisions, not grants. |
POST /v1/auth/context | Authenticated user | {orgId, product?}; mint from live access; preserves product, scopes, DPoP binding and original expiry. |
GET /v1/organizations/:id/billing | wallet:read | Owner/billing; wallet, scoped credits, budgets, invoices, past-due flag, accrued and projected current-month seat estimates. |
GET /v1/organizations/:id/billing/members | wallet:read | Owner/billing; budget-subject membership metadata. |
PUT /v1/organizations/:id/budgets | budgets:manage | Owner/billing; {scope, limitMicrousd, product?, membershipId?}. Scope is org/product/member/member_product. |
DELETE /v1/organizations/:id/budgets/:budgetId | budgets:manage | Owner/billing; disable a budget while retaining outstanding holds. |
GET /v1/organizations/:id/usage?month=current|previous | usage:read | Owner/billing; UTC summary by product/member. Counts/tokens by creation month; charges by ledger settlement month; holds are current outstanding totals. |
POST /v1/organizations/:id/billing/checkout | billing:checkout | Owner/billing; {kind: top_up, amountMicros, product?, idempotencyKey} or {kind: payment_method, idempotencyKey}. Returns {provider, transactionId, url}. |
POST /v1/organizations/:id/billing/external-mapping | billing:checkout | Owner only; {product: frenzy, provider: stripe_connect, externalOrgId, mode: test|live}; verifies existing Frenzy ownership/billing. |
Roles (owner, admin, billing, member) never consume seats. Daily billable seats are max(1, assigned) while enabled, using UTC intervals and monthly catalog prices. Frenzy $20 and Voxq $15 are owner-review placeholder prices; collection remains disabled by default. Seat invoices are separate from metered-usage budgets. Estimates assume current assignments continue through month end and exclude verified external Stripe billing.
Stable errors include not_member, forbidden, last_owner, product_disabled, no_seat, seat_cap_reached, billing_past_due, budget_exceeded and invitation_unavailable. Unrecognized upstream errors are redacted. Reports fail closed with org_report_limit above their documented history limits instead of returning partial totals. Current/previous-month usage reads at most 10,000 inference records, 20,000 ledger projections, and 10,000 open reservations; billing reads at most 10,000 seat/entitlement intervals, 1,000 invoices and 1,000 credit lots.
The TypeScript client exposes client.organizations for these endpoints, including members, products, seats, billing, checkAccess, usage and checkout. client.switchOrganization(orgId, product) returns an isolated client with its own credential cache; the original client stays personal. The source token must be for that product; switching cannot expand scopes, change products or extend token expiry. createOrganizationSwitcher(personalClient) is usable from React or any other frontend framework.
Portal administration proxies through session/CSRF-protected /api/organizations/*; product tokens and DPoP keys stay server-side. Invitation links use /organizations/invitation#token=…, require explicit acceptance and survive sign-in in tab-local session storage. Python, Rust and Unison SDK organization namespaces are not included in this stage. SSO/SCIM, erasure and delegated-agent changes remain later stages.
Model requests
| Endpoint | Capability | Response |
|---|---|---|
POST /v1/responses | infer:<alias> | Responses-shaped JSON or SSE when supported. |
POST /v1/chat/completions | infer:<alias> | Chat JSON or SSE. |
POST /v1/embeddings | infer:<alias> | Embedding result. |
POST /v1/images/generations | infer:<alias> | Image result. |
POST /v1/audio/speech | infer:<alias> | Audio response. |
POST /v1/audio/transcriptions | infer:<alias> | Multipart transcription request. |
POST /v1/audio/translations | infer:<alias> | Multipart translation request. |
GET /v1/realtime | realtime:connect | WebSocket upgrade; consent and adapter required. |
The body’s model alias selects the inference scope: a request for balanced needs infer:balanced. Aliases include fast, balanced, reasoning, vision, embedding, image, audio, realtime, and persona. Enabled routes and provider capabilities determine which combinations work. persona is a user model for simulated respondents rather than an assistant tier; it is defined in the contract but served by no deployment yet, so requesting it returns model_unavailable. Raw models require explicit authorization and allowlisting.
Metered requests need Idempotency-Key and x-notorganic-max-cost-microusd. Use JSON for JSON endpoints and multipart form data where the audio route requires it. OpenAI-shaped requests do not imply complete parity with every OpenAI endpoint or SDK feature.
The SDK’s chat helper supports an async iterable for streaming. Its responses.create helper parses JSON; consume a streaming Responses request with a streaming-capable HTTP client instead of assuming that helper returns an iterable.
Stored responses
| Endpoint | Capability | Notes |
|---|---|---|
GET /v1/responses/:responseId | responses:read | Read an unexpired response owned by the account. |
DELETE /v1/responses/:responseId | responses:delete | Delete the gateway record. |
GET /v1/responses/:responseId/input_items | responses:read | Accepts after and limit. |
Missing or inaccessible response records are not returned across account boundaries. The response store defaults to a 30-day expiry. See storage semantics.
Optional execution and evolution
| Endpoint group | Capabilities | Configuration |
|---|---|---|
/v1/projects and /v1/projects/:projectId/execution-config | projects:read, projects:configure | List/get project configuration; PUT validates the account and product. |
/v1/sandbox/runs, /:runId, /:runId/cancel | sandbox:run, sandbox:read, sandbox:cancel | POST creates (202); GET reads; POST cancels. Requires execution registry and runner. |
/v1/ci/runs and /:runId | ci:read | GET durable run status; requires CI registry. |
/v1/evolution/artifacts, /evidence, /jobs, /active-revision | evolution:read, evolution:write, evolution:execute | Account-scoped artifacts, evidence, job scheduling, and revision activation. |
POST /v1/sync/account-key | sync:key:read | Wraps account key material for the requesting public key. |
These are optional first-party integrations, not a public grant of execution access. Their full request schemas live in packages/contracts/src/{sandbox,project-execution,account-evolution,account-sync}.ts. Use those schemas rather than guessing a body from this route index.
Pagination and compatibility
List routes validate limit in the range 1–100. Use each route’s actual response shape; not every list exposes a cursor. In particular, the current Convex-backed usage adapter returns a limited list and does not implement the SDK’s after cursor. Do not build an infinite history view assuming that cursor advances.
The API is implemented under /v1. Treat new or optional routes as integration-specific until deployed and tested. Keep response parsing tolerant of additional fields while validating the fields your application relies on.
Representations and reranking
Use POST /v1/embeddings with embedding or embedding-image, POST /v1/embeddings/contextual with embedding-contextual, POST /v1/late-interaction/score with late-interaction, and POST /v1/rerank with rerank or rerank-lite. Each requires DPoP, its infer:<alias> scope and an Idempotency-Key. Plain embedding requests retain the legacy Portkey response and metering when dense representation configuration is absent. Using input_type, manifest_id, truncation, image input items, or a configured dense upstream selects the representation path. Standard OpenAI fields alone do not opt in. Missing representation upstream or retail price returns 503 model_unavailable; representation-only aliases require configuration, while legacy embedding remains listed when enabled.
Representation embedding responses preserve OpenAI fields and add manifest and manifest_id: SHA-256 over compact JSON with sorted keys, excluding input_type. Keep this identity with every vector; compare only matching identities. A request may include manifest_id to reject incompatible revisions before spending. Text/image input accepts input_type: query | document. Images use HTTPS or base64 PNG/JPEG/WebP data URLs (5 MB each, 8 images, 10 MB combined); private-network URLs and redirects are rejected.
{ "model":"embedding-contextual", "input_type":"document", "documents":[["first chunk","second chunk"]], "dimensions":1024, "quantization":"int8" }
Contextual queries instead send input_type: query and queries: ["question"]. Dimensions are 1024 or 2048; quantization is int8 or float. The gateway preserves ordered document context and pins one upstream revision. Float vectors are L2 normalized.
{ "model":"late-interaction", "query":"agreement", "documents":[{"id":"d1","text":"We both agreed to pause."}], "top_spans":3 }
Late interaction returns server-computed MaxSim scores and best UTF-16 document character spans with weights and query token indices. Matrices stay server-side. Scores and span weights are relevance cues, not probabilities or claim-support verdicts.
{ "model":"rerank", "query":"agreement", "documents":["We agreed to pause."], "instruction":"Prefer explicit shared agreements", "top_n":1, "truncation":false }
Reranking rejects over-limit evidence with 413 input_too_large. Voyage allows explicit truncation: true for context limits. Preflight counts UTF-8 bytes conservatively against token limits, including repeated query/instruction bytes. Cohere has smaller conservative bounds and does not accept explicit truncation. Text prices are operator-set micro-USD per 1000 input bytes (rounded up); image embedding prices are per input item. Reported input tokens are nullable when unavailable. There are no default prices.
Decision judgements
POST /v1/judgement requires DPoP and judgement:evaluate. Send System One state (string or map of strings) and named questions with type: noul | choice | score, instructions, and criteria. Responses preserve typed answers and probabilities. An optional Idempotency-Key replays a settled result.
{ "model":"judgement-vision", "state":"Inspect the product", "images":["https://example.com/product.png"], "questions":{ "damage":{ "type":"noul", "instructions":"Is the product visibly damaged?", "criteria":{ "true":"Visible damage", "false":"No visible damage" } } } }
judgement selects the configured text backend (Jev by default). judgement-jev, judgement-luna, and judgement-pplx select explicit backends; judgement-vision selects a configured image backend. Jev retains its published 0.042 microUSD/input-token default, so a TypeSafe key alone enables judgement. Luna and pplx require explicit prices; missing credentials or required pricing returns 503 model_unavailable. Jev rejects images with 400 images_unsupported. Images are public HTTPS or base64 PNG/JPEG/WebP data URLs, at most four and 5 MB each; redirects and private addresses are rejected. pplx enforces an 8192-token branch limit without truncation.
The response model names the actual backend and version, for example judgement-luna/gpt-6-luna. Keep thresholds separate per identity. Fallback requires both allow_fallback: true and operator configuration, and only follows an explicit overload rejection. An executed fallback is reported as fallback: {from,to,reason}. Ambiguous delivery, malformed answers and missing required usage enter reconciliation. No silent backend switch occurs.