Skip to main content
A recipient address is an external blockchain address that a Digital Asset Account can send funds to. Register each address before you send to it. Circle screens the address, and you can send to it only after its status is active or verification_succeeded. To send funds, see Send crypto transfers. Your backend manages recipient addresses with your API key, for custodial and non-custodial accounts alike. For a non-custodial account, register the address for the same clientEntityId as the account. Registration doesn’t need the end customer’s signature.

Prerequisites

Before you begin, ensure that you’ve:
  • Obtained an API key for Digital Asset Accounts from Circle.
  • Onboarded the end customer and kept their clientEntityId. See Onboard customers.
  • Run a device check for the end customer and kept the deviceId it returns. Every request that registers an address carries it in riskSignals. See Collect device risk signals.
  • For end customers in the European Economic Area (EEA), prepared a Strong Customer Authentication (SCA) assertion. Registering a recipient address is an SCA-gated operation. See Implement SCA.
  • Installed cURL on your development machine.

Register a recipient address

Register the external blockchain address where you want to send stablecoins. For every field, see POST /v1/addresses/recipient.
Response
Send to the address only when its status is active or verification_succeeded. If it isn’t yet, get it with GET /v1/addresses/recipient/{recipientAddressId} until it is. For end customers booked to Circle’s EEA entity, the request must also declare wallet ownership, and you must send the X-Sca-Challenge-Id and X-Sca-Assertion headers from an ADDRESS_BOOK_ADD challenge. For the ownership object, see the example in Register a self-hosted wallet and EEA API behavior.

Register a self-hosted wallet

A self-hosted wallet is a blockchain wallet that an end customer controls directly, outside any custodian. Before you can send funds to one, the end customer must prove that they own it. Register the wallet with its ownership details, then have the end customer complete one of two ownership checks:
  • Message signature: The end customer signs a Circle-provided message with the wallet’s private key. Available for EVM blockchains and Solana.
  • Test deposit: The end customer sends a small deposit, called a satoshi test, from the wallet. It confirms they control the private key. It’s the fallback for all other blockchains, and remains available on EVM blockchains and Solana.

Register the wallet with its ownership

Call POST /v1/addresses/recipient with the wallet’s address and chain, the end customer’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 customer; you can’t register a third_party self-hosted wallet.
The SCA headers (X-Sca-Challenge-Id and X-Sca-Assertion) are required only for end customers in the EEA. Omit them otherwise.
The address is created in pending_verification and the response includes a verificationChallenge. On EVM-family blockchains and Solana, the challenge carries both a messageSignature block and a satoshiTest block, so you can complete either check. On all other blockchains, only satoshiTest is present.

Verify ownership of the wallet

Complete one of the two checks. On EVM-family blockchains and Solana, the message-signature check and the satoshi test are available. On all other blockchains, use the satoshi test.

Sign a message

Have the end customer sign the verificationChallenge.messageSignature.message string exactly as returned, with the wallet’s private key:
  • EVM-family blockchains: Produce a personal_sign signature (EIP-191) and submit the 0x-prefixed hex string.
  • Solana: Produce an ed25519 signature over the raw UTF-8 message bytes, with no hashing and no prefix, and submit the 64-byte signature as Base58 or Base64.
Then submit the signature with POST /v1/addresses/recipient/{recipientAddressId}/verification/signature:
A 200 response means the signature verified and the address moved out of pending_verification. A 400 response means the signature was invalid or the address was already verified. If messageSignature.status becomes expired before you submit, request a fresh challenge with POST /v1/addresses/recipient/{recipientAddressId}/verification/resend, then have the end customer sign the new message. A resend issues new challenges for both methods.

Send a satoshi test

Have the end customer send exactly satoshiTest.amount.amount from their self-hosted wallet to satoshiTest.destinationAddress, in USDC for a USD address or in EURC for an EUR address. If the amount or token doesn’t match, the address stays pending_verification. If the chain requires a memo or tag, include satoshiTest.paymentId. If satoshiTest.status becomes expired before the deposit arrives, request a fresh one with POST /v1/addresses/recipient/{recipientAddressId}/verification/resend, then repeat the deposit against the new satoshiTest.destinationAddress and satoshiTest.amount values.

Poll until verification completes

Poll the address until its status moves to verification_succeeded:
When verification completes, the response status changes to verification_succeeded and the verificationChallenge is omitted:
Once the recipient address is verification_succeeded, it’s eligible for transfers. A verified self-hosted wallet stays in this status. It doesn’t move to active. See Send crypto transfers.

List recipient addresses

Retrieve an end customer’s verified recipient addresses, which are eligible for transfers, with GET /v1/addresses/recipient. This endpoint supports pagination. To check an address that is still being verified, get it by id with GET /v1/addresses/recipient/{id}.
Response

Delete a recipient address

Remove a recipient address that is no longer needed, with DELETE /v1/addresses/recipient/{id}. You can’t delete an address whose status is failed, disabled, or verification_succeeded. The API returns a 400 error. Deleted addresses cannot be used for new transfers.
If the deletion is successful, the API returns a 200 response. For an end customer in the EEA, also send the X-Sca-Challenge-Id and X-Sca-Assertion headers from an ADDRESS_BOOK_DELETE challenge. See Implement SCA.
Deleting a recipient address does not affect previously completed transfers to that address. The transaction history is preserved.

See also