Layers
Partner APIConcepts

Credits

How the credit wallet works — balance vs available, and how a parent funds, caps, and auto-refills its child organizations.

View as Markdown

Credits are the unit you spend on generation. Every organization has one wallet; content generation reserves credits when a workflow starts and settles them when it finishes. This page covers how to read a wallet, and — if you run customers as sub-organizations — how a parent funds and governs its children's wallets.

Reading a wallet

GET /v1/credits returns your own wallet; GET /v1/organizations/:orgId/credits returns a child's. Both report the same two top-line numbers, and the difference between them is the one thing to get right:

  • balance — the gross wallet: included credits remaining this period plus the prepaid balance.
  • available — what you can actually spend on new work right now: balance minus credits already reserved for in-flight generations (reservedCredits). A generation reserves credits the moment its workflow starts and releases them when it settles, so available dips below balance while work is running.

Gate a "can I generate?" decision on available, not balance. Reserving against the gross number double-counts credits already committed to running jobs, and the reservation will fail at the gate.

When available can't cover a reservation, the generation is rejected with 402 BILLING_EXHAUSTED.

Parent and child wallets

Each child organization has its own isolated wallet. A child's spend never touches a sibling's balance, and the parent is always the billing principal — children never put a card on file. Three mechanisms move and govern credits between a parent and its children: allocation, caps, and auto-refill.

Allocation — funding a child

A child starts empty. You fund it by allocating credits from your parent wallet down to the child:

POST /v1/organizations/:orgId/credits/allocate with { "credits": <positive integer> } moves that many credits out of your parent balance and into the child's. It's idempotent — send an Idempotency-Key so a retry doesn't double-fund. The response reports the child's post-allocation balance and available.

Every allocation writes paired ledger rows: a positive allocation event on the child's credit ledger and the matching debit on your own /v1/credits/events. If your parent wallet is short, the allocate call returns 402 BILLING_EXHAUSTED; allocating into an archived child returns 409 CONFLICT.

When you archive a child, its unspent non-reserved credits are reclaimed to the parent automatically (reported as reclaimedCredits). Credits reserved for in-flight work are not swept.

Credit config — caps and auto-refill

A child's spend governance — its monthly cap and its auto-refill rule — lives in one place: the child's credit config, which you read and set with your parent (org:admin) key. GET /v1/organizations/:orgId/credit-config returns it; PATCH …/credit-config sets it. All three knobs are in credits (not cents), and each is nullable — null means "no cap" / "no auto-refill":

FieldMeaning
monthlyCreditCapCeiling on the child's spend per billing period. null = uncapped.
refillThresholdWhen the child's available drops below this, auto-refill fires.
refillAmountHow many credits each auto-refill moves from the parent.
autoRefillEnabledRead-only, derived: true exactly when both refillThreshold and refillAmount are set.

The PATCH is partial: send only the fields you're changing (a number sets, null clears, omitted leaves unchanged). Auto-refill is both-or-neither — after your patch, refillThreshold and refillAmount must be both set or both null, or the call is rejected with 422 (details.code: REFILL_REQUIRES_THRESHOLD_AND_AMOUNT). A one-sided patch is fine when the other side is already set.

Caps — bounding a child's monthly spend

Set monthlyCreditCap (say, 5,000 credits/month) so one customer can't drain the budget you allocated across your roster. Once it's in force:

  • A child generates normally until its period spend (used + reserved) would exceed the cap. The check is strict — a child exactly at its cap can still place a reservation that lands it on the cap, but not one that crosses it.
  • Once a reservation would cross the cap, that generation is rejected with 402 BILLING_EXHAUSTED (details.reason: "cap"). The child's existing balance is untouched; the cap is about rate of spend this period, not total funds.
  • A capped child is never auto-refilled to get past its cap — the cap is authoritative. The period counter resets on the normal billing-period boundary.

Auto-refill — keeping a child topped up

Set refillThreshold + refillAmount (say, threshold 1,000 / amount 2,000) and a child tops itself up from the parent whenever it runs low — the same parent→child transfer as a manual allocation, no Stripe charge, no new payment path. With those set, autoRefillEnabled reads true. How it behaves:

  • The refill fires from the generation path the moment a child's available falls below refillThreshold, moving refillAmount and recording it as an allocation event on both ledgers.
  • A short cooldown (a few minutes) means a burst of generations tops the child up once, not once per request.
  • If the parent wallet is exhausted, the refill is a no-op: the child stays under-funded and that generation gets 402 BILLING_EXHAUSTED, but siblings are untouched and a later attempt retries once the parent is topped up.
  • A child that is over its cap is never refilled — the cap is checked first, so refill can't be used to spend past the ceiling.

The child's current config also rides along on the GET /v1/organizations/:orgId summary as summary.creditConfig, so a dashboard can show a customer's cap + refill state without a second call.

Credit config is governance the parent sets; a child key never sees or changes it. From the child's side caps and refills are invisible until a reservation is denied — at which point the signal is always 402 BILLING_EXHAUSTED.

See also

On this page