> ## Documentation Index
> Fetch the complete documentation index at: https://docs.reap.global/llms.txt
> Use this file to discover all available pages before exploring further.

# Virtual Asset Postings

> Credit, debit, and settle virtual asset balances on an account through a single endpoint.

<Note>
  Applies to **Program-Funded** programs. See [Overview](/virtual-assets/overview) for the bigger picture.
</Note>

A **virtual asset posting** is how you update an account's virtual asset balances. Every posting carries a `type` that says what kind of change you mean, plus one or more `entries` listing the virtual assets and amounts involved. The whole posting is applied atomically: either all entries land, or none do.

## The three types

| `type`       | What it does                                                                                                                                    | Typical use                                                            |
| ------------ | ----------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------- |
| `DEPOSIT`    | Credits the entries to the account's virtual balance.                                                                                           | User deposits with you, sign-up bonus, cashback, salary, top-up.       |
| `WITHDRAWAL` | Debits the entries from the account's virtual balance. Rejected if any entry would take a balance below zero.                                   | User withdraws from you, expiring a bonus, revoking unspent allowance. |
| `SETTLEMENT` | Debits the entries from the account's virtual balance **and** applies their value (in the program's billing currency) to outstanding card debt. | Closing the loop after card spend.                                     |

All three go through the same call:

```
POST /postings
```

See [`POST /postings`](/api-reference/virtual-asset-postings/create-posting) for the full request and response contract, including `settledAmount` and per-entry `rateSnapshot` returned for `SETTLEMENT`.

<Tip>
  Submit multiple `entries` in one posting to apply correlated changes together. A multi-asset deposit, a multi-asset settlement, or a deposit-and-bonus stack all go in a single call, so partial states never become visible.
</Tip>

## Patterns

Most programs fall into one of two shapes. They use the same endpoint and the same operations; what differs is what the balance represents on your side, and which postings you actually need.

### Custodial mirror

You hold the user's funds on your side - a custody wallet, an exchange account, a fund - and the virtual balance on Reap mirrors yours so the user can spend on their card.

* **User deposits with you** → `DEPOSIT` for the matching asset.
* **User withdraws from you** → `WITHDRAWAL` for the same asset.
* **User's card spend has cleared** → `SETTLEMENT` for the asset they are paying with. Debits their virtual balance and clears the matching card debt in one step.

The third operation is what makes `SETTLEMENT` distinct from `WITHDRAWAL`. After a card swipe clears, you need to pull from the user's holdings on your side to cover their card spend. A plain `WITHDRAWAL` for that pull would drop the user's available balance a second time - once when the card debt accrued, again when the withdrawal posted. `SETTLEMENT` nets the two against each other so the user's spending position only moves once and matches what they swiped.

Each entry's `amount` is the delta to apply, not the new total. A user depositing 100 USDC becomes a `DEPOSIT` with `entries: [{ virtualAssetId: <USDC>, amount: "100" }]`; a later 30 USDC withdrawal becomes a `WITHDRAWAL` with `amount: "30"`.

### Issued credits

You give the user balance - cashback, sign-up bonus, salary allowance - funded by your program rather than the user's own holdings. Define one virtual asset per credit type (e.g., `BONUS_USD` with a FIXED rate of `1.00`) and:

* **Grant** → `DEPOSIT`. The user can spend it on their next card swipe.
* **Revoke unused balance** → `WITHDRAWAL`.

Whether you also need `SETTLEMENT` against the granted asset depends on how you want card debt to behave on the account; see the next section.

## Settling card debt

`SETTLEMENT` is how you close card debt against a user's virtual balance. You debit the user's balance for the assets they are paying with, and Reap converts those amounts to the program's billing currency and applies them against the account's outstanding card debt in the same atomic step.

```json theme={null}
{
  "type": "SETTLEMENT",
  "entries": [
    { "virtualAssetId": "<USDC>", "amount": "12.50" }
  ]
}
```

You only pass virtual asset units. Reap computes the settled value in the program's billing currency using each asset's rate at posting time, returns it as `settledAmount` on the response.

### When you need it

