Docs/Budget Ai/Api Reference

API Reference

Budget AI serves an OpenAI-compatible API at https://<your-gateway-host>/v1. Point any OpenAI SDK at that base URL and use a Budget AI key as the API key. The exact address for your deployment is shown in Project Settings → Budget AI → Budget AI address.

This page covers the gateway's own API and the key minting API for short-lived agent keys. Managing model groups and budgets, and issuing other keys, is done in the product; those operations are not part of the public REST API.

Authentication

Send the key in either header:

http
Authorization: Bearer sk-ants-...
http
api-key: sk-ants-...

Requests must use Content-Type: application/json. The default body limit is 4,718,592 bytes (4.5 MiB).

Routes

MethodPathPurpose
POST/v1/chat/completionsChat completions, streaming or not
POST/v1/embeddingsEmbeddings
GET/v1/modelsThe model groups this key may call

Any other path returns 404 with code unknown_route.

POST /v1/chat/completions

The body follows the OpenAI Chat Completions API.

FieldRequiredNotes
modelNoA model group name. May be omitted or empty when the key is granted exactly one model group.
messagesYesA non-empty array; each message needs a role
streamNotrue returns server-sent events
stream_optionsNoAs in the OpenAI API
tools, temperature, max_tokens, max_completion_tokens, response_format and other parametersNoSent on to the provider. For Anthropic, AWS Bedrock and Google Vertex AI the request is translated to the provider's API.
bash
curl https://<your-gateway-host>/v1/chat/completions \ -H "Authorization: Bearer $ANTS_GATEWAY_KEY" \ -H "Content-Type: application/json" \ -d '{ "model": "prod-chat", "messages": [{"role": "user", "content": "Summarise our refund policy in one line."}], "max_tokens": 200 }'

The response is an OpenAI chat completion object. For a non-OpenAI provider it is translated to the same shape, including usage.

Streaming

With "stream": true the response is text/event-stream in the OpenAI chunk format, ending with data: [DONE]. Headers are sent when the provider sends its first byte; until then Budget AI can still retry or fail over. If the provider stream breaks after that, the stream ends with an error event and [DONE]:

text
data: {"error":{"message":"stream interrupted: ...","type":"server_error","param":null,"code":"upstream_stream_error"}} data: [DONE]

For OpenAI-compatible and Azure OpenAI providers, Budget AI asks for a final usage chunk so streamed calls are costed from real usage.

max_tokens matters for streaming and non-streaming calls alike: it sets the output allowance used for rate limits and budget reservations. Without it, 4096 output tokens are assumed.

POST /v1/embeddings

The body follows the OpenAI Embeddings API.

FieldRequiredNotes
modelNoA model group name, with the same single-group rule as chat
inputYesText or an array, as in the OpenAI API

Embeddings are served only by deployments whose provider family has an embeddings API, which today is the OpenAI-compatible family. Streaming does not apply. The response cache does not apply. Usage is priced on input tokens.

bash
curl https://<your-gateway-host>/v1/embeddings \ -H "Authorization: Bearer $ANTS_GATEWAY_KEY" \ -H "Content-Type: application/json" \ -d '{"model": "embeddings", "input": "The quick brown fox"}'

GET /v1/models

Lists the model groups the key is granted, sorted by name:

json
{ "object": "list", "data": [ { "id": "prod-chat", "object": "model", "created": 1760000000, "owned_by": "ants-gateway" } ] }

id is the model group name to send as model. created is when the group was created.

Caller context headers

langfuse-user-id, langfuse-session-id, langfuse-tags, langfuse-metadata and traceparent are accepted on chat completions and embeddings to attribute the request in Tracing. See Caller context headers.

Response headers

HeaderWhenValue
x-ants-request-idEvery chat completions and embeddings response, including errorsThe request id, which is also the trace id in Tracing
x-ants-model-groupWhen the model group was foundThe group that served the request, which is the fallback group when one was used
x-ants-deploymentWhen a deployment was chosenThe deployment id
x-ants-costServed requestsCost in USD. For streams, the estimate made at admission.
x-ants-cost-estimatedServed requeststrue for streams, otherwise false
x-ants-attemptsWhen at least one provider attempt was madeJSON list of attempts: d deployment id, o outcome (ok, retryable, failed, timeout, benched), ms duration, and where available st provider status and why provider message
x-ants-cacheResponse cache hitshit
retry-afterRate limit refusalsSeconds until the current minute ends

Errors

Errors use the OpenAI error envelope, so OpenAI SDKs raise their usual exception types:

json
{ "error": { "message": "This gateway key has expired.", "type": "authentication_error", "param": null, "code": "key_expired" } }

type follows the status: authentication_error (401), permission_error (403), rate_limit_error (429), invalid_request_error (other 4xx) and server_error (5xx).

