Wallet & Deposits

Read the prepaid balances and the wallet statement, fund the wallet with stablecoins through your own deposit addresses, and audit the deposit history.

Your workspace wallet is the prepaid balance every order spends from — one wallet per currency. This page covers reading balances, the wallet statement, funding with stablecoins, and auditing the deposit history. Reads require wallet.read; requesting a deposit address requires the dedicated wallet.deposit-address.write scope.

Read a balance

GET /api/v1/wallet/balance?currency=USD
{
  "availableBalance": 425.00,
  "reservedBalance": 75.00,
  "currency": "USD",
  "asOfUtc": "2026-09-05T12:00:00+00:00"
}
  • availableBalance — spendable right now: new orders and withdrawals draw from this.
  • reservedBalance — set aside: the totals of orders still being fulfilled (captured on fulfillment, released if they fail) and the amounts of withdrawals requested but not yet paid or cancelled.

currency is required: a three-letter currency code (any case). A malformed or unsupported code is 400 invalid_request; a currency in which the workspace holds no active wallet — none at all, or one that is frozen or closed — is 404 not_found.

Alert your operations well before available funds reach your hourly burn rate — an order admitted without sufficient funds is rejected, not queued.

Read every wallet

GET /api/v1/wallet/balances

Every wallet of the workspace, in currency order — a frozen or closed one too, saying which — with the reserved balance split by what it is held for:

{
  "items": [
    {
      "currency": "USD",
      "availableBalance": 425.00,
      "reservedBalance": 75.00,
      "ordersReserved": 52.50,
      "withdrawalsHeld": 22.50,
      "status": "active",
      "asOfUtc": "2026-09-05T12:00:00+00:00"
    }
  ]
}

status is active, frozen (nothing can be ordered or withdrawn from it until Xegora releases it) or closed. ordersReserved and withdrawalsHeld add up to reservedBalance; when they did not add up exactly at the moment of the read (a change was being made), both are null rather than guessed — read again.

The wallet statement

GET /api/v1/wallet/movements?currency=USD&fromUtc=2026-09-01T00:00:00Z&toUtc=2026-10-01T00:00:00Z

Every movement of the workspace's wallets, newest first, each with the balance it left behind and what it was about — the same statement the dashboard shows — and, per currency, the window's opening and closing balance with its totals.

ParameterMeaning
currencyA wallet currency to read (three letters, any case). Repeatable, at most ten; none reads every wallet.
typeA movement code (below) to narrow the lines to. Repeatable; none shows every movement.
fromUtc / toUtcThe window: fromUtc inclusive, toUtc exclusive. Leave toUtc out to keep the window open up to now; fromUtc defaults to 30 days before the window's end. The window must end after it starts and span at most 366 days.
cursorThe next value of the previous page, to read the next (older) page.
limit1–200 lines a page; default 50. A ceiling, not a promise — see Paging below.

Any value the statement cannot read — an unknown code (including other), a malformed currency or more than ten of them, a cursor no page returned, a window that is reversed or too long, a limit out of range — is 400 invalid_request.

Paging: follow next, never count the lines

Walk the statement until next is absent (null). A page shorter than limit is not the end of the statement.

limit is a ceiling, not a promise. Every line carries the balance it left behind, and a balance is only exact if every movement between two shown lines is counted — so when you narrow the lines with type, the statement walks the hidden movements in between as well, and it walks at most 10,000 of the workspace's movements for one page. When the lines you asked for lie further apart than that, the page ends early at the last line within reach and next carries on from exactly there. A page can therefore come back with a handful of lines, or even one, while next is still set.

The figures are never approximate: balanceAfter, reservedAfter and availableAfter are exact on every line a short page returns, and totalCount still counts every movement matching the filters in the whole window — compare your line count against totalCount rather than against limit. A page without a type filter shows nothing in between, so it fills to limit as long as movements remain.

