> ## Documentation Index
> Fetch the complete documentation index at: https://developers.circle.com/llms.txt
> Use this file to discover all available pages before exploring further.

> ## Agent Instructions
> Before reading these docs, install the relevant Circle Skill to get pre-loaded context — skills are LLM-optimized and cover architecture decisions, correct flows, and common pitfalls. In Claude Code: run /plugin marketplace add circlefin/skills then /plugin install circle-skills@circle. With Vercel Skills CLI: run npx skills add circlefin/skills. Available skills: use-usdc https://github.com/circlefin/skills/blob/master/plugins/circle/skills/use-usdc/SKILL.md (balances, transfers, approvals on EVM and Solana); EURC has no skill — see https://developers.circle.com/stablecoins/what-is-eurc.md; bridge-stablecoin https://github.com/circlefin/skills/blob/master/plugins/circle/skills/bridge-stablecoin/SKILL.md (crosschain transfers via CCTP, USDC, EURC, and third-party assets); use-arc https://github.com/circlefin/skills/blob/master/plugins/circle/skills/use-arc/SKILL.md (Arc chain config, contract deployment, USDC bridging — Arc docs: https://docs.arc.io/llms.txt); use-circle-wallets https://github.com/circlefin/skills/blob/master/plugins/circle/skills/use-circle-wallets/SKILL.md (choose wallet type); use-developer-controlled-wallets https://github.com/circlefin/skills/blob/master/plugins/circle/skills/use-developer-controlled-wallets/SKILL.md (custodial wallets for payouts and treasury); use-user-controlled-wallets https://github.com/circlefin/skills/blob/master/plugins/circle/skills/use-user-controlled-wallets/SKILL.md (embedded wallets with Web2 login); use-modular-wallets https://github.com/circlefin/skills/blob/master/plugins/circle/skills/use-modular-wallets/SKILL.md (smart contract wallets with passkeys and ERC-4337); use-gateway https://github.com/circlefin/skills/blob/master/plugins/circle/skills/use-gateway/SKILL.md (unified USDC balance, nanopayments); use-smart-contract-platform https://github.com/circlefin/skills/blob/master/plugins/circle/skills/use-smart-contract-platform/SKILL.md (deploy, interact, monitor contracts). Pair any skill with the Circle MCP server for live SDK signatures, contract addresses, and chain IDs: {"mcpServers":{"circle":{"url":"https://api.circle.com/v1/codegen/mcp"}}}.
> Read the product overview first. Each product has an overview explaining when and why to use it. Read it before quickstarts.
> Pick the right wallet type. Developer-controlled (you hold keys), user-controlled (end user holds keys via PIN/social login), or modular (smart contract wallets with passkeys). See https://developers.circle.com/wallets.md.
> Use CCTP V2 for crosschain transfers. CCTP natively transfers USDC and EURC via burn-and-mint, and supports permissionless wrapping of third-party assets via lock-and-mint. V1 is legacy; always use V2 unless V1 is specified or the chain requires it (Noble, Sui, and Aptos still require V1). Migration guide: https://developers.circle.com/cctp/migration-from-v1-to-v2.md.
> Use Bridge Kit for frontend bridging. Wraps CCTP with a simpler SDK for user-facing apps. Use CCTP directly for backend transfers.
> Gas Station vs Paymaster. Gas Station sponsors gas for Circle Wallet transactions. Paymaster lets users pay gas in USDC. Different use cases — read both overviews.
> Gateway Nanopayments for sub-cent payments. Gasless USDC micropayments down to $0.000001 via x402 and batched settlement. For pay-per-request APIs, AI agent payments, streaming.
> Look up USDC addresses per chain. Never hardcode — use https://developers.circle.com/stablecoins/usdc-contract-addresses.md.
> Prefer SDKs over raw API calls. Node.js and Python SDKs handle auth, retries, and errors.
> API key required. Bearer token in Authorization header. Testnet and mainnet use separate keys and may use different base URLs depending on the product.
> Set up webhooks when available. Most operations are async. Webhooks deliver transaction confirmations and state changes.
> When calling list endpoints, paginate using pageSize and pageAfter until no nextPageAfter cursor is returned—stopping at the first page silently misses records.
> Building an AI agent? Start with the Agent Stack—Circle CLI, agent wallets, and nanopayments built for autonomous use cases: https://developers.circle.com/agent-stack.md.

