Deposit volume and transaction count by payment method, scraped hourly from the funkit Hex dashboard.
Every endpoint needs the same header. There is no second scheme and no unauthenticated data path.
Authorization: Bearer $API_TOKEN
No header, a wrong token, or a Basic header all return 401 with WWW-Authenticate: Bearer. Ask makushi for the token — it is not on this page.
/delta is for. Never read a /latest or /history row as a period total.
Refresh state, last error, cookie expiry. 200 healthy · 503 starting (no successful refresh yet) or degraded (last refresh failed, or the cookie is past expiry). Same body either way.
{
"status": "ok",
"lastSuccessAt": "2026-09-23T17:07:41.009Z",
"lastError": null,
"sessionCookieOk": true,
"cookieExpiresAt": "2026-10-07T17:07:12.274Z",
"daysUntilCookieExpiry": 14,
"cookieExpirySource": "rotated",
"snapshotCount": 6,
"scrapeInFlight": false,
"refreshCron": "0 * * * *",
"nextRefreshAt": "2026-09-23T18:00:00.000Z"
}
Most recent snapshot. 503 if no scrape has succeeded yet.
{
"basis": "cumulative-all-time",
"capturedAt": "2026-09-23T17:07:41.009Z",
"updatedDate": "2026-09-23T17:07:22.781Z",
"rows": [
{ "category": "Fiat", "txCount": 122, "volumeUsd": 6109 },
{ "category": "Other", "txCount": 1, "volumeUsd": 0 },
{ "category": "Transfer Crypto", "txCount": 318, "volumeUsd": 75033 },
{ "category": "Wallet", "txCount": 37, "volumeUsd": 2739 }
]
}
capturedAt is when this service stored the snapshot; updatedDate is when Hex executed the cell. Always within 30 minutes of each other, or the scrape is rejected as stale.
| Query | Required | Meaning |
|---|---|---|
from | no | ISO timestamp, inclusive. Defaults to the epoch |
to | no | ISO timestamp, inclusive. Defaults to now |
Snapshots whose capturedAt falls in the range, oldest first. Still cumulative totals — one row set per refresh.
GET /history?from=2026-09-01T00:00:00Z&to=2026-09-23T00:00:00Z
{
"basis": "cumulative-all-time",
"from": "2026-09-01T00:00:00.000Z",
"to": "2026-09-23T00:00:00.000Z",
"count": 6,
"snapshots": [ { "capturedAt": "…", "updatedDate": "…", "rows": [ … ] } ]
}
400 if a timestamp is unparseable or from is later than to.
| Query | Required | Meaning |
|---|---|---|
from | yes | ISO timestamp — start of the period |
to | yes | ISO timestamp — end of the period |
Per-category difference between the snapshots nearest each bound. This is the endpoint that answers "how much was deposited in crypto vs fiat this week".
GET /delta?from=2026-09-16T00:00:00Z&to=2026-09-23T00:00:00Z
{
"basis": "delta",
"requested": { "from": "2026-09-16T00:00:00.000Z", "to": "2026-09-23T00:00:00.000Z" },
"from": { "capturedAt": "2026-09-16T00:00:12.041Z", "updatedDate": "…" },
"to": { "capturedAt": "2026-09-23T00:00:09.882Z", "updatedDate": "…" },
"spanHours": 168,
"rows": [
{ "category": "Fiat", "txCount": 80, "volumeUsd": 1400.5 },
{ "category": "Transfer Crypto", "txCount": 405, "volumeUsd": 41250.75 }
],
"totals": { "txCount": 497, "volumeUsd": 42951.25 }
}
Check the returned from/to before quoting a number — "nearest" can be hours off what you asked for if a refresh failed. A category present in only one endpoint counts as 0 in the other.
400 a bound is missing or the range is reversed · 422 both bounds resolve to the same snapshot · 503 fewer than two snapshots exist.
Replace the Hex session cookie at runtime — no restart. The cookie has a fixed 14-day TTL that traffic does not extend, so this gets used roughly fortnightly.
| Field | Required | Meaning |
|---|---|---|
cookie | yes | The connect.sid value, exactly as DevTools shows it |
issuedAt | no | ISO timestamp of when it was issued. Defaults to now — correct if you just grabbed it |
refresh | no | Default true: scrape immediately to prove the new cookie works |
POST /cookie
Content-Type: application/json
{ "cookie": "s%3A…", "issuedAt": "2026-09-23T17:00:00Z", "refresh": true }
{
"cookie": {
"fingerprint": "8bcb330f0881",
"expiresAt": "2026-10-07T17:00:00.000Z",
"daysUntilExpiry": 14,
"source": "rotated-with-issued-at"
},
"refreshTriggered": true,
"refreshSkipped": null
}
The value is never logged and never returned — only a fingerprint. 400 if it is not a signed connect.sid value, the body is over 8 KB, or issuedAt is in the future.
| Refresh | Hourly. Each run drives a real headless Chrome session and takes 90–150 s. One at a time — a tick that fires during a run is skipped, not queued. |
| Failure | No retries: a failed scrape waits for the next tick. The last good snapshot keeps serving; only /health changes. |
| Staleness | Cell output older than 30 minutes is rejected rather than stored — Hex serving a cached run is a failure, not a result. |
| Errors | Always {"error": "…"} with a plain-language message. |