Running inference through Anchorage Agentic Banking
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).
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).
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_urlat 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, and instant revocation all apply to inference spend exactly as they do to any other agent payment, 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).
- 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 the Inference page shows prices
The Inference page lists the models the provider prices, grouped by what each produces into Text, Image, Video, Audio, and Other tabs. Text, image, video, and audio models are callable through the inference endpoint today; the other tab says its models are listed for pricing only. Each row shows the identifier to send asmodel, with a copy button, and the model’s display name when the provider publishes one that differs from the identifier, and its price in the unit the model is billed in: text models in USD per 1M tokens for input, output, cached input, and cache writes, with their context window and maximum output in tokens; image models per image; video models per second with any per-call surcharge and length limits; audio models per 1K characters, per track, or per generation, with their input and duration limits. A model priced by input length shows each tier’s price under the base price in each cell, with the input-token threshold it applies from, and a chip under its name naming the thresholds. A model with no charge is marked Free. Any other published price or limit shows as the provider published it. The page is public, and signed-in users reach it from the Inference entry in the sidebar.
Agents read the same list from GET https://inference.agentic.anchorage.com/v1/models, with no API key. Each entry carries the identifier, the model’s owner in owned_by (the maker’s name, or anchorage when no maker is listed or the listed owner is the provider itself), and, where the provider publishes them, a display name, the context window and maximum output in tokens, category tags, a billing mode, and whether the model is currently available. Each entry also states which kind of model it is (chat, image, video, audio, or other), whether it is callable through the endpoint and, when it is, the endpoint path to send it to (for example /v1/chat/completions), whether it is free, and which of its pricing keys are limits rather than prices, so a client can pick a model without knowing the provider’s pricing shapes. Prices are decimal strings in the same units the page shows.
How a call is billed
The agent’s API key authenticates the call (see Agents; 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 is declined withpayment_declined, and the
message says the payment would take the agent’s budget past its cap. Other
declines share the payment_declined code, so the message is what identifies
this one (see Over budget). An org admin raises the cap,
and you retry with a new Idempotency-Key: the identical request with its
original key returns the same decline. A non-streamed completion priced by
metered usage is also declined when its per-request maximum exceeds
the remaining budget, so the budget must cover that maximum.
Once payment is made, a
completion passes through unchanged: status, Content-Type, and body. When
the provider rejects the paid request instead, you get an error from the
Errors and retries table with a Retry-After header when
the provider sent one, such as rate_limit_exceeded for its rate limit.
Either way the response carries X-Transaction-ID, and an error’s message
names the same transaction. The exception is the rare 500 internal_error
for a payment whose own record fails an internal check, which
Errors and retries
describes and which carries neither. A payment the provider refused is
paid_no_response, or platform_unavailable when the cause is on
Anchorage’s side; a provider answer (a completion or an error) too large to
record in full, and no completion coming back at all, are each
paid_no_response.
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 is declined (see Over budget). 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 up to 30 minutes. The provider has 10
minutes to start its response, and then each chunk has its own 10 minutes
to arrive, the first chunk included. If the provider hasn’t started its
response within 10 minutes, you get a paid_no_response error with the
transaction ID. Once the stream has started, a stream that reaches
either limit is cut off the same way as one that passes the size limit
below. Either way, the charge stays as submitted. During an Anchorage
service update, the server handling a stream gives it up to about 5 minutes
to finish once that server starts shutting down, within the limits above,
then cuts it off with the same result. A non-streamed request stops if the
model hasn’t answered 2 minutes after the payment is sent, and a reasoning
model can think for longer than that before it sends anything, so send
"stream": true for reasoning models and other long calls.
The charge for the full completion is submitted when the stream starts,
and it stays pending until the payment settles on chain (see
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 before the first chunk, you get the
same error code and X-Transaction-ID a non-streamed call gets. If
Anchorage’s merchant directory is temporarily unavailable when a streamed
request starts, the request stops before it reaches the model provider
and you get a retryable platform_unavailable error. Its message says Anchorage
can’t confirm whether a payment was made, since an earlier attempt with
the same Idempotency-Key may already have paid. Send the
identical request again with the same Idempotency-Key if you sent one:
Anchorage reuses any payment already made for that key instead of charging
again. If that earlier attempt was paid, the resend may not return a
completion; the paragraph below on sending the same streamed request again
explains what it returns.
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
paid_no_response.
Anchorage sends a paid streamed request to the model provider at most once,
and the same goes for a request whose body is over 10 MiB. Sending the same request
again with the same idempotency key doesn’t charge you again, doesn’t replay
the earlier stream, and doesn’t send the payment again. While the first
request is still being answered, the retry returns payment_in_progress with
a Retry-After header. After that, the retry returns already_paid. 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 anIdempotency-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. If the provider asks to be
paid a different way on the repeat, the request returns a payment_declined
error naming the first payment’s transaction ID, and nothing is paid
again; check the first payment, and confirm with Anchorage support that it didn’t go through, before you send a new key (see Payment failures).
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.
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
See Errors and retries for each error code, what it means, and what to do.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. On a successful response, the provider’s status,
Content-Type, and body come back unchanged. An error renders as described
below, sometimes with a different status: for example, a provider 401 comes
back as a 502. 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). 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 exactly like a chat completion: from the
agent’s primary budget, with the same X-Transaction-ID header and the
same 32 MiB request limit (see How a call is billed).
Repeats follow the same idempotency-key rules (see
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 is declined for
being over the budget cap, an org admin raises the cap, and you then retry with a new Idempotency-Key.
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:
x-should-retry header on this route, and error.type follows
from that status the way Anthropic’s API assigns it: invalid_request_error
(400 and 409), authentication_error (401), billing_error (402),
permission_error (403), not_found_error (404), rate_limit_error (429),
and api_error for a 5xx. A request that uses a method other than POST
gets a 405 invalid_request_error with an Allow: POST header and no
x-should-retry header.
This route carries no error.code, so errors that share a status share a
type; error.message says which failure it is. An error the provider returns
renders the same way, without the provider’s own text: 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
declined (see 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 astimed_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, except for the case below that’s charged when it finishes. 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’sid 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.
Image, music, and video generation work like this:
- They pay on only one of the supported rails, so the agent needs a wallet on it; Crypto payments names it. Speech and sound-effects generation pay on any supported rail.
- A fixed-price image or music generation is charged when it finishes if the provider supports that, so a failed one usually costs nothing.
- If the provider confirms that for a generation that takes longer than the submit, the submit charges nothing, and one second payment is made when it finishes: never above the submit’s price, and never twice. It comes from the same wallet.
- Any other fixed-price image, music, speech, or sound-effects generation is charged at submit, and a failed one stays charged. Its transaction shows the charge. The provider reviews failed paid generations and may return the payment.
- A video, or an image paid with the metered option, is not charged at submit. When it finishes, the poll pays the provider once more, from the same wallet and under the same spending checks, and that second payment is the charge for the generation. The job’s own transaction charges nothing, and its reserved amount is released: right away for a metered submit, and for a fixed-price video once Anchorage confirms the submit payment can never be collected, which it does before the second payment, so the budget holds the price once.
How a job ends without completing
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
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. A generation charged when it finishes, on a rail whose polls
carry a signed proof, is the exception: once Anchorage has ended it, its
output can’t be collected, and nothing is charged for it.
Repeating a submit
A submit carries an idempotency key the same way a chat completion does (see 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’sid 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 Errors and retries), plus these:
A poll returns:
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): 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). 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.
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.