{
  "items": [
    {
      "id": "0198e001-7a1b-7c2d-8e3f-4a5b6c7d8e9f",
      "occurredAtUtc": "2026-09-05T12:01:09+00:00",
      "type": "order_charge",
      "entry": "debit",
      "balanceDelta": -52.50,
      "reservedDelta": -52.50,
      "currency": "USD",
      "balanceAfter": 447.50,
      "reservedAfter": 0.00,
      "availableAfter": 447.50,
      "order": {
        "id": "0198e000-1111-7abc-9def-222233334444",
        "publicReference": "ord_0198e00011117abc9def222233334444",
        "clientReference": "your-order-1001"
      },
      "withdrawal": null,
      "deposit": null,
      "invoice": null
    },
    {
      "id": "0198e000-1a2b-7c3d-8e4f-5a6b7c8d9e0f",
      "occurredAtUtc": "2026-09-05T12:01:02+00:00",
      "type": "order_hold",
      "entry": "hold",
      "balanceDelta": 0.00,
      "reservedDelta": 52.50,
      "currency": "USD",
      "balanceAfter": 500.00,
      "reservedAfter": 52.50,
      "availableAfter": 447.50,
      "order": {
        "id": "0198e000-1111-7abc-9def-222233334444",
        "publicReference": "ord_0198e00011117abc9def222233334444",
        "clientReference": "your-order-1001"
      },
      "withdrawal": null,
      "deposit": null,
      "invoice": null
    }
  ],
  "next": "AAZHMdnm6MABmOAAERF6vJ3vIiIzM0RE",
  "totalCount": 37,
  "fromUtc": "2026-09-01T00:00:00+00:00",
  "toUtc": "2026-10-01T00:00:00+00:00",
  "summaries": [
    {
      "currency": "USD",
      "openingBalance": 0.00,
      "closingBalance": 447.50,
      "credits": 1000.00,
      "debits": 552.50,
      "creditCount": 2,
      "debitCount": 8,
      "movementCount": 37
    }
  ]
}

Each line:

FieldMeaning
typeA stable movement code (below).
entrycredit (the balance went up), debit (it went down), hold (part of it was set aside) or release (a hold was lifted).
balanceDelta, reservedDeltaThe signed change to the balance and to its reserved part. A hold or a release moves only the reserved part.
balanceAfter, reservedAfter, availableAfterThe wallet after the movement: its balance, the reserved part, and what was available (balanceAfter − reservedAfter). The newest line's balanceAfter is the balance now.
order, withdrawal, deposit, invoiceWhat the movement was about, when it was about one: the order (id, publicReference, clientReference), the withdrawal (id, publicReference), the deposit (id, network, currency, transactionHash), or the invoice the wallet paid (number, kind: setup or recurring). The others are null.

The movement codes:

typeEntryWhat moved the money
deposit_creditcreditA stablecoin deposit to one of your addresses was credited.
payment_creditcreditXegora recorded a payment it received for your workspace.
order_holdholdAn order's total was reserved.
order_chargedebitA delivered order's reserved total was captured.
order_releasereleaseAn order's reservation was released: it was not delivered, or it was refunded before delivery.
order_refundcreditA delivered order was refunded to the wallet.
withdrawal_holdholdA requested withdrawal's amount was set aside.
withdrawal_payoutdebitA withdrawal was paid out.
withdrawal_releasereleaseA withdrawal was cancelled or declined; its amount is available again.
setup_feedebitThe plan's setup invoice was paid from the wallet.
recurring_feedebitA subscription invoice was paid from the wallet.
adjustment_creditcreditXegora credited the wallet to put something right (a goodwill or correcting credit two of its operators approved).
adjustment_debitdebitXegora debited the wallet to correct it.
cashback_creditcreditYour share of the cashback a fulfilled order earned.
cashback_reversaldebitThat share taken back out of the order's refund, at the same instant as the order_refund credit — the refund undid the sale that earned it.

