---
description: >-
  End-to-end Wallet API walkthrough — deposit and split a wire across sub-wallets, preauthorize, capture, refund, void, and transfer, with balance checks at every step.
---

# Integration Guide

This guide walks through a real B2B scenario end-to-end.

**Scenario:** ACME Corp wires $10,000 USD to Inyo. That money is split across 10 sub-wallets — one per vendor — with $1,000 each. Vendor 03 later runs a $500 preauthorization for an outstanding invoice, captures $400 of it (the invoice came in lower than expected), refunds $50 to the customer, and finally voids the remaining hold.

Every dollar remains traceable back to the original wire.

For the examples below, export these once:

```bash
export WALLET_HOST=https://{FQDN}
export TENANT=acme-corp
export API_KEY=your-tenant-api-key
```

***

### Step 1 — Create the Wallets

You need 11 wallets: one "treasury" wallet that receives the wire, and 10 vendor wallets that receive the split.

```bash
curl -sS -X POST "$WALLET_HOST/organizations/$TENANT/wallets" \
  -H "X-API-KEY: $API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: acme-treasury-2026-07-14" \
  -d '{
    "owner_type": "company",
    "owner_ref": "acme-corp",
    "name": "ACME Treasury"
  }'
```

Response:

```json
{
  "id": "f64c49bd-47a3-4cc6-b9d4-265d1fe5ba65",
  "name": "ACME Treasury",
  "kind": "operational",
  "ownerType": "company",
  "ownerRef": "acme-corp",
  "createdAt": "2026-07-14T04:01:33+00:00"
}
```

Repeat for the 10 vendor wallets with different `owner_ref` and `name` values, and store the returned UUIDs. Below, `$VENDOR_03_ID` refers to vendor 03's wallet.

> **Naming your `Idempotency-Key`:** use something meaningful and unique per operation (e.g., `acme-vendor-03-2026-07-14`). Reusing the same key returns the original response instead of creating a duplicate — safe to retry on network failure.

***

### Step 2 — Deposit + Split the $10k Wire

ACME's bank confirmed the wire hit your settlement account. Record it in the ledger and split it across the 10 vendors in one atomic operation:

```bash
curl -sS -X POST "$WALLET_HOST/organizations/$TENANT/deposits" \
  -H "X-API-KEY: $API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: wire-BANKREF-20260714-001" \
  -d '{
    "source": {
      "source_type": "wire",
      "external_ref": "BANK-WIRE-98765432",
      "asset_code": "USD",
      "amount": "10000.00",
      "received_at": "2026-07-14T14:30:00Z",
      "metadata": {
        "originator": "ACME Corp",
        "reference": "Q3 vendor payments"
      }
    },
    "splits": [
      {"wallet_id": "<VENDOR_01_ID>", "amount": "1000.00"},
      {"wallet_id": "<VENDOR_02_ID>", "amount": "1000.00"},
      {"wallet_id": "<VENDOR_03_ID>", "amount": "1000.00"},
      {"wallet_id": "<VENDOR_04_ID>", "amount": "1000.00"},
      {"wallet_id": "<VENDOR_05_ID>", "amount": "1000.00"},
      {"wallet_id": "<VENDOR_06_ID>", "amount": "1000.00"},
      {"wallet_id": "<VENDOR_07_ID>", "amount": "1000.00"},
      {"wallet_id": "<VENDOR_08_ID>", "amount": "1000.00"},
      {"wallet_id": "<VENDOR_09_ID>", "amount": "1000.00"},
      {"wallet_id": "<VENDOR_10_ID>", "amount": "1000.00"}
    ]
  }'
```

Response (abbreviated — the full response has all 11 entries):

