Skip to main content

Vercel AI Gateway

Route your Vercel AI Gateway calls through AI SpendOps for automatic usage tracking and cost attribution.

The gateway is a single endpoint fronting hundreds of models across many providers, addressed as creator/model. AI SpendOps sits in front of it, so you change one base URL and add one header.

Configuration

SettingValue
Route/v1/vercel/*
Upstreamhttps://ai-gateway.vercel.sh
Auth headerAuthorization: Bearer vck_... (also accepts a Vercel OIDC token)
Streaming usageAlways included
CostReported in-band by the gateway

SDK base URL

The gateway supports two SDK families, and they need different base URLs.

ClientBase URL
OpenAI SDK, AI SDK createOpenAICompatiblehttps://proxy.aispendops.com/v1/vercel/v1
Anthropic SDK (Messages shape)https://proxy.aispendops.com/v1/vercel

The doubled /v1 in the OpenAI case is expected. The Anthropic SDK appends /v1/messages itself, so the shared part of the route stops before /v1.

Example

curl https://proxy.aispendops.com/v1/vercel/v1/chat/completions \
-H "Authorization: Bearer vck_your_gateway_key" \
-H "X-ASO-API-Key: aso_k_yourkey.secret" \
-H "Content-Type: application/json" \
-d '{"model":"anthropic/claude-sonnet-5","messages":[{"role":"user","content":"Hello"}]}'

Python SDK

from openai import OpenAI

client = OpenAI(
api_key="vck_your_gateway_key",
base_url="https://proxy.aispendops.com/v1/vercel/v1",
default_headers={"X-ASO-API-Key": "aso_k_yourkey.secret"},
)

response = client.chat.completions.create(
model="anthropic/claude-sonnet-5",
messages=[{"role": "user", "content": "Hello"}],
)
print(response.choices[0].message.content)

Anthropic SDK

from anthropic import Anthropic

client = Anthropic(
api_key="vck_your_gateway_key",
base_url="https://proxy.aispendops.com/v1/vercel",
default_headers={"X-ASO-API-Key": "aso_k_yourkey.secret"},
)

message = client.messages.create(
model="anthropic/claude-sonnet-5",
max_tokens=1024,
messages=[{"role": "user", "content": "Hello"}],
)
print(message.content[0].text)

Usage fields

FieldDescription
prompt_tokensInput tokens
completion_tokensOutput tokens
total_tokensSum of prompt + completion tokens
costAmount charged by the gateway (provider_cost)
market_costList-price value of the same consumption
is_byokWhether your own provider key served the request

Restricting models

Your API key policy is checked against the full slug, so you can restrict by creator without naming individual models:

allowed_models: ["anthropic/*", "openai/gpt-5*"]
allowed_models: ["vercel:anthropic/*", "vercel:openai/*"]

Because every gateway request arrives under the single vercel provider, provider-level policy cannot separate creators. Use allowed_models for that.

The gateway also accepts fallback models in models[] and in providerOptions.gateway.models[]. AI SpendOps validates every entry against your policy, not just the primary model, so a restricted key cannot reach a disallowed model through a fallback. If any entry fails, the request is denied with model_not_allowed.

Bring your own key (BYOK)

warning

Use gateway credits rather than BYOK if you want AI SpendOps to show what you spent.

Vercel lets you attach your own provider credentials. When a request is served that way, the provider bills you directly and the gateway reports cost: 0, because the gateway itself charged you nothing. That zero is accurate for what Vercel charged, but it is not what the request cost you.

AI SpendOps records these requests with a cost of zero and a source of byok-zero, so they are visibly distinct from a pricing failure. Tokens are still recorded in full, so usage reporting stays accurate. The market_cost field is also captured, so the list-price value of that consumption is retained even when the charged cost is zero.

Budgets and spend alerts are driven by charged cost, so BYOK traffic will not count toward them.

Notes

  • Model names use the format creator/model, for example anthropic/claude-sonnet-5 or openai/gpt-5.6-sol.
  • The gateway reports cost in-band on both streaming and non-streaming responses, so AI SpendOps uses the amount actually charged rather than calculating from token rates.
  • Streaming responses include a final usage chunk automatically. You do not need stream_options.include_usage.
  • Response ids are Vercel generation ids of the form gen_..., recorded as generation_id.
  • If a request falls back to a different model, the response reports the model that actually ran, and that is the model AI SpendOps records.
  • Requests are attributed to the vercel provider. To break spend down by creator, group on the leading segment of the model name.
  • Vercel may retry a failed request against another provider or model. One AI SpendOps request can therefore correspond to more than one billed generation on your Vercel invoice.
  • Latency measurements include Vercel's own routing and any internal retries, so first-token times are higher and noisier than calling a provider directly.