AVAILABLE balance to HELD and returns a PENDING redemption. Your fulfillment service then completes, fails, or cancels that redemption.
Instant redemptions suit flows that can deliver immediately. Both modes use the same amount and catalog redemption endpoints.
Choose a fulfillment mode
Set the default on the program:
fulfillment_mode defaults to INSTANT. pending_redemption_ttl is optional and accepts a duration from 60 seconds through 365 days. A create request can override the mode with capture:
Authorize a redemption
Setcapture to false on an amount redemption:
capture, expires_at, and ttl_seconds fields at POST /v1/participants/{id}/redemptions/items.
The response includes the status, hold and reservation IDs, and deadline:
journal_entry_id is the HOLD journal entry that authorized it. capture_journal_entry_id, captured_at, and resolved_at appear after successful capture. release_journal_entry_id, released_amount, and resolved_at appear after a fail, cancel, or timeout that released value.
Track catalog inventory
For aUNIT_BASED catalog reward, authorization increments both committed_units and pending_units. Capture moves the quantity from pending_units to delivered_units while committed_units stays unchanged. Failure, cancellation, and timeout decrement pending_units and committed_units without changing delivered_units.
Releasing pending inventory can return an OUT_OF_STOCK reward to ACTIVE. See Rewards catalog for the full inventory contract.
Use the returned deadline
You can send one request deadline:expires_at: absolute RFC 3339 timestampttl_seconds: lifetime relative to authorization
LOT asset, the redemption must complete before any selected lot expires. This can shorten the deadline. Schedule fulfillment against the expires_at returned on the redemption.
If the resulting deadline is less than 60 seconds away, authorization returns
422 fulfillment_window_too_short.
Capture is accepted only before the returned deadline. At or after it, the complete endpoint returns 409 reservation_expired, even if the redemption still shows PENDING.
Resolve the redemption
Send anIdempotency-Key header on complete, fail, and cancel.
Complete
Complete only after your fulfillment provider confirms delivery:HELD to the redemption target in one REDEMPTION journal entry and changes the redemption to COMPLETED. Capture is full-only. The amount cannot be changed during completion.
An authorization can still complete while the participant is SUSPENDED
because the spend was already approved. A CLOSED participant cannot be
captured.
Fail
Use failure when fulfillment was attempted and could not be delivered:Cancel
Use cancellation when your application or the participant stops fulfillment before delivery:HELD to AVAILABLE in one RELEASE journal entry. The response names that entry in release_journal_entry_id and the amount it returned in released_amount. They do not recreate LOT value that already expired. If all of the reserved value has expired, no RELEASE is created and both fields are null.
State transitions
Only
COMPLETED and PARTIALLY_REVERSED redemptions can be reversed. See Redemptions.
The first terminal request wins. Repeating the same outcome returns the stored redemption. A different terminal request returns 409 redemption_already_resolved.
Ledger entries
Each transition creates one journal entry. Itsaction_type tells you which step a statement row or journal entry belongs to.
The redemption’s
journal_entry_id is the HOLD entry, capture_journal_entry_id is the REDEMPTION entry, and release_journal_entry_id is the RELEASE entry. released_amount is the amount the RELEASE returned to AVAILABLE. For a LOT asset, the HOLD, RELEASE, and REDEMPTION entries share one reference_id, so GET /v1/journal-entries?reference_id=... returns the full ledger history of one redemption. For a SIMPLE asset, reference_id is empty on these entries.
release_journal_entry_id and released_amount are set only when reserved value was released:
The
EXPIRATION entry comes from lot expiration, not from the redemption. It has no program_id, event_id, or reference_id, so a group statement filtered by program_id leaves it out. See Lots and expiration.
Expiration and reserved lots
A reservation protects value fromRELEASE, FORFEIT, and VOID_HOLD operations. It does not stop normal LOT expiration. Reserved lots keep their original expiration, maturity, and issuing program.
Scrip changes an overdue PENDING redemption to FAILED with failure_reason: "expired" and creates a RELEASE for the reserved value still in HELD. Fail and cancel behave the same way. If every reserved lot already expired, there is no RELEASE, the reservation ends EXPIRED, and release_journal_entry_id stays null. That value left HELD earlier through an EXPIRATION entry.
Gift cards
Scrip handles fulfillment for gift cards. It reserves the participant’s balance, orders the card, and captures the balance when the order succeeds. Follow Gift cards for the purchase flow and Get redemption for order statuses and cancellation rules.Webhooks and balance mirrors
Authorization emitsredemption.pending and balance.held. The pending webhook includes the reservation_id and effective expires_at. A fulfillment provider can identify the reservation and schedule capture without fetching the redemption first. Capture emits redemption.completed and balance.redeemed with bucket: "HELD". An instant redemption emits redemption.completed and balance.redeemed with bucket: "AVAILABLE". Failure and timeout emit redemption.failed plus balance.released when live value is released. Cancellation emits redemption.cancelled plus balance.released when live value is released. A reversal emits redemption.reversed and balance.reversed.
Every journal action has one movement event, so a participant or group balance mirror that applies every balance.* and transfer.completed event stays consistent with participant balance and statement reads. Program wallet balances cannot be reconstructed from webhooks; see Movement and lifecycle events. See Event payloads for each data object.
Time windows
The participant redemption list filtersfrom and to by creation time, which is the authorization time for a pending redemption. Reporting recognizes redeemed value when capture succeeds, using captured_at.
A redemption authorized in June and captured in July appears in a June-filtered redemption list and in July reporting. Use each surface for its stated purpose.
Redemptions
Instant redeem, catalog items, and reversals.
Webhooks
redemption.*, balance.held, balance.redeemed, and balance.released.Lots and expiration
Reserved lots keep their original expiration.