Credits
Stored-value balances, their append-only ledger and drawdown on issued invoices.
Stored value is a capability your deployment switches on. While it is off,
every endpoint below answers 501 with billing credits are not enabled —
and that is the honest answer, because with it off the billing engine does
not draw credit into invoices at all, so any balance shown would never be
consumed.
Credits are stored value held against a contract — customer prepayments,
promotional grants, goodwill. Balances are derived from an append-only
ledger; drawdown happens automatically when an invoice is issued against a
contract holding credit (visible on the invoice as creditAppliedMinor).
Wallet balance, credit balance and customer balance. A wallet balance
is money a seller owns and is paid out from (wallets). A credit balance
is stored value a buyer holds and spends instead of cash; it lives in the
credit ledger, anchored either on a billing contract (the merchant's
customer) or on a platform consumer (the coupon wallet). A customer balance
is that credit balance for one consumer. The two stored-value systems never
hold the same money: credit becomes wallet money only when an order it funded
settles to the seller.
Endpoints
GET /billing-api/v1/credits— your balances across all contracts, one row per currency and credit type:
{
"balances": [
{"currency": "EUR", "creditType": "purchased", "balanceMinor": 250000, "isLiability": true}
]
}
creditType is one of promotional, purchased, manual, gift,
enterprise, ai_token, marketplace or proration. isLiability marks
the paid-for types (purchased, enterprise, proration) — unearned revenue
you owe as service. Those never expire; granted credit may. proration is
minted by the engine rather than granted by you: when a mid-term subscription
amendment credits your customer more than the invoice it lands on can absorb,
the remainder becomes a proration lot — money the customer already paid for
service not rendered — and the next document draws it down.
GET /billing-api/v1/contracts/{contractId}/credits— one contract's balances (always complete) plus a page of its ledger history.limitsets the page size (1–100, default 20); whilehasMoreis true, pass the returnednextCursorback ascursorto walk older entries:
{
"balances": [ ... ],
"hasMore": true,
"nextCursor": 1180,
"nextBeforeId": 1180,
"entries": [
{
"id": 1201,
"kind": "topup",
"creditType": "purchased",
"signedDeltaMinor": 250000,
"currency": "EUR",
"invoiceId": null,
"reason": "annual prepayment",
"occurredAt": "2026-08-01T09:30:00Z"
}
]
}
Entries are newest-first. kind is topup, deduction, expiry or
reversal — the last one returns a deduction to the customer when the invoice
it funded is cancelled. signedDeltaMinor is positive for topup and
reversal, negative for deduction and expiry, and invoiceId links a
deduction (and the reversal that undoes it) to the document it funded.
POST /billing-api/v1/contracts/{contractId}/credits/top-up— grant a credit lot. This is the only way credit enters the ledger;deduction,expiryandreversalrows are the engine's and have no public route.
curl -s -X POST "$FYNEX_API_BASE/contracts/42/credits/top-up" \
-H "Authorization: Bearer $FYNEX_API_KEY" \
-H "Idempotency-Key: 3f0b6a1e-9c1d-4f10-9f2b-6f2a1c1e6a1e" \
-H "Content-Type: application/json" \
-d '{"creditType":"purchased","amountMinor":250000,"currency":"EUR","reason":"annual prepayment"}'
Idempotency-Key is required, and here the body is compared: the same key
with a different contract, amountMinor or currency answers 422 instead of
returning the first grant, because a top-up that never happened must not look
like one that did. A matching replay answers 200 with the original entry; the
first call answers 201.
currency must equal the contract's own — credit is never converted. An
expiresAt is allowed only on granted credit: purchased and enterprise
were paid for, and money someone paid must not evaporate on a calendar date.
sellerCustomerId is optional attribution and must name one of your customers
(POST /billing-api/v1/customers); the contract remains the balance anchor.
Correcting a grant is not an edit — the ledger is append-only. Contact support for a correcting entry.