A code never changes meaning, and a new kind of movement gets a new code; a movement without a published code reads other. Keep clients tolerant of codes you do not know.

The page's totalCount counts the movements matching the filters in the whole window; next is null on the last page — and only there, so keep following it even when a page came back short (above). Each summary covers one wallet over the window: openingBalance and closingBalance (at the window's end — now, for an open window), and the credits and debits (as positive amounts) with their counts, of the movements the filters match. Balances always count every movement, so with no type filter closingBalance = openingBalance + credits − debits; with one, the totals cover only the matching lines.

Fund with stablecoins

Your workspace gets its own permanent deposit address per network and stablecoin. Anything that arrives at an address, on its network, in its stablecoin, is credited to your wallet automatically once it is confirmed — no deposit "intents", no amounts to pre-declare.

See what can be deposited

GET /api/v1/wallet/deposit-options     (scope: wallet.read)
[
  {
    "network": "<network code>",
    "networkName": "<network name>",
    "tokenStandard": "<token standard>",
    "currency": "<stablecoin>",
    "decimals": 6,
    "confirmations": 20,
    "minimumDeposit": 1.00,
    "feePercent": 2.0,
    "ledgerCurrency": "USD"
  }
]

The networks and stablecoins are whatever this endpoint returns — read them from it rather than hard-coding any. Only the options offered right now are listed; one may disappear while its network is under maintenance and come back later. Label from the response, key on the codes: networkName and tokenStandard are the names to show your team; network and currency are the stable identifiers to match on. Each option carries its own confirmations (how deep a transfer must be buried before it is recorded), minimumDeposit, and feePercent.

Request (or fetch) an address

PUT /api/v1/wallet/deposit-addresses     (scope: wallet.deposit-address.write)
GET /api/v1/wallet/deposit-addresses     (scope: wallet.read)
{ "network": "<network code>", "currency": "<stablecoin>" }

Send a network and currency exactly as an option names them (each at most 16 characters). PUT is idempotent and immediate: it returns 200 OK with the address, and every later call for the same network and stablecoin returns the same one. GET lists every address the workspace has been issued.

{
  "id": "0198db4d-f20c-765e-a89a-2b1b0b9a4f74",
  "option": {
    "network": "<network code>",
    "networkName": "<network name>",
    "tokenStandard": "<token standard>",
    "currency": "<stablecoin>",
    "decimals": 6,
    "confirmations": 20,
    "minimumDeposit": 1.00,
    "feePercent": 2.0,
    "ledgerCurrency": "USD"
  },
  "address": "<address on that network>",
  "createdAtUtc": "2026-09-05T12:00:00+00:00",
  "lastDepositAtUtc": null
}
  • Send only the stablecoin on the network of that address. Another token, or the same token on another network, sent to it cannot be credited.
  • address is exactly what to send to, in the form its network uses (checksummed hex on EVM networks, base58 on TRON).
  • The address is permanent and reusable — print it into your treasury runbook once; deposits any time simply appear.
  • 422 with code deposit_asset_not_offered means the option is not offered right now; 422 deposit_account_unavailable that an address cannot be issued for the workspace right now (it holds no active wallet in the ledger currency, for example); 503 with deposits_unavailable (and a Retry-After) that deposits are paused altogether.

The deposit fee

The deposit contract keeps the option's feePercent of every deposit; your wallet is credited the rest, in ledgerCurrency, one stablecoin unit to one currency unit. To know what to send so that an exact amount is credited:

GET /api/v1/wallet/deposit-quote?network=<network code>&currency=<stablecoin>&amount=100     (scope: wallet.read)
{
  "option": { "network": "<network code>", "currency": "<stablecoin>", "feePercent": 2.0, "...": "..." },
  "credit": 100.00,
  "sendAmount": 102.040816,
  "feeAmount": 2.040816
}

amount is the credit you want, in whole cents of the ledger currency: a value that is not positive is 400 invalid_request, one with more than two decimals 422 deposit_amount_invalid.

