Custodian API Overview
The Xellar Custodian API lets you create and manage custodial wallets, accept crypto deposits via invoices, send withdrawals, track off-chain balances and transaction history, and receive real-time events through outbound webhooks.
What You Can Do
- Account & Wallets — Create custodial accounts and read their wallet addresses per network.
- Listen Wallet — Subscribe on-chain addresses so incoming deposits are detected.
- Invoice — Generate a payment request (a deposit address + amount) and track its status.
- Deposits — List combined incoming activity (invoices + non-invoice on-chain deposits).
- Withdraw — Estimate fees and send funds to an external address.
- Assets & Balances — Public token catalog, off-chain balances, ledger history, convert (per-app), and transfer between apps.
- Custom transactions — Submit signed EVM contract calls from a custodial wallet.
- KYC submissions — Create and submit end-user KYC packages (when enabled for your integration).
- Webhooks — Configure your HTTPS endpoint and inspect delivery attempts.
Understanding Balances
Xellar tracks money in two ways. You only interact with off-chain balance through the API — but it helps to know both exist.
On-chain balance
Think of this as the real coins sitting inside a wallet address on the blockchain.
When someone sends crypto to a deposit address, the tokens land here first. Xellar reads this from the blockchain and keeps it updated behind the scenes. You do not query on-chain balance through the Custodian API — it is used internally to detect deposits and move funds.
Off-chain balance
Think of this as your app's account book at Xellar — a running total of how much you own, per token.
This is what you see in Assets, what withdrawals spend from, and what deposit webhooks update when a payment is credited. It is fast, consistent, and what you should use for your product logic.
How that ledger is keyed depends on your app's balance type (set when the app is created; it cannot be changed later):
| Balance type | Ledger | Withdraw |
|---|---|---|
per_app (default) | One off-chain balance per token for the whole app | Do not send walletId |
per_wallet | One off-chain balance per token and deposit wallet | You must pass walletId so the correct wallet's balance is deducted |
How they connect (simple flow)
- Deposit arrives — crypto lands on-chain at a wallet address.
- Xellar detects it — as soon as the on-chain transfer is matched, you get
deposit.invoice.pending_confirmationordeposit.wallet.pending_confirmation(confirmationStatus: "pending", not credited yet). - Xellar waits for block confirmations — after the network's confirmation threshold, the invoice is marked paid (if matched) and the ledger is credited.
- Your balance is credited —
deposit.invoice.paidordeposit.wallet.credited. Treat these as final for product logic. - You withdraw — the request deducts from off-chain balance; Xellar sends the tokens on-chain to the recipient.
Rule of thumb: If an API response includes
pendingBalance,activeBalance,withholdBalance, orlatestBalance, that is off-chain. On-chain amounts only appear inside webhooktransactionobjects as the raw blockchain transfer that triggered an event.
Signed API routes (/api/v1)
All routes below require authentication (X-App-ID, X-Timestamp, X-Signature) unless noted as public.
| Area | Method | Path | Doc |
|---|---|---|---|
| Account | POST | /account/create | Account |
| Account | GET | /account/:subID | Account |
| Account | GET | /account/:subID/wallet/:walletID | Account |
| Account | GET | /account/:subID/network/:network | Account |
| Listen | GET | /wallets/listen | Listen wallet |
| Listen | POST | /wallets/listen/:address | Listen wallet |
| Listen | PATCH | /wallets/listen/:address | Listen wallet |
| Listen | DELETE | /wallets/listen/:address | Listen wallet |
| Listen | GET | /wallets/to-listen | Listen wallet public |
| Listen | GET | /wallets/listen/:address/status | Listen wallet public |
| Invoice | POST | /invoices | Invoice |
| Invoice | GET | /invoices | Invoice |
| Invoice | GET | /invoices/:id | Invoice |
| Invoice | POST | /invoices/:id/cancel | Invoice |
| Deposits | GET | /deposits | Deposits |
| Withdraw | POST | /withdraws/estimate | Withdraw |
| Withdraw | POST | /withdraws | Withdraw |
| Withdraw | GET | /withdraws | Withdraw |
| Withdraw | GET | /withdraws/:id | Withdraw |
| Custom tx | POST | /transactions | Custom transactions |
| Custom tx | GET | /transactions/:id | Custom transactions |
| Assets | GET | /tokens | Assets public |
| Assets | GET | /assets | Assets |
| Assets | GET | /assets/:tokenCode | Assets |
| Assets | GET | /transaction-histories | Assets |
| Assets | POST | /balances/convert/estimate | Assets |
| Assets | POST | /balances/convert | Assets |
| Assets | POST | /balances/transfer | Assets |
| Webhook | GET | /webhooks/settings | Webhook |
| Webhook | PUT | /webhooks/settings | Webhook |
| Webhook | DELETE | /webhooks/settings | Webhook |
| Webhook | POST | /webhooks/test | Webhook |
| Webhook | GET | /webhooks/deliveries | Webhook |
| KYC | POST | /kyc/submissions | KYC |
| KYC | GET | /kyc/submissions | KYC |
| KYC | GET | /kyc/submissions/:id | KYC |
| KYC | PATCH | /kyc/submissions/:id | KYC |
| KYC | POST | /kyc/submissions/:id/documents | KYC |
| KYC | POST | /kyc/submissions/:id/submit | KYC |
Base URL
All client endpoints are served under the /api/v1 prefix.
| Environment | Base URL |
|---|---|
| Development | https://custodian-api-dev.xellar.co/api/v1 |
| Production | https://custodian-api.xellar.co/api/v1 |
Authentication
Every client endpoint (except a few public reads) is protected by an ED25519 request signature. You authenticate using an App ID and a private key that you generate from the Xellar Panel (opens in a new tab).
Public (no signature): list addresses to listen, listen status, and list allowed tokens.
See Authentication to get your key pair and learn how to sign requests.
Getting Started
- Get your App ID and private key from the Xellar Panel (opens in a new tab).
- Create an account to provision custodial wallets.
- Create an invoice or subscribe an address to receive deposits.
- Configure a webhook to get real-time updates.
Need help? Email support@xellar.co or Telegram @xellarsupport.