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 during onboarding — they are provisioned when the customer claims non-custodial control (see Creating Wallets), which by default provisions a wallet on every supported chain in one step. 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 by default: the customer holds the keys (passkey or roster of signers) and must sign every outbound transfer. Conduit does not hold customer signing keys. On the non-custodial path, a customer must claim non-custodial control before any wallet address can be issued. POST /v2/customers/:id/wallets returns 422 WALLET_NO_PROVIDER_ACCOUNT until that’s done. Where the custodial path is enabled for your account, that same call instead mints a custodial wallet directly. 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. Custodial wallets remain available where Conduit has the necessary licences in your jurisdiction; contact your Conduit representative to enable the custodial path.

Signing modes

Signers don’t have to be humans. Every customer has a signing mode — passkey required, programmatic, or programmatic unattended — that governs whether roster seats are held by human passkey holders, server-held API keys, or a mix. Conduit configures it out of band as an organization-wide default with per-customer overrides (the customer-level setting wins); there is no API to set it, so arrange it with your Conduit representative. See Non-Custodial Wallets for the mode-by-mode breakdown and Programmatic payout signing for the machine flow.

The Wallet Resource

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

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. The three EVM chains — ethereum, base, and polygon — share a single on-chain address. A customer’s wallets on those chains all resolve to the same address, so funding one and reading another are the same account on each network. solana and tron each have their own distinct address.
solana wallets are address-only for now: you can create the wallet and receive on it, but outbound payouts and orders on Solana are not yet available. Payouts and orders are supported on the EVM chains and tron (tron carries USDT only). An order naming an unsupported asset/chain combination is refused with UNSUPPORTED_ASSET; a payout is refused as a validation error on assetAmount.chain.

Creating Wallets

Wallets are provisioned by claiming non-custodial control once per customer, which by default provisions a wallet on every supported chain. Adding a wallet on a chain you excluded from the claim is an optional second step.
1

Claim non-custodial control (once per customer)

Opt the customer into the non-custodial multi-signer model:
The request body may include an optional chains array naming which chains to provision. Omit it — the recommended default — and every supported chain is provisioned in one claim, so a customer that later needs a new chain does not have to re-authenticate its signers. Provisioning one wallet up front on each chain covers future use with no further signer ceremony.Because the three EVM chains share a single address and key, provisioning them costs one admin approval, not three. solana and tron are provisioned as their own addresses in the same claim.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 and the claim’s wallets activate. Polling GET /v2/customers/{customerId}/wallets/claims/{claimId} returns a chains field listing every chain provisioned for the claim.
2

Add a wallet on another chain (optional)

When you omit chains at claim time, wallets on every supported chain already exist and this step is unnecessary. To add a wallet on a chain you explicitly excluded, call:
clientReferenceId is optional — 1-255 characters from A-Za-z, 0-9, underscore, hyphen, colon, and period; no spaces. The idempotency-key header is required — replaying the same key returns the same result rather than creating a duplicate.The response has two shapes, depending on whether the new wallet needs fresh signing material:
  • 201 Created with the wallet — when the chain reuses key material the customer already controls. Adding an EVM chain (ethereum, base, or polygon) while the customer already has an EVM wallet reuses the existing shared address and key, so no admin approval is needed and the wallet is returned immediately, already active on the shared address.
  • 202 Accepted with { "ceremonyId": "wcm_…", "verificationUrl": "…" } — when the wallet needs new signing material (a chain that does not share the existing key, or a second wallet on a chain). This parks an admin-cosign ceremony rather than creating the wallet inline: route verificationUrl to one of the customer’s admins to approve on the verify page. A wallet_ceremony.awaiting_admin_approval webhook carries the same admin link. On approval, wallet.created and crypto_wallet.completed fire and the wallet is active; if the admin declines, wallet_ceremony.failed fires and no wallet is created. Retrying while a ceremony for the same chain is already pending is idempotent: the call re-mints that pending ceremony’s approval and returns 202 again (or 409 CEREMONY_IN_FLIGHT if a concurrent request for the same chain has not finished recording its ceremony). Wait for the pending ceremony to resolve rather than opening a second one.
Before the customer has claimed non-custodial control, the same request returns 422 WALLET_NO_PROVIDER_ACCOUNT. See Non-Custodial Wallets for the multi-signer model and the WALLET_NO_PROVIDER_ACCOUNT error page for the resolution path.

Reading Wallets

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.
Returns 200 with the replacement wallet. The idempotency-key header is required.
Move the funds out before rotating — the new key controls a different address, so rotation is blocked while the wallet still holds a balance worth moving. A leftover at or below the asset’s dust floor does not block it.
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.

Add a Crypto Wallet

Step-by-step: enable the feature, claim non-custodial control, enroll the roster, and activate.

Programmatic payout signing

Approve payouts server-to-server with an API-key signer instead of a passkey.