---
title: "Usage the ledger recorded and Stripe never heard about"
method: GET
path: "/v1/admin/billing/unsynced"
tags: ["billing"]
---

# Usage the ledger recorded and Stripe never heard about

`GET /v1/admin/billing/unsynced`

## Request

- Base URL: `https://api.hyperresearch.ai`
- URL: `https://api.hyperresearch.ai/v1/admin/billing/unsynced`
- Auth: API key in cookie `hr_session`

Every priced `usage_events` row with `stripe_synced_at IS NULL`, across the estate: how many, how much, how old, whose, and how much of it has stopped retrying. This is the read that did not exist on 2026-09-18, when twelve staging events ($181.70) were retried into a dead-letter queue with no consumer and nothing anywhere said so. One D1 read; no vendor is called and no query, report or customer name appears in it.

## Response `200`

What has not reached Stripe

- BillingUnsynced
  - `available` boolean, required: False when migration 0040 has not been applied to this deployment yet. Every figure below is then zero and means nothing — "we could not look", never "there is nothing".
  - `as_of` string, required
  - `events` integer, required
  - `amount_cents` integer, required
  - `oldest_ts` string, nullable, required
  - `exhausted` integer, required: Rows the re-drive sweep has given up on. Each has a `billing_failures` row with code `redrive_exhausted`; a re-drive resets them.
  - `accounts` BillingUnsyncedAccount[], required
    - `account_id` string, required
    - `events` integer, required
    - `amount_cents` integer, required
    - `oldest_ts` string, required
  - `alert_threshold_cents` integer, required
  - `alerting` boolean, required
  - `complimentary_events` integer, required: Comped rows (0041) still awaiting their local settlement, kept OUT of `events`/`amount_cents` and out of the alert: nobody is owed that money. Non-zero here for more than a minute means the settlement path is broken, which is worth looking at.
  - `complimentary_cents` integer, required
  - `needs_reconcile_events` integer, required: Rows whose money cannot be decided in code and are waiting on you (0042): either Stripe refused the reused Idempotency-Key, or the row was handed to Stripe longer ago than its identifier is de-duplicated for. Counted INSIDE `events`/`amount_cents` — "we do not know whether Stripe took this" is unsynced money — and split out here because it is the part that will not clear on its own. Resolve with `POST /v1/admin/billing/redrive` carrying a `reconcile` verdict.
  - `needs_reconcile_cents` integer, required
  - `needs_reconcile` object[], required: The waiting rows themselves, oldest first, capped at 50.
    - `usage_event_id` string, required
    - `account_id` string, required
    - `workspace_id` string, required
    - `amount_cents` integer, required
    - `ts` string, required
    - `reason` string, required
    - `last_sync_error` string, nullable, required

## Other responses

- `400`: Invalid request
- `401`: Authentication failed
- `403`: Insufficient scope or plan
- `404`: Not found
- `429`: Rate limited or over quota
- `500`: Internal error

---

[API](https://skmtc.dev/hyperresearch/apis/hyperresearch-cloud-api.md) · [All operations](https://skmtc.dev/hyperresearch/apis/hyperresearch-cloud-api/llms.txt) · [OpenAPI document](https://skmtc.dev/hyperresearch/apis/hyperresearch-cloud-api/revisions/726ef831ebf4?raw)
