> ## Documentation Index
> Fetch the complete documentation index at: https://docs.anchorage.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Paid inference

> OpenAI-compatible completions, the Anthropic Messages API, and image, video, and audio generation, billed through Anchorage's Agentic Banking Platform.

## Running inference through Anchorage's Agentic Banking Platform

`POST /v1/chat/completions` speaks the same request shape as OpenAI's own
chat completions API. Point any OpenAI-compatible SDK's `base_url` at it
and it works as a drop-in swap, including streaming with `"stream": true`
(see [Streaming](#streaming)).

`POST /v1/messages` speaks Anthropic's Messages API on the same host, so
Claude Code and an Anthropic SDK's message-creation calls work against it
(see [Anthropic Messages API](#anthropic-messages-api)).

## Why run inference here

* **Nothing to set up.** No account with the provider, no invoice, no
  separate billing relationship. Anchorage handles payment on the
  agent's behalf and sends the request straight to the provider —
  point `base_url` at the endpoint and go.
* **Settles instantly.** No waiting on an external biller; the call
  completes as soon as it's paid.
* **Anchorage carries the payment infrastructure.** Your organization
  never has to hold, manage, or expose any payment credentials of its
  own to use this.
* **The same budget.** The budget that pays for other purchases on this
  platform pays for inference too, drawn from the agent's identity here
  rather than a separate balance held with the provider.
* **The same governance controls.** The org's budget cap, the
  [per-agent daily cap](/agentic-banking/concepts/agents#stopping-a-runaway-agent), and
  instant revocation all apply to inference spend exactly as they do to
  any other agent payment, approved and reconciled the same way. A
  budget with the default allow-all merchant setting needs no extra
  configuration; one restricted to a specific allowlist needs the
  inference provider added to it (see
  [prerequisites](/agentic-banking/guides/call-a-model#prerequisites)).
* **Drop-in for existing code.** Point an existing OpenAI-compatible
  integration at this endpoint and swap the API key. The request and
  response shapes don't change.

## How a call is billed

The agent's API key authenticates the call (see
[Agents](/agentic-banking/concepts/agents#authorization-model); no OAuth session works
here). Anchorage bills the charge to the agent's primary budget, gated by
the same compliance and spending checks as any other agent payment.

A charge over the budget cap waits for an org admin to approve it instead
of completing; retry with the same request once it's approved (see
[Approvals](/agentic-banking/concepts/payments#approvals)). A non-streamed completion priced
by metered usage is declined instead when its per-request maximum exceeds the
remaining budget, so the budget must cover that maximum. Once payment is made, a
completion or an ordinary provider rejection (its own rate limit, for
example) passes through unchanged: status, `Content-Type`, body, and a
`Retry-After` header when the provider sent one. Either way the response
carries `X-Transaction-ID`. A response the provider can't relay this way
falls back to a specific error instead: one too large to record in full is
`response_truncated_after_payment`; anything else — no completion coming
back at all, or one in a shape this endpoint can't safely relay — is
`upstream_failed_after_payment` (see [Failure modes](#failure-modes)
below).

## Streaming

Set `"stream": true` to receive the completion as the provider produces
it. Each chunk is relayed as the provider sends it, so an
OpenAI-compatible SDK's streaming mode reads it unchanged. A streamed
completion always pays the merchant's fixed-price option, so a charge over
the budget cap waits for an org admin to approve it. A non-streamed
completion can pay a metered offer instead, which is declined when its
per-request maximum exceeds the remaining budget. The charge is submitted
before the first chunk arrives, and `X-Transaction-ID` is in the response
headers.

A streamed response can run for at most 120 seconds. A stream still
going at that point is cut off the same way as one that passes the size
limit below, and the charge stays as submitted, so cap the output length
of requests that could take longer.

The charge for the full completion is submitted when the stream starts,
and it stays pending until the payment settles on chain (see
[Settlement](/agentic-banking/concepts/payments#settlement)). A stream that ends early
doesn't reduce the charge. If the connection closes before the
provider's final event arrives, treat what you received as incomplete. If
the provider rejects the paid request, you get its status and body
unchanged, the same as for a non-streamed call.

A streamed completion can be at most 10 MiB. A stream that passes that
size is cut off: the connection closes without a normal end of stream,
the same as any other stream that ends early, and the charge stays as
submitted. A provider rejection whose body passes that size returns
`upstream_failed_after_payment` instead of the provider's own status and
body.

Sending the same streamed request again with the same idempotency key
doesn't charge you again, and it doesn't replay the earlier stream. The
retry reuses the first request's payment authorization, which has already
been used, so the provider is likely to reject it and the retry is likely
to fail. To get a new completion, send the request with a new
`Idempotency-Key`.

## Managing idempotency keys

To avoid multiple charges on retries, every request carries an
idempotency key.

If you don't send an `Idempotency-Key` header, we generate one from your
agent and the request body, so sending the exact same request twice only
charges you once.

Send `Idempotency-Key` yourself to control this directly. Reuse the same
key on a second request and you don't pay again, even if you changed the
body: the key guarantees you're not charged twice, not that you get the
exact same response back. Usually you get the first request's result
again; on rare occasions the original response wasn't retained, and the
provider is contacted again for a fresh one. Send a new key when you
actually want to send a new request with the same body.

The response normally tells you which one you got. A response that reused an
earlier payment says so, with the time the original request was first
submitted, and a response whose body is the first request's recorded result
is also marked as a replay. A chat completion that reused the payment without
the replay mark was normally fetched from the provider again for this
response; either way, you weren't charged again. A streamed response is
always relayed fresh, so it is never marked as a replay. The marks are a
hint, not proof; see [Idempotency](/agentic-banking/concepts/payments#idempotency).

Your idempotency key is scoped to your agent, so two agents on the same
account can each reuse the same key value without colliding. Use something
unique per request you actually want to send, like a UUID.

## Failure modes

| Status | `error.code` | What it means | What to do |
| - | - | - | - |
| 401 | `invalid_api_key` | No usable agent API key. | Mint or check the key on the agent's page. |
| 413 | `request_too_large` | Body over 1.5 MiB. Nothing charged. | Send a smaller request. |
| 400 | `invalid_idempotency_key` | `Idempotency-Key` over 255 characters. | Send a shorter key. |
| 403 | `budget_not_configured` | No spend limit configured. | Configure a budget, then retry. A retry with the `Idempotency-Key` of a request you already paid for goes through to that payment. |
| 402 | `budget_approval_required` | Over budget cap, waiting on an admin. | Get it approved, then retry with the same body (and key, if one was sent). |
| 403 | `payment_refused` | Compliance/spending check refused, or the provider was unreachable. Nothing charged. | See [Failure modes](/agentic-banking/concepts/payments#failure-modes). |
| 502 | `upstream_error` | Provider server error before payment. Nothing charged. | Retry. |
| 502 | `upstream_failed_after_payment` | Payment submitted, no completion came back. | Check that transaction before retrying. |
| 422 | `response_truncated_after_payment` | Completion too large to record; payment submitted. | Check that transaction, then ask for a shorter completion with a new key. |
| 403 | `origin_not_permitted` | Refused before this endpoint's own request handling ran (for example, a compliance check on the connection). Nothing charged. | See [Failure modes](/agentic-banking/concepts/payments#failure-modes). |

## Anthropic Messages API

`POST /v1/messages` takes the request body of Anthropic's Messages API and
passes it to the provider unchanged, including `cache_control` blocks and
any other field. The provider's status, `Content-Type`, and body come back
unchanged. The provider's `Retry-After` and `Retry-After-Ms` headers also
come back on a provider error and on any response that isn't streamed. Other
provider response headers aren't relayed. With `"stream": true`, the route
relays Anthropic's server-sent events as the provider sends them (see
[Streaming](#streaming)). Message creation is the one Messages API operation
served: an SDK's token-counting call isn't. Set `model` to a Claude model's
identifier from the model list.

The route authenticates with the agent's API key, sent either as the
`x-api-key` header, as Anthropic's API expects, or as a bearer token. If a
request sends both, they must carry the same key, and a request may carry
only one of each.

The `anthropic-version` and `anthropic-beta` headers are forwarded to the
provider; other request headers aren't. Every request sends exactly one
`anthropic-version` value, as Anthropic's API requires: a request that omits
it, repeats it, or lists more than one version is refused with a 400
`invalid_request_error`, and nothing is charged.

A message is billed and approved exactly like a chat completion: from the
agent's primary budget, with the same `X-Transaction-ID` header and the
same 1.5 MiB request limit (see [How a call is billed](#how-a-call-is-billed)).
Repeats follow the same idempotency-key rules (see
[Managing idempotency keys](#managing-idempotency-keys)), with one addition:
when you don't send an `Idempotency-Key`, the generated key covers the
forwarded `anthropic-version` and `anthropic-beta` headers as well as the
body, so changing a beta header makes a new request. When a message waits
for approval, retry it with the same body and the same forwarded headers.
A message and a chat completion never share a payment, even when their
bodies are identical.

Errors on this route use Anthropic's error shape, so an Anthropic SDK
raises its usual exception types:

```json theme={null}
{"type": "error", "error": {"type": "billing_error", "message": "..."}}
```

A failure listed under [Failure modes](#failure-modes) keeps its status on
this route, and `error.type` follows from that status the way Anthropic's API
assigns it: `invalid_request_error` (400), `authentication_error` (401),
`billing_error` (402), `permission_error` (403), `request_too_large`
(413), and `api_error` for a 5xx. A 422 is `invalid_request_error`. A request
that uses a method other than `POST` gets a 405 `invalid_request_error` with
an `Allow: POST` header.
This route carries no `error.code`, so errors that share a status share a
type; `error.message` says which failure it is and what to do. A 4xx the
provider returns passes through in its own Anthropic shape. A provider 5xx
before payment is a 502 `api_error`, and nothing is charged.

## Image and video generation

`POST /v1/images/generations` and `POST /v1/videos/generations` take a
generation request on the same host, with the same agent API key, and bill
it the same way as a chat completion: from the agent's primary budget,
behind the same compliance and spending checks, with an over-cap charge
waiting for an org admin's approval (see [How a call is billed](#how-a-call-is-billed)).

A model that finishes within the request answers `200` with the result,
the same way a chat completion does. A generation that takes longer answers
`202` with a job: its `id`, its `status`, and a `poll_url` on the inference
host. `poll_url` is a path, `/v1/images/generations/{id}` or
`/v1/videos/generations/{id}`, to request with `GET` on
`https://inference.agentic.anchorage.com`.
Only the agent that submitted a job can read it.

### Polling drives the job

The provider works on the generation on its own, and Anchorage learns its
progress only when you poll, so the job's status moves forward only while
you poll it. A job has about an hour from its submit to finish: a job still
unfinished after that ends as `timed_out`, however often it was polled. A
completed job answers every later poll from its record.

The poll answers with the job's `id`, `status`, and `price_atomic` (its
price in the payment's smallest unit: the submit-time quote until a poll
observes a price, then the most recent poll's price, and on a completed job
the price the provider reported for it). `status` is `queued`, `in_progress`, `completed`,
`failed`, or `timed_out`. `completed` means the provider reported the generation
finished and paid for; the job's transaction, described below, is the record
of the charge itself. A completed job carries `data`, the provider's own array
of generated output, such as image or video URLs, when there is output to
return. A completed job has no `data` when the provider sent none, or when the
output was larger than about 2.5 million characters and too large to record. A job that ended any other way carries `failure_reason`.

### What a generation costs

A generation is one payment, however many times you poll it. The submit
signs one payment authorization and reserves its price against the budget,
and no poll signs another. The provider can charge that authorization at any
point after the submit. The job's `id` is also its payment's transaction id,
and that transaction's status is the record of whether you were charged.
The payment's page at `https://agentic.anchorage.com/payments/{id}` shows it. If
the provider never charges it, the reserved amount is released back to the
budget once the authorization is confirmed unused, which can take until
shortly after the authorization expires.

### How a job ends without completing

| `failure_reason` | `status` | What it means |
| - | - | - |
| `provider_failed` | `failed` | The provider reported that the generation failed. |
| `payment_window_closed` | `failed` | Anchorage ended the job: the payment authorization signed at submit can no longer serve a poll, most often because the job outlived it. |
| `payment_not_repeatable` | `failed` | Anchorage ended the job: the payment rail can't present one authorization on more than one poll. Submitting the same request again won't change the rail. |
| `timed_out` | `timed_out` | Anchorage ended the job: it was still unfinished about an hour after its submit. |

A job's `failure_reason` says why the job ended, not whether the payment was
charged. Whatever the ending, check the job's transaction before you pay for
the generation again. A charged transaction means the generation was paid
for; a pending one can still be charged, or be released once its
authorization expires. For the
three endings Anchorage concludes, a poll within a day of the submit returns
the job as `completed` once the provider reports it finished, with its
output when one was recorded. Keep polling such a job during that day to
collect it.

### Repeating a submit

A submit carries an idempotency key the same way a chat completion does
(see [Managing idempotency keys](#managing-idempotency-keys)). Sending a
submit again under the same key, or the same body with no key, reuses the
first submit's payment instead of paying for a second generation. Usually it
attaches to the job the first submit started and answers with that job's
`id` and `poll_url`; on rare occasions the provider answers the repeated
submit differently, and you get its answer instead. When the repeat
answers with a job, the response reports the reused payment and isn't marked
as a replay, because it reports the job's current status. A submit
that sent no key and one that sent a key never share a payment, so a retry
keeps the first submit's choice. Use a new `Idempotency-Key` for a new
generation.

### Generation errors

A submit returns the same errors as a chat completion (see
[Failure modes](#failure-modes)), plus these:

| Status | `error.code` | What it means | What to do |
| - | - | - | - |
| 400 | `invalid_request` | A body that isn't a JSON object, a text field that's missing, blank, or not a string (`prompt`, or on the audio routes the route's own field), or a `model` name that's too long. Nothing charged. | Fix the request. |
| 502 | `generation_job_not_recorded` | Payment was submitted and the provider may have accepted a job, but no job could be recorded. | Retry with the same body, and with the same `Idempotency-Key` if the first submit sent one. A new key starts a second payment, and so does a changed body on a submit that sent no key. |

A generation submit can also return 403 `payment_refused` when the provider
offers its lowest price only on a rail that can't present one authorization
on every poll. Nothing is signed, the message names the rail, and the same
request gets the same answer until the provider's prices change.

A poll returns:

| Status | `error.code` | What it means | What to do |
| - | - | - | - |
| 404 | `generation_job_not_found` | No job of this kind with that id belongs to this agent. | Check the id and the route. |

## Audio generation

Three routes on the same host generate audio from text:
`POST /v1/audio/speech` reads `input` aloud, `POST /v1/audio/sound-effects`
makes the sound effect `text` describes, and `POST /v1/audio/generations`
makes the music track `prompt` describes. Each is billed, repeated, and
answered like an image or video generation, with the same errors (see
[Image and video generation](#image-and-video-generation)): one payment per
generation from the agent's primary budget, behind the same compliance and
spending checks.

A callable audio model is served by exactly one of the three routes, the one
matching the unit it's priced in: speech models per 1K characters, sound
effects per generation, and music per track. The model list's `endpoint`
names that route.

Each route answers either `200` with the audio, when the generation
finishes within the request, or `202` with a job. Speech and sound effects
usually finish within the request, and music usually answers with a job,
but any route can give either answer. A job's
`poll_url` is its submit path followed by its `id`, such as
`/v1/audio/generations/{id}`, and it's polled exactly like an image or video
job (see [Polling drives the job](#polling-drives-the-job)). A `200` is the
provider's answer passed through unchanged, and a completed job carries the
provider's `data` array when it returned one. The provider defines these
entries, and Anchorage doesn't reshape them. So far, speech answers and
`minimax/music-2.5+` jobs have carried a `url` in each entry, pointing at the
provider's storage, and a music entry has also carried the track's
`duration_seconds`. Those links expire, so download the audio when the
answer arrives.

## Typed judgments

`POST /v1/decide` answers questions about a piece of text your code can't
read reliably on its own: yes/no, pick one of several options, or a score.
It's free. It doesn't draw on a budget or create a payment, and the same
agent API key authenticates it.

A request carries a `state` (the text, or any JSON value, to judge) and
up to 20 named `questions`. Each question sets a `type`, its
`instructions`, and, for `choice` and `score`, its `criteria`. `model` is
optional and defaults to `openjev`.

| `type` | `criteria` | The answer carries |
| - | - | - |
| `noul` (yes/no) | None. | `noul`, the probability the answer is yes, from 0 to 1. |
| `choice` | An object that maps each option to a short description, such as `{"billing": "payments or charges", "shipping": "delivery"}`. | `choice` (the picked option), `probabilities` per option, and `confidence`. |
| `score` | An array of levels ordered lowest first, such as `["calm", "annoyed", "furious"]`. | `score` on a scale from 0 to the last level's index, a `legend` that maps each index to its level, `probabilities` per level, and `confidence`. |

The response carries one answer per question name, under `answers`.
Anchorage passes the provider's request and response shapes through
unchanged.

The provider may retain the text you send under its standard terms, so
don't send data you can't share with a third party.

| Status | `error.code` | What it means | What to do |
| - | - | - | - |
| 401 | `invalid_api_key` | No usable agent API key. | Mint or check the key on the agent's page. |
| 413 | `request_too_large` | Body over 64 KiB. | Send less `state`. |
| 400 | `invalid_request` | No `state`, no questions, more than 20 questions, or an unknown question `type`. | Fix the request. |
| 400 | `blockrun_bad_request` | The provider rejected the request's shape. The message names the field. | Fix the request. |
| 429 | `armada_rate_limited` | This agent, or all callers together, sent too many requests, or too many requests are already waiting on a slow provider. | Retry shortly. |
| 429 | `blockrun_rate_limited` | The provider's shared hourly limit is used up. | Retry later. |
| 502 | `blockrun_unavailable` | The provider didn't answer. | Retry. |


## Related topics

- [Changelog](/agentic-banking/changelog.md)
- [Connect your harness](/agentic-banking/guides/connect-your-harness.md)
- [Call a model](/agentic-banking/guides/call-a-model.md)
- [Crypto payments](/agentic-banking/concepts/payments.md)
- [Generate an image or video](/agentic-banking/guides/generate-an-image-or-video.md)
