Skip to main content
Early access, with metered billing.
Reading the credit balance before each request has two gaps. It only knows the usage you have already sent, and two requests that start at the same moment both see the same credit. For expensive work, such as an AI generation or a batch of SMS, that can let a customer spend past zero. A hold closes both gaps. Before the work, you reserve the credit it will need. If the credit can’t cover it, the hold is refused and you stop.

How it works

1

Hold before the work

Bouclay prices the usage the way the invoice will (tiers, discount, VAT, which credit pays first) on top of the usage so far and every other open hold. It answers:
  • 201 with the hold (hold_…). amount is what it takes from the credit. Go ahead.
  • 402 insufficient_credit, with available and needed. Nothing is reserved. Stop here.
  • 409 spending_cap_reached when the usage would go past a spending cap that stops billing.
2

Do the work

3

Commit what was actually used

This records the usage as meter events and closes the hold in one step, so it is billed once. Less than held frees the rest. More is accepted and billed as ordinary usage.If the work didn’t happen, call POST /credit-holds/{id}/release instead.
Commit and release are safe to retry and need no Idempotency-Key.

Details

  • Expiry. expiresIn is in seconds: 3,600 by default, 7 days at most. A hold neither committed nor released stops counting when it expires, and you get credit_hold.updated. Committing it afterwards is refused with 409 hold_expired: send the usage as a meter event instead.
  • Which meters. Holds work on meters that sum their values, billed by one of the customer’s active subscriptions. When those meters bill in two currencies, pass currency.
  • On the balance. Open holds show as held on the credit balance and come off projectedAvailable.
  • Scopes. Holds use the credits scope. Committing records usage without needing usage:write.