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 custodial vs non-custodial setup for this flow, 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, not set via API, 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. It is configured by Conduit out of band: an org-wide default with an optional per-customer override (the customer-level setting wins). There is no API to set it — arrange it with your Conduit representative. Programmatic unattended additionally requires an approval review by Conduit.
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"). 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 every supported chain in one claim (recommended). 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; solana and 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.