API reference/account

Read the credit ledger

GET/api/v1/account/ledger

authentication
Secret API key as a bearer token
billing
Free.

Every credit movement on the account, newest first: lookups debited, monthly grants, purchased packs and plan deposits. Each row carries the signed delta, the balance_after it left, the reason, an optional reference (a Stripe session or invoice id for purchases), and via, the label of the key, widget, bulk run or monitor that spent it. Filter with since and until (ISO 8601 dates), reason and via; page with page and per_page (up to 200). The dashboard's Usage page offers the same rows as a CSV download.

Parameters

name in type description
sincequerystringOnly rows on or after this date.
untilquerystringOnly rows on or before this date.
reasonquerystringOnly rows with this reason, e.g. email_lookup, ip_lookup, monthly_grant, purchase, subscription.
viaquerystringOnly rows spent through this label, e.g. "api · Production".
pagequeryinteger
per_pagequeryintegerDefault: 50.

Example request

curl https://spaw.co/api/v1/account/ledger \
  -H "Authorization: Bearer sk_live_…"
const response = await fetch('https://spaw.co/api/v1/account/ledger', {
  method: 'GET',
  headers: {
    'Authorization': 'Bearer sk_live_…',
  },
});
const result = await response.json();
import requests

response = requests.get(
    'https://spaw.co/api/v1/account/ledger',
    headers={'Authorization': 'Bearer sk_live_…'},
)
result = response.json()
$ch = curl_init('https://spaw.co/api/v1/account/ledger');
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_HTTPHEADER => ['Authorization: Bearer sk_live_…'],
]);
$result = json_decode(curl_exec($ch), true);

Responses

200One page of ledger rows.

{
    "success": true,
    "data": [
        {
            "id": 9812,
            "delta": -1,
            "balance_after": 8,
            "reason": "ip_lookup",
            "reference": null,
            "via": "api · Production",
            "created_at": "2026-09-04T10:12:44+00:00"
        },
        {
            "id": 9801,
            "delta": 10,
            "balance_after": 10,
            "reason": "monthly_grant",
            "reference": "2026-09",
            "via": null,
            "created_at": "2026-09-01T00:00:03+00:00"
        }
    ],
    "meta": {
        "page": 1,
        "per_page": 50,
        "total": 2,
        "request_id": "req_01m1kgdm4xngzmbmff68g94w0c"
    }
}

401The key is missing, malformed, or revoked.

{
    "success": false,
    "error": {
        "code": "UNAUTHENTICATED",
        "message": "Provide a valid API key as a bearer token.",
        "request_id": "req_01m1kgdm4xngzmbmff68g94w0c"
    }
}

422The request body could not be validated; `error.errors` lists the fields.

{
    "success": false,
    "error": {
        "code": "VALIDATION_FAILED",
        "message": "The email field is required.",
        "errors": {
            "email": [
                "The email field is required."
            ]
        },
        "request_id": "req_01m1kgdm4xngzmbmff68g94w0c"
    }
}

429Over 5 requests per second for the key. Retry after the limit resets.

{
    "success": false,
    "error": {
        "code": "RATE_LIMITED",
        "message": "Too many requests. Retry after the limit resets.",
        "request_id": "req_01m1kgdm4xngzmbmff68g94w0c"
    }
}

Error codes

Failures answer { success: false, error: { code, message, request_id } }. Each code has its own page.

markdown version·openapi.json