For [custodial mirror](#custodial-mirror) programs, `SETTLEMENT` is essential. It is how you pull from the user's holdings to cover their card spend without dropping the user's available balance twice.

For [issued-credit](#issued-credits) programs, `SETTLEMENT` is optional. The available balance equation `assets - liabilities` already shows the right number for the user - card debt subtracts from it as soon as a swipe clears, regardless of whether you post anything. Whether you also post `SETTLEMENT` against the credit depends on how you want the books to read:

* **Post `SETTLEMENT`** to drain the credit's virtual balance as the user spends. The virtual balance then reflects credit-still-available, and `cardDebt.cleared` returns to zero. Cleaner per-asset reporting; more API calls.
* **Skip `SETTLEMENT`** and let `cardDebt.cleared` grow as the running total of granted-and-spent. The virtual balance reflects credit-ever-granted, and the user's available position is still correct. Fewer calls; the per-asset view shows totals rather than remaining.

Pick what matches how you reconcile on your side. Both are valid.

### How card debt is drained

Card debt on an account is split into two buckets:

* `pending` - authorizations that have been approved but not yet cleared by the network.
* `cleared` - cleared transactions awaiting settlement from you.

Each `SETTLEMENT` drains `cleared` first, then any overflow drains `pending`. You can read the current split from [`GET /accounts/:id/balance`](/api-reference/accounts/get-account-balance) under `liabilities.cardDebt`.

### Card debt can go negative

If you settle more than the user owes (or the user gets a refund after settlement), `liabilities.cardDebt.total` goes negative. Negative card debt is real credit on the account: it absorbs future card spend before any virtual balance is drained. Reap surfaces the structured split (`pending`, `cleared`, `total`) on the balance endpoint so you can decide how to present it.

## Sizing WITHDRAWAL postings

A `WITHDRAWAL` only checks that its entry does not take the virtual asset's own balance below zero. It does **not** check `availableBalance`. Posting a `WITHDRAWAL` that ignores outstanding card debt can leave the account with a negative `availableBalance` - and the master collateral account holding the bag for spend you have already let the user pull off your side.

To size a `WITHDRAWAL` safely, read the `withdrawable` field on each row of [`GET /accounts/:id/assets`](/api-reference/accounts/get-account-assets). It is the maximum amount of that virtual asset you can debit without taking `availableBalance` below zero. Outstanding card debt - including pending authorizations - is netted out, so the value matches what the account can actually release at the moment of the call.

`withdrawable` is a **per-asset cap, not a budget that adds up across rows**. Each value assumes only that asset is being debited and every other balance stays untouched. Example on an account holding 100 `USDC` virtual and 500 `YUSD` virtual with $100 of card debt and $525 of headroom:

* The `USDC` row shows `withdrawable: "100.000000"` (the full balance - well under the \$525 cap).
* The `YUSD` row shows `withdrawable: "500.000000"` (the full balance - same headroom, different asset).

You cannot do both. After each posting, call the endpoint again to read the updated caps.

## Best practices

### Order postings around your actual fund movements

The posting changes Reap's view of what the user can spend. When the matching change happens on your side matters.

* **`DEPOSIT` only after on-chain finalization.** When the deposit you are mirroring is a chain transfer into your custody, wait for it to be finalized (irreversible), not just confirmed once. If you credit on confirmation and the transfer is later reorged out, you have enabled spend the user cannot back. Plain confirmation depth is not enough on chains that re-org.
* **`WITHDRAWAL` before the user withdraws.** If you debit Reap after letting the user pull funds, the user can race the withdrawal against a card swipe and overspend. Post the `WITHDRAWAL` first sized via [`withdrawable`](#sizing-withdrawal-postings); once it returns successfully, you know Reap will reject further spend against that amount, and you can release the funds on your side.
* **`SETTLEMENT` after card spend is observable.** Settle on the [`CARD_TRANSACTION_UPDATED`](/api-reference/card-transaction-updated) clearing webhook or on a periodic cadence using `liabilities.cardDebt.cleared` as the target.

### Use the `Idempotency-Key` header

Every successful posting is a new ledger event, so retries without idempotency double-apply. Pass an `Idempotency-Key` header with a stable, request-scoped value (UUID v4 is fine) and Reap will return the original result on retry instead of creating a duplicate posting.

### One posting per real-world event

A multi-asset deposit on your side becomes one `DEPOSIT` posting with multiple entries, not one posting per asset. This avoids brief windows where Reap shows half the deposit applied, and keeps every entry in the same atomic ledger event for audit.

## What postings are not

* **Not a cap on card spend.** Available balance is the cap. Postings feed into available balance but do not block individual transactions on their own.
* **Not a log of your internal movements.** Only post when you want Reap's view of the user's balance to change. Internal transfers between two of your own buckets do not need a posting.
* **Not how Reap settles with the card network.** That happens automatically against the master collateral account. Postings settle the user side: your obligation to the user, and the user's spend on Reap.
