Skip to main content

Overview

A Crypto Wallet is the customer-facing resource for holding crypto on a single blockchain. Each wallet has one on-chain address on one chain, and its balances[] reflect the deposits and pending movements Conduit has observed for that address. Wallets are scoped to a customer. No wallets are created automatically during onboarding — you create each one on demand, on the chain you need. A customer can hold multiple wallets across different chains. The crypto-wallets feature must be enabled for your client. Calls to these endpoints while the feature is disabled return a feature-not-enabled error.

Custody Model

Every wallet on this surface is non-custodial: the customer holds the keys (passkey or roster of signers) and must sign every outbound transfer. Conduit does not hold customer signing keys.
Who controls the keyHow funds are moved
Customer (passkey or signer roster)Conduit and the customer’s signers co-sign; Conduit broadcasts once the signing threshold is met
A customer must claim non-custodial control before any wallet address can be issued. POST /v2/customers/:id/wallets returns 409 WALLET_CUSTODY_NOT_CLAIMED until that’s done. Receiving crypto works once a wallet exists; the custody model determines what happens on outbound — see Non-Custodial Wallets for the full co-signing flow.

The Wallet Resource

FieldTypeDescription
idstringWallet ID, prefixed wlt_.
chainenumThe blockchain this wallet operates on.
addressstring | nullThe on-chain address. null while the wallet is provisioning.
statusenumLifecycle status — see below.
custodyModelenum | nullnon_custodial for wallets on the current surface. The wire still accepts custodial for legacy ops-managed wallets, but the public customer surface only mints non_custodial. Omitted until the customer’s custody model is determined.
rotatedAtstring | nullWhen this wallet was rotated, if it has been.
replacedByWalletIdstring | nullThe wallet that replaced this one after rotation.
clientReferenceIdstring | nullYour external reference, if you supplied one at creation.
balances[]arrayPer-asset balances, each with available, pending, and frozen amounts.
createdAtstringWhen the wallet was created.
updatedAtstringWhen the wallet was last updated.

Balances

Each entry in balances[] splits a single asset into three buckets:
  • available — settled funds you can move out.
  • pending — funds observed on-chain but not yet fully settled.
  • frozen — funds held and temporarily unavailable.
Balances reflect deposits as they arrive. See Receiving crypto below.

Status lifecycle

StatusMeaning
pendingThe wallet has been requested and Conduit is provisioning its on-chain address. address is null until provisioning completes.
activeThe wallet has an address and can receive and send funds.
disabledThe wallet is no longer in use — for example, it has been rotated and replaced.
A wallet enters pending with a null address while it is being provisioned. Rather than polling, subscribe to crypto_wallet.completed to learn when provisioning has finished and the address is populated.

Supported Chains

Wallets can be created on the following chains. The chain value is always lowercase.
chainNetwork
ethereumEthereum
baseBase
polygonPolygon
solanaSolana
tronTron

Creating Wallets

Wallets are provisioned in two steps: claim non-custodial control once per customer, then create one wallet per chain.
1

Claim non-custodial control (once per customer)

Opt the customer into the non-custodial multi-signer model:
POST /v2/customers/{customerId}/wallets/claim-non-custodial
Returns 202. The customer’s signers complete their enrollment via per-signer verification URLs delivered through wallet_signer.invited webhooks. Once the final signer has enrolled, crypto_wallet.completed fires; from that point the customer can create wallets.
2

Create a wallet per chain

Once the customer has claimed non-custodial control, create wallets one chain at a time:
POST /v2/customers/{customerId}/wallets
idempotency-key: <unique-key>

{ "chain": "base", "clientReferenceId": "ext-wallet-001" }
Returns 201 with the new wallet. clientReferenceId is optional. The idempotency-key header is required — replaying the same key returns the same wallet rather than creating a duplicate. The wallet starts in pending until its address is provisioned.Before the claim completes, the same request returns 409 WALLET_CUSTODY_NOT_CLAIMED. See Non-Custodial Wallets for the multi-signer model and the WALLET_CUSTODY_NOT_CLAIMED error page for the resolution path.

Reading Wallets

EndpointReturns
GET /v2/customers/{customerId}/walletsA cursor-paginated list of the customer’s wallets. Accepts an optional clientReferenceId filter.
GET /v2/customers/{customerId}/wallets/{walletId}A single wallet.

Key Rotation

Rotating a wallet replaces its on-chain key. It produces a new wallet with a new address; the old wallet moves to disabled. The two are linked: the old wallet’s replacedByWalletId points to the new wallet, and the new wallet carries the same replacedByWalletId back-reference so the chain of replacements is traceable.
POST /v2/customers/{customerId}/wallets/{walletId}/rotate
idempotency-key: <unique-key>
Returns 200 with the replacement wallet. The idempotency-key header is required.
Rotation requires the wallet to have a zero balance. Move all funds out before rotating — rotation is blocked while any balance remains, because the new key controls a different address.
A wallet.rotated webhook fires when rotation completes, carrying both the old walletId and the replacedByWalletId.

Receiving Crypto

Share the wallet’s address and incoming deposits surface in the wallet’s balances[]. The end-to-end flow — including how deposits are detected and credited — is covered in the Receive Crypto guide.

Non-Custodial Wallets

The two-signature model, the customer verify page, and outbound co-signing.

Receive Crypto

How deposits arrive and credit a wallet’s balances.