active wallets ready to receive and send. For the concepts behind each step see Crypto Wallets, Non-Custodial Wallets, and Multi-signer wallets. To move funds afterward, see Receive Crypto and the Non-Custodial Payout Lifecycle.
The customer must already be onboarded and active. You get customerId from the application.approved webhook; see Onboard a Customer. Calling these endpoints before the customer is active returns CUSTOMER_NOT_ONBOARDED.
Test this flow in sandbox. Drive it end-to-end with simulated money and deterministic controls: start with the sandbox quickstart, then the multi-signer recipes for roster and signing scenarios, and the cheat sheet for every magic value and simulate endpoint.
Flow
- Know the customer’s signing mode: it is arranged with Conduit, and it dictates the roster shapes Step 2 will accept.
- Request the
crypto_walletfeature; wait forapplication.approved(applicationType: "crypto_wallet"). - Claim non-custodial control with a signer roster and threshold. The roster’s shape (passkey members, machine (
api_key) members, or a mix) is set by the customer’s signing mode (Step 0). - Passkey members enroll via their invitation link (delivered on
wallet_signer.invited); machine members are active immediately, and an all-machine roster skips this step. - Wait for
crypto_wallet.completed: the wallets are nowactive.
crypto_wallet feature only makes the customer eligible to claim.
Step 0: Know the customer’s signing mode
Every customer has a signing mode that dictates which roster shapes a claim accepts and how the wallets activate. Conduit sets it for each customer; to confirm or change it, ask your Conduit representative. Programmatic unattended additionally requires an approval review by Conduit. For choosing between the modes, and what each one commits you to, see Signing modes.
These rules are enforced at claim time and again on every later signer add. A roster that breaks the mode’s shape (an
api_key member under passkey-required, or an api_key admin under programmatic) returns 422 SIGNING_MODE_ROSTER_INVALID; a programmatic roster whose machine keys cannot cover the threshold (including zero machine keys) returns 422 PROGRAMMATIC_QUORUM_UNREACHABLE.
Step 1: Request the crypto-wallet feature
Discover any extra requirements, then submit the feature application.Idempotency-Key is required; without it the call returns IDEMPOTENCY_KEY_REQUIRED.
application.approved / application.rejected (applicationType: "crypto_wallet"). A rejection carries resubmittable: when it is true, correct the data and request the feature again; when it is false, the decision is final. Customers in restricted jurisdictions are rejected up front with CRYPTO_NOT_AVAILABLE_IN_JURISDICTION; calling the next step before the feature is approved returns CRYPTO_FEATURE_NOT_APPROVED.
Step 2: Claim non-custodial control
One call mints the customer’s signing setup and provisions the initial wallets. The roster needs at least two admins;signingThreshold sets how many stamps each payout needs. chains is optional: omit it to provision a wallet on the default set of supported chains in one claim (recommended), or pass an explicit list to choose the chains (for example ["solana"], which is not in the default set). Pick the roster shape that matches the customer’s signing mode (Step 0). A machine (api_key) member carries a publicKey: a compressed P-256 public key you generate and hold, 33 bytes hex-encoded (66 hex chars, 02/03 prefix; optional 0x). Conduit only ever receives the public half; no field anywhere carries a private key. Missing key → 400 API_KEY_PUBLIC_KEY_REQUIRED; malformed → 400 API_KEY_PUBLIC_KEY_INVALID; two members sharing one → 422 API_KEY_PUBLIC_KEY_DUPLICATE.
- Passkey roster
- Hybrid (programmatic)
- Machine-only (unattended)
202 Accepted with a claimId. The claimId is a correlation receipt, not a status handle. Don’t poll it; wait for the webhooks. See Multi-signer wallets for roster rules (admin vs signer, thresholds, root quorum) and Crypto Wallets for the shared EVM address and optional chains.
Step 3: Enroll the passkey members
This step applies to passkey members only. Machine (api_key) members seat active at claim: no invite webhook, no URL, no enrollment (passkeyCount stays 0). An all-machine roster skips this step entirely: claim.completed is your activation signal, with no signer action in between.
For passkey members: Conduit never contacts signers directly. Each one gets a wallet_signer.invited webhook carrying their own verificationUrl and expiresAt; forward each URL to the intended signer. The signer opens it and registers their passkey on-device. A plain signer enrolls one passkey; an admin enrolls two (a backup device).
wallet_signer.enrolled on their qualifying stamp. See Non-Custodial Wallets for the hosted verify page. In sandbox, POST /v2/sandbox/wallet-signers/:signerId/mark-enrolled collapses a passkey member’s enrollment headlessly (machine members never need it).
Step 4: Wait for activation
Once every passkey member has enrolled, the wallets activate. Listen forclaim.completed: it carries the claimId from Step 2 plus the activated walletIds, so you can close the loop on the claim without polling. A customer-level crypto_wallet.completed also fires, carrying customerId only (no wallet IDs). Either is your signal the customer can receive deposits and originate payouts.
status: "active" with an address. The three EVM chains (ethereum, base, polygon) share one address; non-EVM chains like tron each have their own. GET /wallets hides wallets until they activate, so this list is empty between the claim and crypto_wallet.completed.
What’s next
- Receive crypto: share a wallet’s
address; see Receive Crypto. - Send crypto: every payout collects the roster’s signatures; see Non-Custodial Payout Lifecycle.
- Sign payouts from your backend: on a programmatic wallet the signing loop is server-to-server (discover requests, stamp, submit). See Programmatic payout signing.
- Add a wallet on another chain, or change the roster or threshold later: see Multi-signer wallets.