Skip to main content
While rules handle most balance changes automatically, you can also modify balances directly via the API for customer service, corrections, and manual workflows.

Adjust

Credit or debit a participant’s balance:
POST /v1/participants/{id}/balances/adjust
{
  "program_id": "program-uuid",
  "asset_id": "asset-uuid",
  "type": "CREDIT",
  "amount": "500",
  "description": "Customer service goodwill credit"
}
FieldRequiredDescription
program_idYesProgram context
asset_idYesWhich asset to adjust
typeYesCREDIT or DEBIT
amountYesPositive amount
allow_negativeNoDEBIT only. When true, allows the debit to overdraw the balance below zero. Used for clawbacks. Defaults to false.
bucketNoAVAILABLE (default) or HELD
descriptionYesReason for the adjustment (1-500 characters)
Amounts must be positive. Use type to control direction. DEBIT fails if the available balance is insufficient, unless allow_negative is set to true. If an amount has more decimal places than the asset’s scale, it is rounded automatically (e.g., "1.009" becomes "1.01" for scale: 2).

Negative Balances

Set allow_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.
POST /v1/participants/{id}/balances/adjust
{
  "program_id": "program-uuid",
  "asset_id": "asset-uuid",
  "type": "DEBIT",
  "amount": "25",
  "allow_negative": true,
  "description": "Clawback: refund on order #4821"
}
For 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 from AVAILABLE to HELD:
POST /v1/participants/{id}/balances/hold
{
  "program_id": "program-uuid",
  "asset_id": "asset-uuid",
  "amount": "500",
  "reference_id": "auth_78945",
  "description": "Auth hold - txn 78945"
}
FieldRequiredDescription
program_idYesProgram context
asset_idYesWhich asset to hold
amountYesPositive amount to reserve
reference_idNoCorrelation ID for this hold (LOT mode only). Stamps held lots so a future release can target them. 1-255 characters, alphanumeric plus ._:@-.
descriptionYesReason for the hold (1-500 characters)
Held funds are not spendable. Use holds for:
  • 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 to AVAILABLE:
POST /v1/participants/{id}/balances/release
{
  "program_id": "program-uuid",
  "asset_id": "asset-uuid",
  "reference_id": "auth_78945",
  "description": "Settlement confirmed"
}
FieldRequiredDescription
program_idYesProgram context
asset_idYesWhich asset to release
amountNoAmount to release. If omitted, all matching held lots are released.
reference_idNoRelease only lots stamped with this reference during a previous hold (LOT mode only)
descriptionYesReason for the release (1-500 characters)
When 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, earned_to, expires_before, and expires_after for batch-releasing held balances.

Forfeit

Remove funds permanently from a participant’s balance:
POST /v1/participants/{id}/balances/forfeit
{
  "program_id": "program-uuid",
  "asset_id": "asset-uuid",
  "amount": "100",
  "bucket": "AVAILABLE",
  "description": "Expired points"
}
FieldRequiredDescription
program_idYesProgram context
asset_idYesWhich asset to forfeit
amountYesPositive amount
bucketYesAVAILABLE or HELD. Specifies which balance bucket to forfeit from.
descriptionNoReason for the forfeit
Forfeited funds move to the SYSTEM_BREAKAGE account.

Auth / Settlement Pattern

Holds model authorization and settlement flows. Use reference_id to correlate the hold with its corresponding settlement or void, especially when a participant has multiple concurrent holds.
1

Transaction authorized

Your backend sends an event with event.type == "auth". A rule matches and holds existing points, stamping the held lots with a reference_id:
{"type": "HOLD", "asset_id": "...", "amount": "event.amount", "reference_id": "event.authorization_id"}
Or, if crediting new points directly into HELD:
{"type": "CREDIT", "asset_id": "...", "amount": "event.amount", "bucket": "HELD", "reference_id": "event.authorization_id"}
2

Transaction settles

Your backend sends a second event with event.type == "settlement". Two approaches:Release held funds. A rule releases the held lots by reference, returning them to AVAILABLE:
{"type": "RELEASE", "asset_id": "...", "reference_id": "event.authorization_id"}
When amount is omitted with a reference_id, all lots held under that reference are released.Settle via CREDIT. A rule credits to AVAILABLE with the same reference_id used during the hold:
{"type": "CREDIT", "asset_id": "...", "amount": "event.settlement_amount", "reference_id": "event.authorization_id"}
When reference_id matches existing held lots, the system reconciles the held amount against the settlement amount. If the settlement differs from the hold, the difference is handled automatically. Excess is credited to the participant, and shortfall is returned to the program. If no prior hold exists for the reference, a standard credit is applied.
3

Or: Transaction voided

If your backend sends an event with event.type == "void" instead, a rule forfeits the held points:
{"type": "FORFEIT", "asset_id": "...", "amount": "event.amount", "bucket": "HELD"}
reference_id requires a LOT mode asset. For SIMPLE mode assets, use amount-based holds and releases without reference_id.

Lot Preservation

For LOT-mode assets, hold and release operations preserve lot metadata (expires_at, matures_at, created_at). Lots move between buckets but retain their identity and lifecycle dates.

Inactive Participants

Most balance operations (adjust, hold, release) are blocked for SUSPENDED and CLOSED participants. The API returns a 409 error with code participant_inactive. Forfeit is the exception: it is allowed on CLOSED participants so you can clean up remaining balances after account closure. Forfeit is still blocked for SUSPENDED participants.