Use CasesTreasury & Self-Custody

Treasury and self-custody

Onboard your own entity, receive into your own accounts, and hold the result in wallets only your Recovery Key controls.

You are your own customer. This is the case where the custody model does the most work, because the funds being held are yours.

The shape

Build order

StepCallNotes
1. Onboard your entityPOST /api/customers with kind: "business"Your operating company, verified through KYB like any other business customer
2. Register your keysPOST /dashboard/partner/wallet_keysPublic halves only, once, and never a private key
3. ActivatePOST /dashboard/partner/wallet_keys/activation then .../authorizeSigned by the cold Recovery Key. Happens once, ever
4. Create walletsPOST /api/customers/{id}/walletsOne per chain, or several per chain if you want separated balances
5. ReceivePOST /api/customers/{id}/virtual_accountsDestination is a wallet you hold, or an address you already control
6. MovePOST /api/wallets/{id}/operations, then authorizeVerified and signed in your KMS

Read the custody model before you generate a key

Wallet addresses derive from your Recovery Key. It is your permanent identity, it cannot be rotated, and losing it means no new signing key can ever be installed.

KeyWhere it livesWhat it does
Recovery KeyCold, offlineIs your identity. Every address derives from it. Installs or replaces the signing key
Primary Signing KeyHot, KMS or HSMAuthorizes sends. Rotate it freely, addresses never change

Generate the Recovery Key offline, in the device it will live in, and back it up like a root of trust. Read Custody Architecture first, and treat that generation as a change-controlled event with more than one person present.

What the model actually guarantees

If our API, our database, our infrastructure keys, or any third party we rely on were fully compromised, an attacker still could not move a token out of one of these wallets. Moving funds requires a fresh signature from your Primary Signing Key, over bytes your own verifier has already rebuilt and checked.

That is worth verifying rather than believing. The threat model table states what each compromise scenario can and cannot do, and every claim in it is checkable against a public chain or by code you run.

Separating balances

Each POST /api/customers/{id}/wallets call mints a new wallet with a new address, including on a chain you already have one on. Use that to separate concerns rather than tracking sub-balances yourself:

  • an operating wallet that funds day-to-day payouts,
  • a reserve wallet nothing automated can reach,
  • a per-counterparty wallet, so an address identifies who paid.

partner_reference_id is your handle on each one, and list endpoints filter by it. name is a display label and is deliberately not unique.

Operational discipline

  • Alert on every verifier refusal. A signing service that refuses is doing its job, and it is the highest-signal alert you have: something did not match.
  • Watch wallet.deposit_received. Funds arriving at a treasury address from an unexpected source is exactly the thing you want to know about within seconds.
  • Use read_only keys for dashboards, reporting jobs, and anything that reads balances. A read-only key cannot create an operation.
  • Reconcile from the chain. GET /api/wallets/total_balances and GET /api/wallets/{id}/history are chain reads, so they are the same numbers an explorer shows.
  • Rehearse a Recovery Key ceremony in sandbox before you need one in anger. Rotating the signing key is the drill worth having run.