```json
{
  "id": "419b03c7-7679-4bce-b3d9-d90f75418602",
  "kind": "deposit",
  "externalRef": "wire-BANKREF-20260714-001",
  "metadata": {
    "source_uuid": "268eda6f-ed57-4e8c-9a07-1b39f15ec817"
  },
  "entries": [
    { "assetCode": "USD", "direction": "debit",  "amount": "10000.00000000", "lineageRef": null },
    { "assetCode": "USD", "direction": "credit", "amount": "1000.00000000",  "lineageRef": [7] }
  ],
  "createdAt": "2026-07-14T14:30:12+00:00"
}
```

**What just happened:**

1. A source row was created recording the wire.
2. A journal of kind `deposit` was written with 11 entries: one debit of $10,000 against the external-source account ("money coming from outside the ledger") and 10 credits of $1,000 against the vendor wallets.
3. Every credit entry carries a `lineageRef` pointing at the source.
4. Sum of debits equals sum of credits — the double-entry invariant holds.

The `source.amount` **must** equal the sum of splits — otherwise the API returns a `LEDGER_IMBALANCE` error.

> To keep a portion of the wire in a system suspense account (settlement fees, ops float), pass `gateway_suspense_amount` at the top level. Then `sum(splits) + gateway_suspense_amount` must equal `source.amount`.

Accepted `source_type` values: `wire`, `ach_debit`, `card`, `stablecoin_deposit`.

***

### Step 3 — Check Balances

```bash
curl -sS "$WALLET_HOST/organizations/$TENANT/wallets/$VENDOR_03_ID/balance" \
  -H "X-API-KEY: $API_KEY"
```

```json
[
  {
    "assetCode": "USD",
    "posted": "1000.00000000",
    "held": "0.00000000",
    "available": "1000.00000000",
    "updatedAt": "2026-07-14T14:30:12+00:00"
  }
]
```

Vendor 03 has $1,000 available. If a wallet holds multiple assets, filter with `?asset=USD` — this returns a single-element array (or empty if no balance in that asset).

***

### Step 4 — Preauthorize $500

Vendor 03 has an incoming invoice. Reserve $500 before you know the exact amount so the money can't be spent elsewhere:

```bash
curl -sS -X POST "$WALLET_HOST/organizations/$TENANT/holds" \
  -H "X-API-KEY: $API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: preauth-invoice-INV-4521" \
  -d "{
    \"wallet_id\": \"$VENDOR_03_ID\",
    \"asset_code\": \"USD\",
    \"amount\": \"500.00\",
    \"expires_at\": \"2026-07-21T14:30:00Z\"
  }"
```

Response:

```json
{
  "id": "19f60a03-7a09-4184-bf66-23ce30115377",
  "assetCode": "USD",
  "amount": "500.00",
  "status": "open",
  "expiresAt": "2026-07-21T14:30:00Z",
  "resolvedAt": null,
  "createdAt": "2026-07-14T15:00:00+00:00",
  "captures": []
}
```

Save the hold `id` — you'll capture/void against it. The balance now shows:

```json
[
  { "assetCode": "USD", "posted": "500.00000000", "held": "500.00000000", "available": "0.00000000" }
]
```

* `posted` dropped from $1,000 to $500 — the preauth debited the wallet and credited a per-wallet hold sub-account.
* `held` shows the $500 reservation.
* `available` is $0 — every remaining dollar is reserved.

> **`expires_at` is advisory.** The hold records the expiration, but nothing auto-voids expired holds. Track hold IDs and expirations on your side and void explicitly when they lapse.

***

### Step 5 — Capture $400 of the $500 Hold

The invoice came in at $400. Capture that amount into a destination account — typically a payables/settlement wallet you created beforehand:

```bash
curl -sS -X POST "$WALLET_HOST/organizations/$TENANT/holds/$HOLD_ID/capture" \
  -H "X-API-KEY: $API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: capture-INV-4521" \
  -d "{
    \"amount\": \"400.00\",
    \"destination_account_id\": \"$PAYABLES_WALLET_ID\"
  }"
```

Response:

