usage & billing LIVE
What counts as a billable read, what the free tier includes, and the exact shape of every quota, billing, and cost figure the api returns. Everything below describes code that is actually deployed — anything still planned is marked DRAFT.
"modeled": true: the $0.003/call price is the plan's pricing math, baked into the code comments as (M), not a price anyone has been charged. No real charges exist today. The free tier is hard-capped, so there is no mechanism that could charge you: when the cap is hit, calls stop, they do not bill. This page documents the metering the code actually performs, not a bill.the billable read
One billable read = one signal × one parcel (PRICE_PER_CALL_USD = 0.003, functions/lib/v1.js). A POST /v1/signals/{signal}/evaluate with N parcels requests N calls; with one parcel it requests one.
| surface | what consumes quota | quota pool |
|---|---|---|
POST /v1/signals/{signal}/evaluate | each parcel in the request (1 signal × 1 parcel = 1 call) | monthly v1 quota (1,000 calls/mo free) |
GET /api/intel | each request (not each parcel) | daily intel quota (25/day free, 5/day anonymous) |
POST /api/keys | each issuance | issuance throttle (3 per IP per hour), not quota |
mcp tools/call | same as the underlying v1 call | monthly v1 quota |
/api/intel calls are ledgered (usage ledger, below) but do not touch the monthly v1 quota — they run on their own daily quota seam. Quotas for v1 are D1-backed when the binding is present (KV monthly counters as fallback); with neither bound, quota is reported but not enforced (dev mode — the quota block carries quota_enforced: false).
the free tier, today
- 1,000 v1 calls/month, no card, hard cap (
FREE_TIER_MONTHLY_CALLS = 1000, functions/lib/api-keys.js). Every self-service key issues at this tier. - quota rows are month-keyed (
period = 'm:2026-09'): a new calendar month automatically starts a fresh row withused = 0— no reset job exists because none is needed. - the full N-call charge must fit: if your request would exceed the remaining cap, the call is refused with
402 quota_exhaustedand nothing is partially billed. - beyond the free tier, the modeled price is $0.003/call — but there is no issuance path that sells it yet.
pro(1000 intel/day, 60 req/min) exists in the tier config but is markedreserved: only the payments track can issue it, and that track has not shipped. See DRAFT sections below.
what gets billed $0
The evaluator bills only completed evaluations. These never consume quota or dollars:
- failed parcels — a parcel whose adapter threw is itemized in
resultswitherror/error_codeand bills $0. Onlycompletedevaluations are consumed. - unresolved parcels — a parcel the normalizer cannot resolve returns
422with"This evaluation was not billed."in the message. - idempotent replays — retries with the same
Idempotency-Keyheader and identical payload return the stored result with$0 additional(replays are free for 24h). A reused key with a different payload is rejected with409 idempotency_replay. The key header is required on the POST (400 idempotency_key_required).
reading your usage — GET /api/keys/usage
The response carries two metering blocks, exactly as the code builds them:
{
"ok": true,
"tier": "free",
...
"v1_monthly": {
"plan": "free",
"calls_used": 41,
"calls_included": 1000,
"resets_at": "2026-10-01T00:00:00.000Z",
"modeled": true, // (M) all cost figures are modeled, never observed
"price_per_call_usd": 0.003, // (M) modeled
"used_value_usd": 0.123, // (M) modeled value of calls consumed
"included_value_usd": 3, // (M) modeled value of the free tier
"upgrade_math": "41/1000 calls used. Free tier: 1000 calls/mo, no card, at $0.003/call (M) = $3/mo modeled included value. Hard stop at cap — no overage billing, no surprise charges. Quota resets 2026-10-01T00:00:00.000Z.",
"note": "v1 signal APIs: 1,000 calls/mo free (M), hard stop at cap — no surprise charges."
}
}
The evaluate response carries its own billing block: calls_consumed, calls_estimated, cost_consumed_usd (modeled), and modeled: true. The estimate binds the charge — the number of parcels you send is the number you pay for (or consume from quota).
the 402 — quota exhausted
Exact shape from functions/lib/v1.js (errQuotaExhausted). It is a 402, not a 429, because it is not a rate problem — it is a cap problem:
{
"ok": false,
"error": "quota_exhausted",
"message": "Monthly free-tier quota exhausted (1000/1000 calls). Hard stop at cap — no overage billing, no surprise charges. Quota resets 2026-10-01T00:00:00.000Z; upgrade raises the cap. No charge was made.",
"modeled": true,
"quota": { "calls_used": 1000, "calls_included": 1000, "resets_at": "2026-10-01T00:00:00.000Z", "price_per_call_usd": 0.003, "included_value_usd": 3 }
}
where metering lives
- D1
usage_ledger— one row per billed request:api_key_id,signal_id,endpoint,cost_cents,status. Today every row carriescost_cents = 0. - D1
quotas— counters:user_id,signal_id(or the'*'wildcard),period(month key),limit_per_period,used. Each billed call appends its ledger row and bumps the quota counter in a single batch, so the ledger and the counter move together. A fully-failed evaluation (calls = 0) writes nothing at all. - metering is best-effort — the ledger write on
/api/intelis wrapped in try/catch with a// metering must not break intelcomment: if metering fails, your request still succeeds.
planned: paid billing DRAFT
There is no checkout, no invoice, and no charge flow anywhere in the codebase today. The $0.003/call seam exists only inside free-tier math: cost_cents = 0 on every ledger row, modeled: true on every cost figure. When the payments track ships, paid issuance, overage, and real charging land on this page with their real endpoints — until then, any price in a response body is math, not money.
planned: pro tier issuance DRAFT
pro is reserved for the payments track: POST /api/keys never issues it and no other issuance path exists. The pricing page's "$0.003 per extra API call on pro" is the modeled price, consistent with the (M) seam — it describes a tier nobody can buy yet.
planned: usage dashboard DRAFT
Until a dashboard ships, GET /api/keys/usage is the usage interface: poll v1_monthly.used / v1_monthly.remaining. No dashboard page, no emailed quota alerts, and no usage history endpoint exist yet — all not final.
next: api keys · rate limits · api reference · docs hub