Replace
vb_live_... with a real project key from Dashboard → Keys, and use
your own stable user id wherever you see user_123.You are integrating Velobase into my app. Velobase is an OpenAI/Anthropic-compatible
AI gateway that bills every model call to one of MY end-customers' wallets, plus a
billing ledger for work I price myself. Use the reference below; wire up the parts I ask for.
# Setup
- Base URL: https://api.velobase.io/v1 (the OpenAI SDK base_url needs the /v1 suffix)
- Auth header: Authorization: Bearer <key>
- vb_live_... project key (server-side). Pick who to bill with header X-Velobase-Customer: <your-user-id>.
- vb_customer_... customer-scoped key (carries its own customer; no header needed).
- Units: every amount is a positive INTEGER number of credits. 1 credit = 1 micro-USD;
1 USD = 1,000,000 credits. Fields like amount_usd / amount_cents / amount_credits are REJECTED.
- Idempotency: deposits take body idempotency_key; billing primitives are idempotent on
transaction_id; gateway calls take an Idempotency-Key header (replay => 409, no double charge).
- Errors are JSON: { "error": { "message", "type", "code" } }.
# Gateway: model calls, billed to the customer's wallet
- POST /v1/chat/completions OpenAI-compatible chat completions (streaming supported). Send X-Velobase-Customer.
- POST /v1/messages Anthropic-compatible messages (streaming supported).
- GET /v1/models The models MY project configured (public id + price + my upstream key).
There is no platform model list; use ids from this response.
- GET /v1/usage Per-call usage rows. Filters: ?customer_id= &model= &transaction_id= &trace_id= &cursor= &limit=
- GET /v1/billing/receipts/{transaction_id} The billing receipt for one gateway call.
- Optional request headers: X-Velobase-Wallet (bill a named wallet; default "credits"),
X-Velobase-Trace-Id (correlation id, query it back via /v1/usage?trace_id=), Idempotency-Key.
- Per-call billing comes back on response headers:
X-Velobase-Cost-Credits, X-Velobase-Cost-Usd, X-Velobase-Balance-Credits,
X-Velobase-Balance-Usd, X-Velobase-Transaction-Id, X-Velobase-Trace-Id
- Streaming: cost/usage arrives in the FINAL standard frame of the stream
(OpenAI: last usage chunk; Anthropic: message_delta).
- 402 insufficient_balance = customer wallet cannot cover the call (body has required/available credits).
402 byok_key_required = the model has no upstream provider key attached (dashboard config, not balance).
- Example (Python, official OpenAI SDK):
from openai import OpenAI
client = OpenAI(api_key="vb_live_...", base_url="https://api.velobase.io/v1",
default_headers={"X-Velobase-Customer": "user_123"})
r = client.chat.completions.with_raw_response.create(
model="<id from GET /v1/models>",
messages=[{"role":"user","content":"Hello"}], max_tokens=256)
print(r.parse().choices[0].message.content, r.headers.get("x-velobase-cost-usd"))
# Customers and wallets (control-plane)
- POST /v1/customers/deposit body { customer_id, amount, idempotency_key?, wallet?, starts_at?, expires_at?, name?, email?, description? }
amount = integer credits (5000000 = $5.00). Customer is created on first deposit.
Default wallet is "credits".
- GET /v1/customers/{id} -> { id, name, email, metadata,
wallets: { "<wallet>": { total, used, frozen, available,
sources: [ { source, total, used, frozen, available, starts_at, expires_at } ] } },
created_at }
- GET /v1/customers/{id}/balance -> object-shaped balance summary.
- GET /v1/customers/{id}/ledger transaction history; cursor pagination; filters operation_type / transaction_id.
# Billing primitives: for work YOU price (model calls bill automatically, you do NOT call these for them)
- POST /v1/billing/deduct body { customer_id, transaction_id, amount, wallet?, business_type?, description? }
charge a known cost now (amount in integer credits).
- POST /v1/billing/freeze body { customer_id, transaction_id, amount, wallet?, business_type?,
unfreeze_after_seconds?, consume_after_seconds?, description? }
reserve a budget before a task. TTLs auto-release or auto-consume if never settled.
- POST /v1/billing/consume body { transaction_id, actual_amount? } settle the actual cost (credits);
the remainder is released. Omit actual_amount to consume the full frozen amount.
- POST /v1/billing/unfreeze body { transaction_id } cancel a freeze; release everything.
# SDK (control-plane only: deposits, balances, ledger, freeze/consume, usage, receipts).
# Model calls go through the OpenAI/Anthropic SDK above.
- JavaScript: npm i @velobaseai/billing@^1.2.0
import { Velobase } from "@velobaseai/billing";
const vb = new Velobase({ apiKey: "vb_live_..." });
await vb.customers.deposit({ customerId: "user_123", amount: 5_000_000 }); // $5.00
await vb.billing.freeze({ customerId: "user_123", transactionId: "job_1", amount: 1_000_000 });
await vb.billing.consume({ transactionId: "job_1", actualAmount: 730_000 });
// also: vb.customers.get / vb.customers.ledger / vb.billing.deduct / vb.billing.unfreeze /
// vb.usage.list / vb.receipts.get, plus GATEWAY_HEADERS and
// parseGatewayInsufficientBalance() for 402 paywalls.
- Python: no maintained SDK; call the REST endpoints above directly (requests/httpx).
Now build what I ask for next. Default to the OpenAI SDK + X-Velobase-Customer for model calls,
and POST /v1/customers/deposit (or the JS SDK) for funding customers.
What to do with it
Tell the assistant the specific task, for example:- “Route my existing OpenAI calls through Velobase and bill each one to the signed-in user.”
- “In my Stripe webhook, top up the paying customer’s Velobase wallet with the amount they paid.”
- “Show each user their remaining balance and a usage history in my dashboard.”