StatuscodeCauseTraced
400invalid_requestThe body fails validation, for example messages is missing or emptyNo
400invalid_jsonThe body is not valid JSONNo
400embeddings_not_supportedNo deployment in the model group offers an embeddings APIYes
401invalid_api_keyThe key is missing or unknown, or serving is off for its projectNo
400guardrail_blockedGuardrail checks found a violation in the prompt, or in a non-streamed response, and the policy blocks it. The message is the policy's Blocked Response Message.Yes
401key_blockedThe key is blocked, including when its agent is suspendedYes, sampled
401key_expiredThe key is past its expiry or its rotation grace windowYes, sampled
403ip_not_allowedThe request comes from outside the key's allowed source networksYes, sampled
403model_not_allowedThe key is not granted the model group, the group does not exist, or model was omitted on a key with zero or several groupsYes
404unknown_routeThe path is not servedNo
409budget_unpriced_modelA hard budget applies and the provider model has no priceYes
413request_too_largeThe body exceeds the size limitNo
415unsupported_media_typeThe body is not JSONNo
429rate_limit_exceededA key or project requests-per-minute limit is reachedYes
429tokens_limit_exceededA key or project tokens-per-minute limit is reachedYes
429budget_exceededA hard budget would be exceeded; the message names the budgetYes
502upstream_unreachableNo provider could be reachedYes
502upstream_invalid_responseA provider answered 2xx with a body that is not a JSON objectYes
503no_deployment_availableThe model group has no eligible deploymentYes
503budget_config_invalidThe key's org unit budget chain cannot be builtYes
503guardrail_unavailableGuardrail checks are on, the detection service cannot be reached, and the policy is set to fail closedYes
503gateway_config_staleThe gateway cannot confirm its configuration is current, or its Redis is unavailable. Retry shortly.No
504upstream_timeoutNo provider answered within the timeoutYes
Provider's statusProvider's code, or upstream_errorThe provider returned an error; its own error envelope is passed through when it has oneYes
200, then an error eventupstream_stream_errorThe provider stream broke after it startedYes
500noneUnexpected gateway errorNo

When every deployment and fallback fails, the caller receives the last provider error (or upstream_unreachable / upstream_timeout), and the trace records gateway.refusal = all_deployments_failed.

"Sampled" means the refusal is traced at most once per minute per key and reason. "Traced" refusals carry zero usage. See Observability & Cost.

ℹ

Retry 429 responses after the retry-after interval, and 503 gateway_config_stale after a short pause. Budget AI already retries provider failures inside the request according to the model group's routing policy, so aggressive client retries on 502 and 504 mostly add load.

Operational endpoints

These are for load balancers and monitoring, not for applications. They need no key.

EndpointPortMeaning
GET /healthAPI port and admin port200 when the process is up and Redis answers
GET /readyAPI port and admin portAs /health, and 503 while the gateway is draining for shutdown or its configuration is stale
GET /metricsAdmin port onlyJSON counters for requests, refusals and errors by code, latency percentiles, telemetry, configuration and process health

See Self-Hosting & Configuration for ports.

Key minting API

An authorised system can mint a short-lived Budget AI key for one agent. This endpoint is served by ANTS Platform, not by the gateway, and uses the same project API keys (HTTP Basic auth) as the other public APIs.

bash
curl -X POST "https://<your-ants-url>/api/public/v1/gateway/keys" -u "$ANTS_PLATFORM_PUBLIC_KEY:$ANTS_PLATFORM_SECRET_KEY" -H "Content-Type: application/json" -d '{ "agentId": "<agent-id>", "modelGroups": ["prod-chat"], "expiresInHours": 2, "budgetUsd": 5 }'
Request fieldRequiredDescription
agentIdYesThe agent the key is bound to
modelGroupsYesNames of the model groups the key may call, at least one
expiresInHoursYesLifetime in hours. It cannot exceed the project's maximum key expiry.
aliasNoA name for the key, unique in the project. A name is generated when omitted.
budgetUsdNoA key budget in USD that stops requests when reached
rpm, tpmNoRequests and tokens per minute limits for the key
allowedNetworksNoIPv4 or IPv6 addresses or CIDR ranges the key may be used from

A successful request returns 201 with the key:

json
{ "id": "<key-id>", "key": "sk-ants-...", "alias": "invoice-reader-task", "agentId": "<agent-id>", "modelGroups": ["prod-chat"], "expiresAt": "2026-10-18T14:00:00.000Z" }

The plaintext key appears only in this response. Store it where the agent can read it, and do not log it. A request with an unknown agent or model group, or a lifetime above the project maximum, is refused with 400 and a message naming the field. Every minted key is written to the audit log.

© 2026 ANTS Platform, Inc.Docs v1.0 · Last updated June 2026