API reference
Send calls, read spend and export the ledger over HTTPS. Bearer-key authentication, JSON in and out.
Base URL: https://veqen-app.com. Authenticate with Authorization: Bearer vq_live_.... The OpenAPI document is at /openapi.json.
Send calls
POST /v1/events (ingest key). Up to 1,000 events and 5 MB per request (a larger batch is refused whole); Content-Encoding: gzip is welcome.
curl https://veqen-app.com/v1/events \
-H "Authorization: Bearer $VEQEN_API_KEY" -H "Content-Type: application/json" \
-d '{"events": [{"id": "9f1c2e7a5b3d4c6e", "ts": "2026-10-22T14:03:11Z", "provider": "openai",
"model": "gpt-5-mini", "input_tokens": 1200, "output_tokens": 340, "cache_read_tokens": 0,
"customer": "acme", "feature": "support-bot"}]}'
| Field | Type | Notes |
|---|---|---|
id |
string, 8–64 characters | Unique per call. Retries with the same id and ts are stored once |
ts |
ISO 8601 | Within the last 35 days, and no more than 24 hours ahead |
provider, model |
string | As the provider names them; Veqen normalizes and prices them |
input_tokens |
integer | Uncached input |
output_tokens |
integer | Including reasoning |
cache_read_tokens, cache_write_tokens, cache_write_1h_tokens |
integer | Optional |
audio_input_tokens, audio_output_tokens |
integer | Optional, for realtime and audio models |
units |
number | Images, seconds, characters, queries or pages, for models billed per unit |
variant |
string | Image size and quality (hd/1024x1792) or video resolution (1080p) |
batch |
boolean | Batch API call |
service_tier, residency |
string | priority, flex; us |
cost_usd |
number | Kept when the model has no price, or when the call reports no usage |
customer, feature, user, project, environment |
string | See Tags |
tags |
object | Up to 32 free-form tags |
latency_ms, status |
integer, ok or error |
Optional |
Response:
{"accepted": 1, "duplicates": 0, "dropped": 0, "rejected": []}
dropped counts calls over your plan's cap or your own bill budget (not stored, not billed). rejected lists {"index", "error"} for invalid events; the rest of the batch is still stored.
POST /v1/otlp/v1/traces accepts OpenTelemetry instead: see OpenTelemetry.
Budget status
GET /v1/budgets/status (ingest key) → {"blocked": [{"scope": "customer", "value": "acme", "limit_usd": 5.0}]}. The SDKs poll this every 30 seconds.
Read spend
GET /v1/usage (full key)
| Parameter | |
|---|---|
start, end |
YYYY-MM-DD, inclusive; defaults to the last 30 days; up to two years |
group_by |
provider, model, customer, feature, user, project or environment |
provider, model, customer, feature, user, project, environment |
Filters (exact match; an empty value means untagged) |
daily |
true adds a per-day series |
limit |
Groups to return, up to 1,000 |
{"start": "2026-09-23", "end": "2026-10-22",
"totals": {"calls": 48211, "cost": 1284.37, "input_tokens": 51200443, "output_tokens": 9102114,
"cache_read_tokens": 30110022, "cache_write_tokens": 1022011, "units": 12400, "unpriced_calls": 0},
"groups": [{"key": "acme", "calls": 12001, "cost": 412.2, "share": 0.321, "...": "..."}]}
GET /v1/usage/models?days=30 (ingest key; Pro and Team) → calls and tokens per model, used by veqen diff.
GET /v1/export.csv?start=&end= (full key) → daily rollups as CSV, one row per day and tag combination.
GET /v1/account (ingest key) → organization, plan, this month's tracked calls and limits.
Prices
GET /v1/prices?model=gpt-5-mini (no key) → the model's kind, its unit if it's billed per unit, rates (per million tokens, or per unit), context window and retirement date. Add what one call uses (input_tokens, output_tokens, cached_tokens, audio_input_tokens, audio_output_tokens, units, variant, batch=true) to get cost_per_call: /v1/prices?model=sora-2&units=8 prices an 8-second clip. The whole price book is at /prices.json.
Simulate a workload
POST /v1/simulate (no key) prices a month of calls across any mix of models at list prices: the same engine as the simulator.
curl https://veqen-app.com/v1/simulate -H "Content-Type: application/json" -d '{"growth_pct": 5, "lines": [
{"label": "support", "model": "anthropic/claude-sonnet-4-5", "calls": 600000, "input_tokens": 2400, "cached_tokens": 12000, "output_tokens": 380},
{"label": "captions", "model": "deepgram/nova-3", "calls": 20000, "units": 1800}]}'
Each line takes the model, calls a month and what one call uses: the token fields, units (images, seconds, characters, queries or pages), variant and batch. Up to 25 lines. The response has each line's per_call, monthly and share; a ladder placing the call among every current model of its kind (cheaper_than is the share of those models that cost more); same_model, the same model on other hosts, cheapest first; and cheaper, cheaper models from the same provider. Totals: monthly, first_year, and a projection per month with growth_pct applied. Limited to a few requests a second per IP address.
Limits
Ingest: 200 requests a second per organization (batch calls instead of raising this). Read endpoints: 10 requests a second per key. Exceeding either returns 429 with Retry-After.
Request bodies: 5 MB, or 25 MB once gzip is inflated. /v1/events takes up to 1,000 events a request; an OTLP export can hold any number of spans within the size limit.