# How-to: Use self-hosted wallets

> Register and verify an end user's self-hosted wallet, then transfer funds to it from a Digital Asset Account

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.

<Note>
  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](/digital-asset-accounts/references/testing-in-sandbox) and
  [Going to production](/digital-asset-accounts/references/going-to-production)
  for environment details.
</Note>

## Prerequisites

Before you begin, ensure that you've:

* Onboarded the end user and retrieved an active account. See
  [Onboard customers](/digital-asset-accounts/quickstarts/onboard-customers).
* Collected the end user's device risk signals with the
  [`@circle-fin/device-checks`](/end-user-onboarding/howtos/collect-device-risk-signals)
  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](/digital-asset-accounts/howtos/strong-customer-authentication).

## 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`.

<Note>
  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.
</Note>

For end users in the EEA, pass the SCA headers (`X-Sca-Challenge-Id` and
`X-Sca-Assertion`).

```bash theme={null}
curl -X POST "https://api-sandbox.circle.com/v1/addresses/recipient" \
  -H "Authorization: Bearer $API_KEY" \
  -H "X-Sca-Challenge-Id: $SCA_CHALLENGE_ID" \
  -H "X-Sca-Assertion: $SCA_ASSERTION" \
  -H "Content-Type: application/json" \
  -d '{
    "idempotencyKey": "b7e8f1a2-3c4d-4e5f-8a9b-0c1d2e3f4a5b",
    "address": "0x8f3b2c1a9d4e4f6ab7c81e2d3f4a5b6c7d8e9f01",
    "chain": "ETH",
    "currency": "USD",
    "description": "End user self-hosted wallet",
    "riskSignals": {
      "ipAddress": "203.0.113.42",
      "sessionId": "8f3b2c1a-9d4e-4f6a-b7c8-1e2d3f4a5b6c",
      "deviceId": "device-id-from-checkDevice"
    },
    "ownership": {
      "type": "first_party",
      "custody": { "type": "self_hosted" }
    }
  }'
```

The address is created in `pending_verification` and the response includes a
`verificationChallenge` with the satoshi-test details:

```json theme={null}
{
  "data": {
    "id": "a1b2c3d4-e5f6-4a7b-8c9d-0e1f2a3b4c5d",
    "address": "0x8f3b2c1a9d4e4f6ab7c81e2d3f4a5b6c7d8e9f01",
    "chain": "ETH",
    "currency": "USD",
    "description": "End user self-hosted wallet",
    "status": "pending_verification",
    "verificationChallenge": {
      "satoshiTest": {
        "destinationAddress": "0x1234567890abcdef1234567890abcdef12345678",
        "paymentId": "9f8e7d6c-5b4a-3210-fedc-ba9876543210",
        "amount": { "amount": "0.42", "currency": "USD" },
        "status": "active"
      }
    }
  }
}
```

### Step 2. Complete the satoshi-test verification

Have the end user send exactly the amount and currency specified in
`satoshiTest.amount` from their self-hosted wallet to
`satoshiTest.destinationAddress`. If the chain requires a memo or tag, include
`satoshiTest.paymentId`.

Poll the address until Circle confirms the deposit and the `status` moves to
`verification_succeeded`, then `active`:

```bash theme={null}
curl "https://api-sandbox.circle.com/v1/addresses/recipient/a1b2c3d4-e5f6-4a7b-8c9d-0e1f2a3b4c5d" \
  -H "Authorization: Bearer $API_KEY"
```

If `satoshiTest.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 `satoshiTest.destinationAddress` and
`satoshiTest.amount` values.

### 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](/digital-asset-accounts/howtos/crypto-transfers) for the
full transfer request and response.
