Metering AI APIs
Chatbots, image and video generation, agents, wrapper APIs — every AI product needs per-customer keys, prepaid credits, and rate limits, because every call costs you real provider money. ReqKey meters all of it today, with the same endpoints you already use.
Why ReqKey fits AI APIs
ReqKey is not a gateway — it never sits between your customer and your model call. You verify the key before the stream starts and settle the cost when it ends, so a response that streams for 20 seconds adds exactly the same <5 ms of metering overhead as a request that returns in 40 ms. Your provider keys, prompts, and responses never pass through ReqKey.
One credit currency
Price every model behind your API in a single credit unit, so each consumer has one pool, one balance, and one number they understand. You choose the exchange rate per call type — a typical sheet looks like:
1 credit per message, or 1 credit per 100 tokens for token pricing.
40 credits per render — heavier calls simply cost more.
400 credits per clip.
2 credits per invocation.
Because /key/validate accepts any credits amount per call, no configuration is needed — your middleware passes the price of whatever the request is about to do.
Fixed-price calls
For calls with a known cost — an image render, a fixed-size completion — validation and metering stay a single request. Use resource to tell your endpoints apart in analytics:
curl -X POST "https://api.reqkey.com/key/validate" \
-H "Authorization: Bearer reqkey_xxx..." \
-H "Content-Type: application/json" \
-d '{
"key": "myai_A1B2C3D4...",
"credits": 40,
"resource": "/v1/images"
}'Token-priced streaming
When the cost depends on tokens you can only count after the stream ends, meter in two phases: a free check up front (credits: 0 deducts nothing), then a settling deduction with the exact amount once the provider reports usage in its final chunk:
// 1 · Free check before the stream starts — credits: 0 deducts nothing
const pre = await validate({ key, credits: 0 })
if (!pre.valid) return res.status(401).end()
// 2 · Run the model call as usual — ReqKey is not in the request path,
// so a 20-second stream adds zero latency
const stream = await openai.chat.completions.create({
...body,
stream: true,
stream_options: { include_usage: true },
})
let usage
for await (const chunk of stream) {
forward(chunk) // pipe to your customer
usage = chunk.usage ?? usage // the final chunk carries exact token counts
}
// 3 · Settle: convert tokens to credits at your own rate and deduct
const tokens = usage.prompt_tokens + usage.completion_tokens
await validate({
key,
credits: Math.ceil(tokens / 100), // e.g. 1 credit per 100 tokens
resource: '/v1/chat:settle',
})
// validate() is a plain POST to /key/validate with your root key —
// use the SDK client or fetch, whichever your stack prefers.resource (like /v1/chat:settle) so the pre-check and the settlement stay easy to tell apart in logs and breakdowns.overage enabled, the settle lands in the overage allowance instead of being rejected — you meter the full cost, your customer tops up, nobody gets cut off mid-answer.Rate limits & budgets
Everything else works unchanged: consumer rate limits cap how fast a customer can hit your model endpoints (one runaway agent can't drain your provider quota), shadowLimit fires low-credit warnings before anyone is cut off, and refill restores a plan's credits every hour, day, week, or month.
What's next
On the roadmap: token fields on /ingest (input tokens, output tokens, model) for per-model analytics, and SDK helpers that wrap the two-phase pattern for OpenAI- and Anthropic-style streams. The pattern on this page works today and won't change.