Skip to main content
A self-hosted wallet is a blockchain wallet an end user controls directly, outside any custodian. Before a Digital Asset Account (DAA) can send funds to one, the end user must prove they own it. You register the wallet as a recipient address with its ownership details, then complete a satoshi-test verification: Circle asks the end user to send a small deposit from the self-hosted wallet, which confirms control of the private key. Once verified, the address becomes eligible for transfers.
The Digital Asset Accounts API base URL is https://api-sandbox.circle.com for sandbox and https://api.circle.com for production. Set your API key in the Authorization header using the format Bearer YOUR_API_KEY. See Sandbox environment and Going to production for environment details.

Prerequisites

Before you begin, ensure that you’ve:
  • Onboarded the end user and retrieved an active account. See Onboard customers.
  • Collected the end user’s device risk signals with the @circle-fin/device-checks SDK. You pass the resulting deviceId on the request.
  • For end users in the EEA, prepared a Strong Customer Authentication (SCA) assertion. Registering a recipient address is an SCA-gated operation. See Implement SCA.

Steps

Step 1. Register the self-hosted wallet as a recipient address

Call POST /v1/addresses/recipient with the wallet’s address and chain, the end user’s riskSignals, and an ownership object. For a self-hosted wallet, set type to first_party, set custody.type to self_hosted, and omit vaspId.
Self-hosted wallets support first-party ownership only. The wallet must belong to the end user; you can’t register a third_party self-hosted wallet.
For end users in the EEA, pass the SCA headers (X-Sca-Challenge-Id and X-Sca-Assertion).
The address is created in pending_verification and the response includes a verificationChallenge with the satoshi-test details:

Step 2. Complete the satoshi-test verification

Have the end user send exactly the challenge amount of the challenge currency from their self-hosted wallet to the destinationAddress. If the chain requires a memo or tag, include the paymentId. Poll the address until Circle confirms the deposit and the status moves to verification_succeeded, then active:
If the challenge status becomes expired before the deposit arrives, request a fresh one with POST /v1/addresses/recipient/{id}/verification/resend, then repeat the deposit against the new destinationAddress and amount.

Step 3. Send funds to the verified wallet

Once the recipient address is active, it’s eligible for transfers. Create a transfer to it with POST /v1/accounts/transfers, using the recipient address id as the destination. See Send crypto transfers for the full transfer request and response.