Wallet Declaration (ACAM)

Central Bank of Brazil reporting of international virtual asset transfers, and the wallet holder declaration it requires on deposits.

Mandatory from November 15, 2026

Brazilian regulation requires every international transfer of virtual assets to be reported to the Central Bank of Brazil (BCB). This report is called ACAM. From November 15, 2026, a deposit that sends crypto to a wallet we cannot identify is refused unless it carries a walletDeclaration. The requirement is being enabled account by account before that date; ask support when it will be enabled on yours.

What changes

When a deposit delivers crypto on-chain, we must report who holds the destination wallet and in which country. A holder outside Brazil makes the transfer international, and an international transfer also needs a purpose code describing why the money is moving.

Most deposits need nothing new. You only send the declaration when the destination is an external wallet we have not seen before on your account.

DestinationWhat you send
A Hodle wallet of your account or of your subaccount's holderNothing. We already know the holder.
An external wallet you already declared (same address and network)Nothing. The saved declaration is reused.
A new external wallet whose holder is in BrazilwalletDeclaration without purposeCode.
A new external wallet whose holder is outside BrazilwalletDeclaration with purposeCode.

Pix legs (BRL in, BRL out) never need a declaration or a purpose code. Payouts to a Pix key or a Pix QR code are domestic.

The walletDeclaration object

Send it in the body of POST /api/deposit/asset.

FieldTypeRequiredDescription
isSelfCustodybooleanYesMust be true. The holder controls the wallet's private keys. Deliveries to custodial wallets (an exchange deposit address, for example) are not accepted.
counterpartyNamestringYesFull name or legal name of the wallet holder, 1 to 100 characters.
counterpartyCountrystringYesISO 3166-1 alpha-2 code, uppercase. A person's country of residence or a company's country of incorporation. BR makes the transfer domestic.
reasonstringYesWhy the money is sent to this wallet, in your own words, 3 to 500 characters.
purposeCodestringCond.Required when counterpartyCountry is not BR. Must be valid for the amount band (below). Omit it for BR.

The declaration is stored per account, address and network. Later deposits to the same wallet reuse it, so you send it once. Sending it again replaces the saved one.

Purpose codes and amount bands

The accepted purpose codes depend on the operation's value in USD:

BandValue of the operation
Up to USD 50,000USD 50,000 or less
Above USD 50,000More than USD 50,000

For buying virtual assets, use:

PurposeUp to USD 50,000Above USD 50,000
Purchase of virtual assets9199212186

A code that does not belong to the band of the deposit is refused. For other purposes, ask support for the list of accepted codes.

Example

A BRLA deposit to an external wallet held by a company incorporated in the United States:

curl --request POST \
  --url https://api.hodle.com.br/api/deposit/asset \
  --header "Authorization: Bearer $API_KEY" \
  --header "Content-Type: application/json" \
  --data '{
    "value": 50000,
    "asset": "BRLA",
    "network": "polygon",
    "address": "0x4444444444444444444444444444444444444444",
    "externalId": "order-3001",
    "walletDeclaration": {
      "isSelfCustody": true,
      "counterpartyName": "Example Holdings LLC",
      "counterpartyCountry": "US",
      "reason": "Purchase of virtual assets for the company treasury",
      "purposeCode": "91992"
    }
  }'
const res = await fetch('https://api.hodle.com.br/api/deposit/asset', {
  method: 'POST',
  headers: {
    Authorization: `Bearer ${process.env.HODLE_API_KEY}`,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    value: 50000,
    asset: 'BRLA',
    network: 'polygon',
    address: '0x4444444444444444444444444444444444444444',
    externalId: 'order-3001',
    walletDeclaration: {
      isSelfCustody: true,
      counterpartyName: 'Example Holdings LLC',
      counterpartyCountry: 'US',
      reason: 'Purchase of virtual assets for the company treasury',
      purposeCode: '91992',
    },
  }),
})
const data = await res.json()
import os, requests

res = requests.post(
    "https://api.hodle.com.br/api/deposit/asset",
    headers={
        "Authorization": f"Bearer {os.environ['HODLE_API_KEY']}",
        "Content-Type": "application/json",
    },
    json={
        "value": 50000,
        "asset": "BRLA",
        "network": "polygon",
        "address": "0x4444444444444444444444444444444444444444",
        "externalId": "order-3001",
        "walletDeclaration": {
            "isSelfCustody": True,
            "counterpartyName": "Example Holdings LLC",
            "counterpartyCountry": "US",
            "reason": "Purchase of virtual assets for the company treasury",
            "purposeCode": "91992",
        },
    },
)
data = res.json()

For a holder in Brazil, drop purposeCode and send "counterpartyCountry": "BR".

The response is the same as any other deposit. Nothing about the declaration is returned.

Errors

A missing or invalid declaration is refused with 400 and errorCode: "DEPOSIT_FAILED" before any Pix code is created, so no charge is left behind:

errorCause
Informe a finalidade, o titular e o país e confirme a autocustódia da carteira externa.New external wallet without walletDeclaration.
País do titular inválido.counterpartyCountry is not a valid country code.
Selecione a finalidade da transferência internacional.Holder outside Brazil without purposeCode.
Finalidade inválida.purposeCode is not an accepted code.
Selecione uma finalidade válida para a faixa de valor desta transferência.purposeCode does not belong to the amount band of this deposit.

Fix the declaration and repeat the request with the same externalId.

Your responsibility

The declaration is reported to the Central Bank under your account. Collect it from your customer, or state it yourself when you are the holder, and keep it true. When the holder or the purpose of a saved wallet changes, send a new declaration.