/api/v1/account/transactionsSigned-delta ledger of recent token transactions (debits, refunds, refills, grants, manual adjustments).
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).
Why use this
Common use case
Signed-delta audit trail for every token movement on the account — both debits (billed API calls) and credits (refills, grants, refunds, manual adjustments). The canonical 'where did my tokens go?' endpoint. EXEMPT (cost: 0) so support workflows can paginate freely. Each row carries request_id in metadata so a customer dispute can be correlated against server logs deterministically. Different from GET /api/v1/billing/history — that endpoint is the per-Stripe-charge wallet ledger, this is the per-API-call token ledger. For live balance use GET /api/v1/account/balance; for daily aggregation use GET /api/v1/account/usage; for self-serve billing use POST /api/v1/account/billing-portal.
Parameters
| Name | In | Required | Default | Allowed | Description | Example |
|---|---|---|---|---|---|---|
| limit | query | optional | 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. | 50 |
Response schema
| Field | Type | Nullable | Description |
|---|---|---|---|
| transactions | array | no | 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 | no | 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 | no | 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 | no | 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 | yes | 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 | yes | 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 | yes | 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 | no | 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 | no | ISO-8601 UTC timestamp the snapshot was generated server-side. NOT cached — always reflects live state. |
Sample response
- "transactions":
- "count": 3
- "as_of": "2026-05-02T15:51:00.000Z"
Errors
| Status | Label | Description |
|---|---|---|
| 200 | OK | Request succeeded. |
| 400 | Bad Request | Invalid query, body, or path parameter. |
| 401 | Unauthorized | Missing or invalid Authorization header / api_Token. |
| 402 | Payment Required | Insufficient token balance for this call. Top up |
| 429 | Too Many Requests | Rate limit exceeded for your tier (see /pricing for tier limits). Tier limits |
| 500 | Server Error | Unexpected server-side failure. Retry with backoff; report if persistent. |
Code samples
curl "https://api.finradar.ai/api/v1/account/transactions" \
-H "Authorization: Bearer YOUR_JWT_TOKEN"Generate an API key in /account/credentials to run live queries (literal YOUR_API_KEY placeholder shown until then).