While rules handle most balance changes automatically, you can also modify balances directly via the API for customer service, corrections, and manual workflows.Documentation Index
Fetch the complete documentation index at: https://docs.scrip.dev/llms.txt
Use this file to discover all available pages before exploring further.
Adjust
Credit or debit a participant’s balance:| Field | Required | Description |
|---|---|---|
program_id | Yes | Program context |
asset_id | Yes | Which asset to adjust |
type | Yes | CREDIT or DEBIT |
amount | Yes | Positive amount |
allow_negative | No | DEBIT only. When true, allows the debit to overdraw the balance below zero. Used for clawbacks. Defaults to false. |
bucket | No | AVAILABLE (default) or HELD |
description | Yes | Reason for the adjustment (1-500 characters) |
type to control direction. DEBIT fails if the available balance is insufficient, unless allow_negative is set to true. If amount has more decimal places than the asset’s scale, the request is rejected with a 400 (invalid_scale). Round in your client before calling adjust.
Negative Balances
Setallow_negative to true on a DEBIT to let the balance go below zero. This is useful when you need to recover value that a participant has already spent:
- Refund clawbacks. A cardholder earned cashback on a purchase that was later refunded. The cashback has already been redeemed, so the available balance is zero. A negative-balance debit records the debt.
- Chargeback recovery. A payment is disputed and reversed, but the associated reward points were already used. The debit brings the balance negative until the participant earns enough to offset it.
- Corrections. An incorrect credit was issued and the participant has already spent part of it. A negative-balance debit corrects the ledger without waiting for funds to replenish.
LOT-mode assets, the system consumes whatever lots are available first, then posts the remaining amount as an overdraft. The balance goes negative by the uncovered portion.
allow_negative also works in rule actions. This lets your rules engine handle clawbacks automatically, for example debiting cashback when a refund event arrives, even if the participant’s balance is zero.
allow_negative only applies to adjustments and rule-based debits. Transfers and redemptions always require sufficient funds.Hold
Reserve funds by moving them fromAVAILABLE to HELD:
| Field | Required | Description |
|---|---|---|
program_id | Yes | Program context |
asset_id | Yes | Which asset to hold |
amount | Yes | Positive amount to reserve |
reference_id | No | Correlation ID for this hold (LOT mode only). Stamps held lots so a future release can target them. 1-255 characters, alphanumeric plus ._:@-. |
description | Yes | Reason for the hold (1-500 characters) |
- Authorization holds (reserve rewards until the transaction settles)
- Fraud review (freeze funds pending investigation)
- Pending approvals (hold until manual review completes)
Release
Move held funds back toAVAILABLE:
| Field | Required | Description |
|---|---|---|
program_id | Yes | Program context |
asset_id | Yes | Which asset to release |
amount | No | Amount to release. If omitted, all matching held lots are released. |
reference_id | No | Release only lots stamped with this reference during a previous hold (LOT mode only) |
description | Yes | Reason for the release (1-500 characters) |
reference_id is provided, only lots stamped with that reference during a previous hold are targeted. You can also filter by lot age using earned_from and earned_to (RFC 3339 timestamps) for batch-releasing held balances. LOT mode only.
Forfeit
Remove funds permanently from a participant’s balance:| Field | Required | Description |
|---|---|---|
program_id | Yes | Program context |
asset_id | Yes | Which asset to forfeit |
amount | Yes | Positive amount |
bucket | Yes | AVAILABLE or HELD. Specifies which balance bucket to forfeit from. |
description | Yes | Reason for the forfeit (1-500 characters) |
SYSTEM_BREAKAGE account.
Void Hold
Cancel HELD lots that were credited directly into HELD (e.g., pending authorization rewards) byreference_id, returning value to the original source account:
| Field | Required | Description |
|---|---|---|
program_id | Yes | Program context |
asset_id | Yes | Which asset to void (LOT mode only) |
reference_id | Yes | Correlation ID matching the original CREDIT to HELD |
description | Yes | Reason for the void (1-500 characters) |
PREFUNDED assets, SYSTEM_ISSUANCE for UNLIMITED).
Void hold only processes lots that were created directly in HELD via CREDIT. Lots moved to HELD via a HOLD operation (participant funds) are excluded for safety — returning those to the source would effectively confiscate participant value. Use release to return participant-held funds to AVAILABLE.
amount, lot_ids, earned_from, and earned_to are not supported — the entire provisional accrual matching the reference_id is voided.
Auth / Settlement Pattern
Card transactions follow a two-step lifecycle: the issuer-processor authorizes the transaction first, and the merchant settles (captures) it later — sometimes hours or days after. The settlement amount can differ from the authorization due to tips, partial captures, or currency conversion. Most programs can skip authorizations and credit rewards on settlement only. This is the simplest approach, and the Stripe Issuing example uses it. But if your program needs to show pending rewards to cardholders in real time — before the transaction settles — you can use the auth/settle pattern to hold provisional rewards at authorization and reconcile them when the merchant captures. This is the dual-message pattern common in card processing: both the authorization and settlement events flow into Scrip, and the system handles the difference between them automatically.This pattern requires a
LOT-mode asset. reference_id stamps individual lots at authorization so they can be matched at settlement. For SIMPLE-mode assets, use amount-based holds and releases without reference_id.Authorization: hold provisional rewards
When a cardholder taps their card, your issuer-processor fires an authorization webhook. Your backend forwards it as an event with The cardholder’s balance now shows pending rewards in the
event.type == "auth". A rule credits points into the HELD bucket, stamping the lots with the authorization ID:held field. These are not spendable.Alternatively, if the participant already has an AVAILABLE balance and you want to reserve existing points rather than mint new ones:Settlement: reconcile and finalize
When the merchant captures the transaction, your backend sends a second event with This is the recommended approach when the settlement amount may differ from the authorization. If no held lots exist for the When
event.type == "settlement". Two approaches:Auto-reconcile with CREDIT. Credit to AVAILABLE with the same reference_id. The system finds the held lots, consumes them, and creates new available lots for the settlement amount. If the amounts differ, the delta is handled automatically — extra funds are sourced from the program wallet (or system issuance for unlimited assets), and any excess is returned.reference_id (e.g., the auth event was missed or not sent), the system falls back to a standard credit.Simple release. If the settlement amount always matches the authorization, a release is sufficient. This moves the held lots back to AVAILABLE without reconciliation:amount is omitted with a reference_id, all lots held under that reference are released.Or: void the authorization
If the authorization is reversed before settling, use For authorizations that simply expire without settling, set
VOID_HOLD to cancel the provisional rewards. This returns value to the source account (program wallet or system issuance):expires_at on the original CREDIT (e.g., "720h"), which automatically forfeits uncaptured holds after the expiration window.See the Stripe Issuing example for details on handling uncaptured authorizations.How auto-reconciliation works
When aCREDIT to AVAILABLE includes a reference_id that matches existing HELD lots, the system reconciles automatically:
| Settlement vs. auth | What happens |
|---|---|
| Equal | Held lots consumed, same amount credited to AVAILABLE |
| Settlement > auth (over-capture, e.g., tip added) | Extra amount sourced from program wallet or system issuance |
| Settlement < auth (under-capture, e.g., partial capture) | Excess returned to program wallet or system issuance |
No held lots found for the reference_id | Standard credit applied with reference_id stamped on the lot |
When to use this pattern
| Scenario | Approach |
|---|---|
| Show pending rewards at authorization, reconcile at settlement | Auth/settle pattern (this section) |
| Credit rewards only after settlement | Credit on settlement directly — no holds needed. See Stripe Issuing. |
| Reserve existing points for a pending operation (e.g., redemption approval) | Hold and release without reference_id |
Lot Preservation
ForLOT-mode assets, hold and release operations preserve lot metadata. When a lot moves from AVAILABLE to HELD (or back), its expires_at, matures_at, created_at, and lot ID all remain unchanged. The lot keeps its identity across bucket transitions.
Inactive Participants
Most balance operations (adjust, hold, release) are blocked forSUSPENDED and CLOSED participants. The API returns a 409 error with code participant_inactive.
Forfeit and void hold are the exceptions: they are allowed on CLOSED participants so you can clean up remaining balances after account closure. Both are still blocked for SUSPENDED participants.