Credits are made in whole cents. What is left over below a cent after the fee is carried on the address and added to its next deposit, so nothing is lost; a deposit worth less than a cent on its own is shown as carried and is credited with the next one.

How crediting works

  1. Your transfer is recorded once it is the option's confirmations blocks deep (status: detected).
  2. It is proved against the chain once more and credited to your wallet (credited); a deposit_credit line appears on the statement and a wallet.credited webhook fires with source: "deposit" and the new available balance.
  3. A deposit that cannot be credited automatically is held for review by our operators; contact support with its id and transactionHash.

Audit the deposit history

GET /api/v1/wallet/deposits?limit=50
GET /api/v1/wallet/deposits?status=credited&detectedFrom=2026-09-01T00:00:00Z&detectedTo=2026-10-01T00:00:00Z
GET /api/v1/wallet/deposits/{depositId}

Keyset-paginated, newest first. Filters, all optional:

ParameterMeaning
statusdetected, credited, carried or held.
networkA network code, as the deposit options name it.
currencyA stablecoin code, as the deposit options name it.
detectedFrom / detectedToA window on when the deposit was recorded: from inclusive, to exclusive; it must start before it ends.
beforeDetectedAtUtc + beforeIdThe cursor: the previous page's nextDetectedAtUtc and nextId, together (both or neither), passed back exactly as returned.
limit1–100; default 50.

An unknown status, network or stablecoin, a reversed window, half a cursor, or a value over 16 characters is 400 invalid_request.

{
  "items": [
    {
      "id": "0198db4d-f2d9-7f8d-867d-329b081134a3",
      "network": "<network code>",
      "currency": "<stablecoin>",
      "transactionHash": "<transaction hash>",
      "explorerUrl": "<link to the transaction on a public block explorer>",
      "grossAmount": 102.040816,
      "feeAmount": 2.040816,
      "netAmount": 100.000000,
      "creditedAmount": 100.00,
      "ledgerCurrency": "USD",
      "status": "credited",
      "detectedAtUtc": "2026-09-05T12:00:00+00:00",
      "creditedAtUtc": "2026-09-05T12:00:20+00:00",
      "networkName": "<network name>",
      "address": "<your address the transfer was sent to>",
      "blockNumber": 48123456,
      "requiredConfirmations": 20
    }
  ],
  "nextDetectedAtUtc": null,
  "nextId": null,
  "totalCount": 1
}
FieldMeaning
grossAmount, feeAmount, netAmountWhat arrived, the fee the contract kept, and the rest, in the stablecoin.
creditedAmountWhat reached the wallet, in ledgerCurrency, in whole cents including any remainder carried from earlier deposits; 0 for a carried deposit, null until a deposit is credited.
transactionHashThe transfer's hash in the form its network's explorers use: 0x-prefixed hex on EVM networks, plain hex on TRON.
explorerUrlA link to the transfer on a public block explorer, when one is known for the network.
addressYour deposit address the transfer was sent to.
blockNumberThe block the transfer is in.
requiredConfirmationsThe confirmations Xegora waits for on that network before it records a transfer — a listed deposit has at least this many; null when Xegora no longer supports the network.
totalCountHow many deposits match the filters, across every page.

GET /api/v1/wallet/deposits/{depositId} returns one deposit in the same shape; another workspace's deposit, or one that does not exist, is 404 not_found.

Treasury reconciliation loop

A robust daily loop:

  1. Read GET /wallet/movements for the day, per currency; its summary's openingBalance should equal your books' closing balance of the day before, and every line names the order, withdrawal, deposit or invoice behind it.
  2. Walk GET /wallet/deposits (with detectedFrom) back to your last stored deposit; match each row to your outgoing transfers by transactionHash.
  3. Compare GET /wallet/balances with your ledger.
  4. Raise any deposit still detected long after its confirmation window, or held, with support, quoting the deposit id and transactionHash.

Did this page help you?