Account
Receipts
Every charge is listed with its order and whether the credit landed. A receipt document is not built yet, and this card says what is missing rather than promising it.
Planned Decided and written down. Not built, or built and not yet released. Do not integrate against it until the card says live.
What it does
The list of charges is GET /credits/history: every order newest first, with its amount, its status, the payment provider's transaction id, and whether the credit has reached the ledger.
The last of those is the one a customer chasing a missing balance needs. grant_status: pending means the money was captured and the credit has not landed yet. It is a different thing from a failed payment and is shown as one.
A refunded charge appears as the same order with a refunded status.
A charge does send a mail. An auto top-up charge sends a German receipt mail, written on the auto top-up branch and not deployed; a top-up bought on the hosted page sends the existing credits mail. What is decided and not built is the receipt document, the tax invoice, and it waits on the value-added tax decision.
The payment provider sends its own cardholder mail as well. That mail is not ours and is not a receipt from us.
Inputs and outputs
GET /credits/history?limit=&cursor= | {object, data, next_cursor}. limit 1 to 100, default 50, keyset-paginated on an opaque cursor. |
|---|---|
| Each entry | order_id, kind (topup or auto_topup), amount_cents, currency, status, grant_status, provider_event_id, created_at, paid_at. |
grant_status | pending money captured, credit not yet landed · granted · stuck · null. |
| Receipt email | German. send_auto_topup_receipt for an auto top-up charge, the existing credits mail for a hosted-page top-up. The first is written and not deployed. |
| Receipt document | |
| Name on the card statement |
Configuration
| Nothing to configure | The history is read-only and takes only a page size and a cursor. |
|---|
Limits
- Not enabled on this deployment yet. Until the ingress rules for
/credits*are applied, this path answers 404 in the gateway's own envelope. Read that as "billing is not enabled here". - Value-added tax handling and an invoice document are open questions and are not built. Nothing here should be treated as a tax invoice.
- The name that appears on a card statement has not been verified against a real charge.
- A refunded order used to appear twice in the list with contradicting credit status. The join is narrowed on the auto top-up branch, so one order is one row. De-duplicating on
order_idis still harmless.
Example
one entry
{"order_id": "…",
"kind": "auto_topup",
"amount_cents": 1000,
"currency": "CHF",
"status": "paid",
"grant_status": "granted",
"provider_event_id": "…",
"created_at": "2026-09-10T14:03:14+00:00",
"paid_at": "2026-09-10T14:03:14+00:00"} Source of truth
philosophers_stone/operations/decisions/0036-prepaid-credits-auto-topup-and-balance-events.md § 4 (the history shape and its fields; `charge_if_due` step 5 sends `send_auto_topup_receipt`, and every tenant mail is German)alchemy_labs/backend/services/email_service.py, branch `w1-auto-topup` (`send_auto_topup_receipt`, `send_auto_topup_declined`, `send_auto_topup_disabled`; written, not deployed)philosophers_stone/operations/prima-onboarding-phase1-report.md § 3.2 (the duplicate history row for a refunded order, and its fix)alchemy_labs/backend/api/routers/primaapi_router.py, branch `w1-auto-topup` (`/credits/history`: the join filtered to `kind == "topup"`, so a refunded order is one row)philosophers_stone/operations/prima-onboarding-implementation-plan.md § W11 (receipt email per charge, and a receipt document once the tax decision lands, both not built)philosophers_stone/operations/prima-onboarding-implementation-plan.md § 1 (tax and invoice document still open)