# Token Pricing — Finradar API > Version: 3.61.0 | Generated: 2026-06-20 | Content Hash: 768c6ee3 > Fetch this file at: https://uat.finradarapi.com/llms/token-pricing.txt ## Authentication All endpoints require an API key. Pass it via query parameter `?apiKey=YOUR_KEY` or header `X-API-Key: YOUR_KEY`. WebSocket endpoints accept the key in the `token` auth payload or query parameter. --- ## Token Pricing Every billed endpoint costs 1, 5, 10, or 25 tokens per call. Free tier ships with 2,000 tokens/month. Paid tier ships with 200,000 tokens/month for $29/mo USD. Tokens refill on your subscription anniversary; balances do NOT roll over. Insufficient balance returns HTTP 402 with `current_balance`, `required_cost`, `next_refill_at`, `plan`, and `upgrade_url` so your client can prompt the user before the next call. Check your live balance at GET /api/v1/account/balance and manage your subscription via POST /api/v1/account/billing-portal (returns a Stripe Customer Portal redirect URL). WebSocket connections follow a flat connection-day model (100 tokens per UTC day connected, regardless of message volume). Exempt endpoints (auth, account self-serve, billing, payments, admin, sniper, user, webhooks, health) carry `cost: 0` and never debit the ledger. ### GET /api/v1/account/balance Live token balance, plan, and days until next refill. EXEMPT — does not consume tokens. Accepts session JWT (browser dashboard) OR `X-API-Key` (server-side automation pre-flighting bursty workloads). **Token cost:** 0 (EXEMPT — auth / billing / account / admin / health) **Response fields:** - `current_balance` (integer): Tokens left in the current billing cycle. Always non-negative — when a billed call would push this below zero, the call returns 402 instead of debiting and the balance stays at the pre-call value. Refilled to `monthly_quota` on `billing_cycle_end`; balances do NOT roll over. - `plan` (string): Plan tier — `free` (2,000 tokens/month, no credit card required) or `paid` ($29/mo, 200,000 tokens/month). Use to gate feature visibility client-side (e.g. show 'Upgrade for full Try-It' button on free plans only). - `plan_display_name` (string): Human-readable plan name for UI display (e.g. `Free`, `Paid`). Casing follows brand guidelines — use this verbatim in dashboards rather than capitalizing the `plan` field client-side. - `monthly_quota` (integer): Total tokens granted on each billing-cycle refill. `2000` for free; `200000` for paid. Display alongside `current_balance` for the customer-facing 'X / Y tokens used' progress bar. - `billing_cycle_end` (string): ISO-8601 UTC timestamp of the next refill (subscription anniversary). At this exact moment the account's `current_balance` is reset to `monthly_quota` regardless of prior balance — there is NO rollover of unused tokens. For paid customers, also coincides with Stripe billing event. - `days_until_refill` (integer): Whole days remaining until `billing_cycle_end` (rounded down). Useful for dashboard countdown chips ('29 days until refill'). When 0, the refill is happening within the next 24 hours. - `suspended` (boolean): True when `current_balance == 0` AND the account has consumed all monthly tokens — subsequent billed calls return HTTP 402 with `current_balance`, `required_cost`, `next_refill_at`, `plan`, and `upgrade_url`. False otherwise (still has balance OR has been topped up via admin grant). Use to render 'Account suspended — upgrade now' banners. - `as_of` (string): ISO-8601 UTC timestamp the balance snapshot was generated server-side. NOT cached — always reflects the live balance at request time, since stale balance display in the dashboard would be confusing during active token consumption. **Since:** v3.16.0 **Utility:** Live customer-facing balance probe — the canonical 'how many tokens do I have left?' call. EXEMPT (`cost: 0`) so balance polling never debits the ledger; safe to call as aggressively as 1 Hz. Returns the current balance, plan tier (free / paid), monthly quota, days until next refill, and a `suspended` boolean that flips to `true` when balance hits zero (subsequent billed calls then return HTTP 402). Customer dashboards typically poll every 30 seconds for near-real-time display; server-side automation scripts should poll before bursty workloads to pre-flight the budget and avoid mid-batch 402s. For per-endpoint spend breakdowns use `/api/v1/account/usage`; for the full debit/credit ledger use `/api/v1/account/transactions`. **Use case:** Customer dashboard polls this every 30 seconds for near-real-time balance display. Server-side scripts can also poll before bursty workloads to avoid 402s. **Sample response:** ```json { "current_balance": 198432, "plan": "paid", "plan_display_name": "Paid", "monthly_quota": 200000, "billing_cycle_end": "2026-05-26T08:39:00.000Z", "days_until_refill": 29, "suspended": false, "as_of": "2026-04-26T10:14:45.000Z" } ``` ### GET /api/v1/account/usage Last-N-days daily token consumption + top-10 endpoints by spend. EXEMPT. Same auth model as `/balance` — accepts session JWT or `X-API-Key`. **Token cost:** 0 (EXEMPT — auth / billing / account / admin / health) **Response fields:** - `window_days` (integer): Echo of the requested `days` query parameter, AFTER clamping to [1, 90]. Use to confirm the server applied the expected window (e.g. caller passed `days=180` but server clamped to 90 — `window_days=90` confirms the truncation). - `daily` (array): Per-day spend buckets, sorted by `day DESC` (most recent day first). Empty array on accounts with zero token activity in the window (free-tier accounts that signed up but never called a billed endpoint). Days with zero activity are ABSENT from the array — densify client-side if rendering a continuous bar chart. - `daily[].day` (string): ISO-8601 date (YYYY-MM-DD) at UTC day boundary. Bucketing uses `date_trunc('day', created_at)` — a debit at 23:59:00 UTC and a debit at 00:01:00 UTC the next morning land in DIFFERENT buckets. Display in user's local timezone if the dashboard expects local-day semantics. - `daily[].tokens_consumed` (integer): Total tokens debited on this day (positive integer; the underlying signed delta is negative on debits, but this field flips the sign for human-readable display). Always non-negative — refunds and grants do NOT subtract from this counter (they show up in `/api/v1/account/transactions` instead). For the live signed-delta ledger use `/api/v1/account/transactions`. - `daily[].calls` (integer): Number of debit transactions (= billable API calls) recorded on this day. Use to compute average cost-per-call (`tokens_consumed / calls`) for a 'most expensive day' diagnostic. Calls with `cost: 0` (auth, account, billing, etc.) are EXEMPT and never appear here. - `top_endpoints` (array): Top-10 endpoints by token spend over the window, sorted by `tokens DESC`. Empty array on accounts with zero billed activity. The leaderboard is computed live (no cache) so newly added endpoints surface within seconds of their first paid call. - `top_endpoints[].endpoint` (string): Endpoint identifier in `METHOD /path` format (e.g. `GET /api/v1/sec/filings`, `POST /api/v1/form-13f/holdings`). Path-parameter values are normalized to placeholders so all calls to `/transactions/by-ticker/AAPL` and `/transactions/by-ticker/NVDA` aggregate into a single `/transactions/by-ticker/{ticker}` row. - `top_endpoints[].tokens` (integer): Total tokens spent on this endpoint over the window (sign-flipped from the underlying signed delta — always non-negative). Use to drive the 'where did my tokens go?' donut chart on the dashboard. - `top_endpoints[].calls` (integer): Number of times this endpoint was called over the window. Combined with `tokens` reveals the cost tier (`tokens / calls` ∈ {1, 5, 10, 25} for the four canonical tiers; WS connection-day rows show `tokens / calls = 100`). - `as_of` (string): ISO-8601 UTC timestamp the usage snapshot was generated server-side. NOT cached — always reflects the live `token_transactions` state at request time. **Since:** v3.16.0 **Utility:** Per-day usage histogram + top-10 endpoints by spend — drives the customer dashboard usage chart and 'where my tokens went' breakdown. EXEMPT (`cost: 0`) so dashboards can poll without quota concerns. Direct query against `token_transactions` (no rollup table in v1) — ~50ms p99 at 10K txns/day per the locked-in CONTEXT.md performance budget. The `daily[]` array is sorted by `day DESC` (most recent day first) and back-fills with `tokens_consumed: 0` only for days that had at least one transaction; gap-days are absent from the array (frontend should densify if a continuous bar chart is desired). The `top_endpoints[]` array is sorted by `tokens DESC` (highest spender first) and is capped at 10 entries server-side. **Use case:** Customer dashboard renders a 30-day bar chart of daily spend + a top-10 leaderboard of which endpoints consumed the most tokens. Use to drive the 'usage trend' chip ('You burned 45,800 tokens this week, +12% vs last week'). **Parameters:** - `days` (query, optional, default: 30): Window size in days (1-90; clamped at the bounds; non-numeric falls back to 30). 30 is the canonical dashboard default; 7 for compact widgets; 90 for quarterly review. **Sample response:** ```json { "window_days": 30, "daily": [ { "day": "2026-05-02", "tokens_consumed": 1250, "calls": 248 }, { "day": "2026-05-01", "tokens_consumed": 980, "calls": 196 }, { "day": "2026-04-30", "tokens_consumed": 1420, "calls": 284 } ], "top_endpoints": [ { "endpoint": "GET /api/v1/sec/filings", "tokens": 8400, "calls": 1680 }, { "endpoint": "GET /api/insiders/transactions/latest", "tokens": 6200, "calls": 1240 }, { "endpoint": "POST /api/v1/form-13f/holdings", "tokens": 4500, "calls": 450 } ], "as_of": "2026-05-02T15:51:00.000Z" } ``` ### GET /api/v1/account/transactions Signed-delta ledger of recent token transactions (debits, refunds, refills, grants, manual adjustments). EXEMPT. Same auth model as `/balance` — accepts session JWT or `X-API-Key`. `delta < 0` is a debit, `delta > 0` is a credit. NOT to be confused with `/api/v1/billing/history` (Stripe charges + admin grants — different table, different sign convention). **Token cost:** 0 (EXEMPT — auth / billing / account / admin / health) **Response fields:** - `transactions` (array): Array of signed-delta transaction rows, sorted by `created_at DESC` (most recent first). Empty array on freshly-registered accounts that have neither been granted free-tier tokens (race window before `ensure_ledger_row` fires) nor called any billed endpoint. Cap of 200 rows enforced server-side. - `transactions[].created_at` (string): ISO-8601 UTC timestamp the transaction was recorded. For debits this is the API call's request-completion time (within milliseconds of the response being sent); for `subscription_refill` events this is the Stripe webhook arrival time. - `transactions[].delta` (integer): Signed token movement — NEGATIVE for debits (e.g. `-5` for a 5-token API call), POSITIVE for credits (`+200000` for a paid-plan refill, `+2000` for a free-tier signup grant, `+10` for an admin manual adjustment). Zero for status-only events (e.g. `subscription_cancelled`, `payment_failed`) where token balance does not move but the event must be recorded for audit. Sum across all rows in the current cycle = `current_balance - monthly_quota`. - `transactions[].reason` (string): Transaction kind — one of `debit` (billed API call), `refund` (per-call refund, e.g. handler error), `subscription_refill` (monthly Stripe charge → token grant), `signup_grant` (free-tier 2,000-token initial grant), `manual_adjustment` (admin-applied credit/debit), `subscription_cancelled` / `payment_failed` (status-only, `delta=0`). Use to dispatch UI badges and audit-trail filters. - `transactions[].endpoint` (string (nullable)): Endpoint identifier in `METHOD /path` format for `debit` and `refund` rows (e.g. `GET /api/v1/sec/filings`). Null for non-call events (`subscription_refill`, `signup_grant`, `manual_adjustment`, status-only events) — these are account-level movements unattached to a specific endpoint. - `transactions[].metadata` (object (nullable)): JSONB blob with event-specific context. For `debit`/`refund`: `{request_id, cost_tier}` (correlate with server logs via `request_id`). For `subscription_refill`: `{stripe_invoice_id, plan}`. For `manual_adjustment`: `{admin_user_id, reason}`. For status-only events: `{stripe_event_id, error_code}`. Null when the row was inserted by an early-Phase-56 path that did not yet write metadata. - `transactions[].response_status` (integer (nullable)): HTTP status code the handler returned for this request. Populated for `debit` rows from 2026-05-18 onward (issue #260). Null on `refund` / `subscription_refill` / `signup_grant` / `manual_adjustment` rows — those are bookkeeping movements, not responses to a specific API call. Null on `debit` rows that pre-date the migration (the column was just added; back-population was not attempted). After the 2026-05-18 batch-1 #254 change, any `debit` row with `response_status >= 400` is always paired with an immediate `refund` row (net-zero on the ledger), so this field is mainly an audit trail rather than a billing-correctness signal. - `count` (integer): Number of transaction rows in the response (matches `transactions.length`). Bounded by the `limit` query parameter; smaller when the account has fewer transactions than requested. - `as_of` (string): ISO-8601 UTC timestamp the snapshot was generated server-side. NOT cached — always reflects live state. **Since:** v3.16.0 **Utility:** Per-call signed-delta audit trail — every token movement on the account, ordered by `created_at DESC` (most recent first). EXEMPT (`cost: 0`) so support workflows can fetch full history without debiting. The canonical answer to 'where did my tokens go?' — each row carries the endpoint that consumed (or refunded) the tokens plus a JSONB `metadata` blob with `request_id` for cross-correlation against server logs. Different from `/api/v1/billing/history` in two ways: this endpoint is a per-call ledger (every API call shows up), the other is a per-billing-event ledger (only Stripe charges + admin grants); this endpoint uses signed deltas (negative for debits), the other uses unsigned amounts in cents with a separate `transaction_type` enum. **Use case:** Customer dashboard 'Recent transactions' card; support troubleshooting ('where did my tokens go on April 26?'); automated reconciliation scripts that need to verify a specific request_id was billed correctly. **Parameters:** - `limit` (query, optional, default: 50): Number of recent transactions to return (1-200; clamped at the bounds; non-numeric falls back to 50). 50 is the canonical dashboard default; 200 for export workflows; 20 for compact widgets. **Sample response:** ```json { "transactions": [ { "created_at": "2026-05-02T15:50:12.000Z", "delta": -5, "reason": "debit", "endpoint": "GET /api/v1/sec/filings", "metadata": { "request_id": "req_3OqK2jK9L8pQ4xZ1", "cost_tier": 5 }, "response_status": 200 }, { "created_at": "2026-05-02T15:48:01.000Z", "delta": -1, "reason": "debit", "endpoint": "GET /api/v1/stats", "metadata": { "request_id": "req_3OqK2jK9L8pQ4xZ0", "cost_tier": 1 }, "response_status": 200 }, { "created_at": "2026-04-26T08:39:00.000Z", "delta": 200000, "reason": "subscription_refill", "endpoint": null, "metadata": { "stripe_invoice_id": "in_1Pz...", "plan": "paid" }, "response_status": null } ], "count": 3, "as_of": "2026-05-02T15:51:00.000Z" } ``` ### POST /api/v1/account/billing-portal Returns a Stripe Customer Portal session URL. The frontend MUST redirect the user to this URL via `window.location.href = response.url` (Stripe disallows iframe embedding via X-Frame-Options: DENY). Free users without a Stripe customer get a 400 with `error: no_stripe_customer`. **Token cost:** 0 (EXEMPT — auth / billing / account / admin / health) **Response fields:** - `url` (string): Stripe Customer Portal session URL. Short-lived (~1 hour TTL). REDIRECT the browser to this URL via `window.location.href = response.url` — DO NOT iframe-embed (Stripe sets `X-Frame-Options: DENY` on the portal response). After the user finishes (or closes the portal), Stripe redirects back to `${FRONTEND_URL}/account` per the server-configured `return_url`. **Since:** v3.16.0 **Utility:** Single endpoint for self-serve subscription management — update card, view invoices, cancel subscription, change billing email. EXEMPT (`cost: 0`). Returns a short-lived Stripe-hosted Customer Portal session URL. The frontend MUST redirect (NOT iframe-embed) — Stripe disallows embedding via `X-Frame-Options: DENY` on the portal HTML response. Sessions expire ~1 hour after creation; if the user idle-bounces back, generate a new one. Customers without a Stripe customer record (free-tier users who never upgraded) get a 400 with `error: no_stripe_customer` — gate the 'Manage Billing' button by `plan === 'paid'` to avoid the dead-click. **Use case:** Customer clicks 'Manage Billing' on the dashboard → frontend POSTs here → redirects to Stripe-hosted portal → returns to the app on close (Stripe's `return_url` brings them back to `/account`). **Sample response:** ```json { "url": "https://billing.stripe.com/p/session/test_YWNjdF8xUXBlV0VLRzQzS3JCbnJ1eA0HDJI" } ```