```json
{
  "id": "b092a884-8cc4-479d-80b5-995e668a8cdb",
  "kind": "capture",
  "metadata": {
    "hold_uuid": "19f60a03-7a09-4184-bf66-23ce30115377",
    "captured_amount": "400.00"
  },
  "entries": [
    { "assetCode": "USD", "direction": "debit",  "amount": "400.00000000", "lineageRef": [7] },
    { "assetCode": "USD", "direction": "credit", "amount": "400.00000000", "lineageRef": [7] }
  ]
}
```

> **Save the journal `id`** (`b092a884-...`) — this is the **capture journal UUID**, required to refund.

Balance after capture: `posted 500 / held 100 / available 400`. The $400 was released from the hold and moved to the destination; the $100 that was reserved above the invoice amount stays held.

**Partial captures:** you can capture multiple times against the same hold until the cumulative amount equals the hold amount. Status transitions `open → partially_captured → captured`. Once fully `captured`, no further captures or voids are possible — only refunds.

***

### Step 6 — Refund $50 of the $400 Capture

The customer disputed part of the invoice. Refund uses the **capture journal UUID** from step 5, not the hold ID:

```bash
curl -sS -X POST "$WALLET_HOST/organizations/$TENANT/captures/$CAPTURE_JOURNAL_UUID/refund" \
  -H "X-API-KEY: $API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: refund-INV-4521-partial" \
  -d '{ "amount": "50.00" }'
```

The refund debits the destination (payables wallet) and credits back to the **originating wallet** (Vendor 03) — the ledger looks up the original hold to find the source wallet. Lineage is preserved through the reversal chain.

Balance: `posted 550 / held 100 / available 450`.

You can refund partially multiple times until the cumulative refunded amount equals the captured amount. A fully-refunded capture rejects further refunds.

***

### Step 7 — Void the Remaining $100 Hold

The invoice is settled ($400 captured, $50 refunded). Release the remaining $100:

```bash
curl -sS -X POST "$WALLET_HOST/organizations/$TENANT/holds/$HOLD_ID/void" \
  -H "X-API-KEY: $API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: void-INV-4521-remainder" \
  -d '{}'
```

Balance: `posted 650 / held 0 / available 650`.

Vendor 03's final position: $1,000 in − $400 captured + $50 refunded = **$650**. Every dollar traceable back to the original wire.

***

### Step 8 — Transfer Between Wallets

Move $200 from Vendor 03 to Vendor 07 (same currency):

```bash
curl -sS -X POST "$WALLET_HOST/organizations/$TENANT/transfers" \
  -H "X-API-KEY: $API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: transfer-v03-to-v07-20260714" \
  -d "{
    \"from_wallet_id\": \"$VENDOR_03_ID\",
    \"to_wallet_id\": \"$VENDOR_07_ID\",
    \"asset_code\": \"USD\",
    \"amount\": \"200.00\"
  }"
```

The response is a `kind: transfer` journal with two entries. Transfers are same-currency only — for cross-asset conversions, use `POST /fx-conversions` with explicit `rate` and `rate_source` fields (both are echoed back in the journal's `metadata` for audit).

***

### Reading the Ledger

List every debit and credit on a wallet, most recent first (paginated, 50 per page; filter by `asset`, `journal_kind`, and date range):

```bash
curl -sS "$WALLET_HOST/organizations/$TENANT/wallets/$VENDOR_03_ID/entries?asset=USD" \
  -H "X-API-KEY: $API_KEY"
```

Each entry includes `lineageRef` — the source IDs that funded that specific movement — letting you trace any debit backwards to prove where every dollar came from.

Fetch a hold with its capture history:

```bash
curl -sS "$WALLET_HOST/organizations/$TENANT/holds/$HOLD_ID" \
  -H "X-API-KEY: $API_KEY"
```

> There is no list endpoint for holds — store hold IDs (and their expirations) in your own system as you create them.

See the [API Reference](api-reference.md) for the full endpoint table, error codes, and idempotency details.
