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

# Addresses

> Addresses represent onchain wallets and offchain bank accounts, identified by `address_id` for use in transfers.

Addresses are represented by an `address_id`, which uniquely identifies a wallet or account for a specific `transfer_type`.

> IDs are KSUIDs (26-char, time-sortable); copy/paste carefully.

An `address_id` can represent either an onchain wallet or offchain account (ACH, Wire, or RTP account), depending on the `transfer_type`. Use `address_id` wherever a source/destination is required in Transfers.

Brale distinguishes between internal and external addresses using the type field:

* `type`: `internal` - An `address_id` associated with wallets managed by Brale on behalf of you or your customers.
* `type`: `external` - An `address_id` managed outside of Brale's infrastructure (e.g., user-owned wallet or external account).

Whether internal or external, all addresses possess:

* `name`: A human readable label
* `transfer_types`: The `transfer_types` the address supports.
* `status`: The lifecycle state of the address. See [Address lifecycle](#address-lifecycle).

## Address lifecycle

Every address has a `status` that represents its lifecycle state:

| Status     | Description                                                                                       |
| ---------- | ------------------------------------------------------------------------------------------------- |
| `pending`  | Address is being provisioned (e.g., a custodial wallet is being created on-chain).                |
| `active`   | Address is ready to be used as a source or destination in transfers.                              |
| `archived` | Address is disabled. It cannot be used in new transfers; existing pending transfers may complete. |

### Archive and unarchive (external addresses only)

You can change the lifecycle state of an **external** address by sending a `status` update to the [PATCH address endpoint](/api-reference/brale/update-address):

* **Archive:** `PATCH /accounts/{account_id}/addresses/{address_id}` with `{ "status": "archived" }` disables the address for new transfers while preserving the historical record.
* **Unarchive:** `PATCH /accounts/{account_id}/addresses/{address_id}` with `{ "status": "active" }` restores the address.

<Warning>
  Archive and unarchive are supported only for addresses with `type=external`. Internal (custodial) addresses are not archived or unarchived through this endpoint.
</Warning>

Archived addresses remain visible in `GET /accounts/{account_id}/addresses` responses with `status: "archived"` but cannot be used as a source or destination in new transfers.

See the [PATCH address endpoint reference](/api-reference/brale/update-address) for request and response examples.

## Supported Transfer Types

* [Off-chain](/coverage/transfer-types#offchain) rails: `wire`, `ach_credit`, `same_day_ach_credit`, `ach_debit`, `rtp_credit`
* [On-chain](/coverage/transfer-types#onchain) (examples): `canton`, `base`, `polygon`, `solana`, `stellar`, `xrp_ledger`<br />(for full list, see [Coverage: Transfer Types](/coverage/transfer-types))

## Custodial (Internal) Addresses

Brale provides custodial wallets that allow businesses to securely hold and transfer stablecoins on behalf of themselves or their customers. Custodial addresses support all supported blockchains.

When your customer's Account is onboarded, Brale automatically generates internal custodial addresses on all supported blockchains. You do not need to create them manually. If an address is visible under an account-scoped endpoint but not globally, use the account-scoped endpoint.

## Non-Custodial (External) Addresses

Create external addresses to link on-chain wallets or off-chain bank endpoints.

### Two ways to create an external bank address

Brale supports two paths for creating an external off-chain bank address. The path you choose determines which `transfer_types` are available.

| Capability   | Plaid-linked bank account | Direct bank entry |
| ------------ | ------------------------- | ----------------- |
| `ach_debit`  | Supported                 | Not supported     |
| `ach_credit` | Supported                 | Supported         |
| `rtp`        | Supported                 | Supported         |
| `wire`       | Not supported             | Supported         |

<Warning>
  **ACH debit** is only available through the **Plaid-linked bank account** flow. You cannot enable `ach_debit` via Direct bank entry.
</Warning>

<Warning>
  **Wire** is only available through the **Direct bank entry** flow. You cannot enable `wire` via the Plaid-linked bank account flow.
</Warning>

For a full comparison and guidance on which path to use, see [External bank addresses](/key-concepts/external-bank-addresses).

### Create onchain external address

The blockchains the address supports. See [Supported Chains](/coverage/value-types) for the full list. Each address is associated with only one blockchain environment (e.g., Solana, EVM).

```json Request theme={null}
{
  "name": "Non-Custodial (External) Wallet",
  "transfer_types": ["ethereum", "base"],
  "address": "0x123456789"
}
```

```json Response theme={null}
{
  "id": "2VcUIIsgARwVbEGlIYbhg6fGG57"
}
```

### Create via Direct bank entry

Use the [Create a new external address](/api-reference/brale/create-address) endpoint to register a bank account when you already have the bank details. This path supports `wire`, `ach_credit`, and `rtp`. It does **not** support `ach_debit`.

**POST** `/accounts/{account_id}/addresses/external`

#### ACH credit example

```json Request theme={null}
{
  "owner": "Jane Doe",
  "transfer_types": ["ach_credit", "same_day_ach_credit"],
  "account_number": "1234567890",
  "routing_number": "063108680",
  "name": "Example Bank",
  "bank_address": {
    "street_line_1": "100 Example St",
    "street_line_2": "Suite 500",
    "city": "Springfield",
    "state": "CA",
    "zip": "90001"
  },
  "beneficiary_address": {
    "street_line_1": "100 Example St",
    "street_line_2": "Suite 500",
    "city": "Springfield",
    "state": "CA",
    "zip": "90001"
  },
  "account_type": "checking"
}
```

```json Response theme={null}
{
  "id": "2VcUIIsgARwVbEGlIYbhg6fGG57"
}
```

#### Wire example

```json Request theme={null}
{
  "owner": "Jane Doe",
  "transfer_types": ["wire"],
  "account_number": "1234567890",
  "routing_number": "063108680",
  "name": "Example Bank",
  "bank_address": {
    "street_line_1": "100 Example St",
    "street_line_2": "Suite 500",
    "city": "Springfield",
    "state": "CA",
    "zip": "90001"
  },
  "beneficiary_address": {
    "street_line_1": "100 Example St",
    "street_line_2": "Suite 500",
    "city": "Springfield",
    "state": "CA",
    "zip": "90001"
  },
  "account_type": "checking"
}
```

```json Response theme={null}
{
  "id": "2VcUIIsgARwVbEGlIYbhg6fGG57"
}
```

<Note>
  Need `ach_debit`? Use the [Plaid-linked bank account flow](#create-via-plaid-linked-bank-account) instead.
</Note>

### Create external address for RTP

Real-time payments (`rtp_credit`) work slightly differently from other transfer types.

RTP eligibility is determined asynchronously by our banking partner after the bank account is registered. When you create an off-chain external address and include `rtp_credit` in `transfer_types`, the **initial** Address may only list ACH rails, for example:

```json Response theme={null}
{
  "transfer_types": ["ach_credit", "same_day_ach_credit"]
}
```

After the bank confirms that the account is RTP-enabled, Brale will update the Address in place and add `rtp_credit` to transfer\_types. This typically happens shortly after creation.

### Update Address transfer types

Sometimes you'll want an address to gain new capabilities over time. For example:

* You want an EVM onchain address to start supporting an additional chain (e.g., `ethereum` in addition to `base`).
* A bank account that initially only supports `wire` is upgraded to also support `ach_credit`.

Instead of creating a new Address, you can add new `transfer_types` to an existing Address (and optionally update its `name`). The same [PATCH endpoint](/api-reference/brale/update-address) also supports [archiving or unarchiving](#archive-and-unarchive-external-addresses-only) external addresses.

Onchain Address Example - add a new EVM chain

Suppose you have a non-custodial EVM wallet Address that currently only supports `base` and want to add `ethereum`:

**PATCH** `/accounts/{account_id}/addresses/{{address_id}}`

```json Request theme={null}
{
  "additional_transfer_types": ["ethereum"]
}
```

Response

```json Response theme={null}
{
  "id": "2VcUIIsgARwVbEGlIYbhg6fGG57",
  "type": "external",
  "name": "EVM Wallet",
  "wallet_address": "0x123456789",
  "transfer_types": ["base", "ethereum"]
}
```

Note: All onchain transfer\_types on a single Address must belong to the same blockchain environment (for example, all EVM mainnets). You cannot mix incompatible environments on the same Address.

Offchain Address Example - add ACH Credit to a wire-only bank Address

Suppose you have an off-chain bank Address that currently only supports wires and now want to update to include ACH and SDACH.

**PATCH** `/accounts/{account_id}/addresses/{{address_id}}`

```json Request theme={null}
{
  "additional_transfer_types": ["same_day_ach_credit", "ach_credit"]
}
```

Response

```json Response theme={null}
{
  "id": "35zDQqWZuiITc8emZc3T7viZSAV",
  "name": "checking 7890",
  "owner": "Jane Doe",
  "status": "active",
  "transfer_types": ["rtp_credit", "same_day_ach_credit", "wire"],
  "created": "2025-11-25T20:53:12.655227Z",
  "bank_address": {
    "state": "CA",
    "zip": "90001",
    "city": "Springfield",
    "street_line_1": "100 Example St",
    "street_line_2": "Suite 500"
  },
  "beneficiary_address": {
    "state": "CA",
    "zip": "90001",
    "city": "Springfield",
    "street_line_1": "100 Example St",
    "street_line_2": "Suite 500"
  },
  "account_number": "****7890",
  "needs_update": false,
  "account_type": "checking",
  "last_updated": "2025-11-25T21:35:40.898085Z",
  "routingNumber": "063108680"
}
```

#### Updating Address Name

You can also use this endpoint to update the human-readable name (alias) of an Address. You can send name on its own, or together with additional\_transfer\_types:

```json Request theme={null}
{
  "name": "My EVM Wallet"
  "additional_transfer_types": ["base"]
}
```

#### Behavior

`additional_transfer_types` is a list of transfer types to **add** to this Address. These are merged into the existing `transfer_types`.

* The values in `additional_transfer_types` are **added** to the Address’s existing `transfer_types`.
* Existing `transfer_types` are preserved even if you don’t include them in the request.
* Sending a transfer type that is already enabled is idempotent and has no effect.
* This endpoint can also be used to update the `name` of the address, a human readable alias.

## Create via Plaid-linked bank account

This flow lets your customers securely link their bank accounts via Plaid. Addresses created through Plaid support `ach_debit`, `ach_credit`, and `rtp`. This is the **only** path that supports `ach_debit`.

For a full comparison of both paths, see [External bank addresses](/key-concepts/external-bank-addresses).

### Overview of the Flow

1. Request a Plaid Link Token from Brale.
2. Initialize Plaid Link in your front-end using the `link_token`.
3. Plaid returns a `public_token` once the user has successfully linked their account.
4. Exchange the `public_token` with Brale to finalize the linking process.
5. Fetch the newly created Address for the end user, then proceed with transfers, etc.

### Request a Plaid Link Token

**POST** `https://api.brale.xyz/accounts/{account_id}/plaid/link_token`

```json Request theme={null}
{
  "date_of_birth": "1990-01-01", // Optional
  "email_address": "user@example.com", // Optional
  "legal_name": "John Doe", // Optional
  "phone_number": "+1234567890" // Optional
}
```

```json Response theme={null}
{
  "expiration": "2025-03-23T03:22:34.086Z",
  "link_token": "link_token_XYZ",
  "callback_url": "https://api.brale.xyz/exchange_public_token/{unique-id}"
}
```

| Parameters     | Description                                                                        |
| -------------- | ---------------------------------------------------------------------------------- |
| `link_token`   | The token you will use to launch Plaid Link in your front-end or mobile app.       |
| `expiration`   | Time at which the `link_token` will no longer be valid.                            |
| `callback_url` | The endpoint to which you should send the `public_token` to finalize the exchange. |

### Render the Plaid Link SDK

In your front-end, initialize Plaid Link using the link\_token you received.

For production apps, it's recommended you send the public\_token to your own backend (over HTTPS), and then have your backend call our exchange endpoint. That way, you avoid exposing your own platform API keys in the browser.

### Register Address (exchange the public token)

Send us the public\_token you received from Plaid Link. Brale securely exchanges it for a Plaid access\_token server-side and creates an Address on the specified Account.

**POST** `https://api.brale.xyz/accounts/{account_id}/plaid/register-account`

```json Request theme={null}
{
  "public_token": "public_token_XYZ",
  "customer_webhook_url": "https://mywebhook.com",
  "transfer_types": [
    "ach_debit",
    "same_day_ach_debit",
    "ach_credit",
    "same_day_ach_credit"
  ]
}
```

```json Response theme={null}
{
  "address_id": "34yknnMShvDbSW6tQg4HLlN41QO"
}
```

After this call completes, our system retrieves the linked bank account and creates an Address for the account the user selected.

### Check for newly created Addresses

Shortly after exchanging the public token, the user's bank accounts are idempotently created as an Address which you can query.

**GET** `https://api.brale.xyz/accounts/account_id/addresses/{id}`

```json Response theme={null}
{
  "name": "Business Checking Account",
  "transfer_type": ["ACH", "Wire"],
  "bank_details": {
    "owner": "Jane Doe",
    "account_number": "1234567890",
    "routing_number": "987654321",
    "name": "Example Bank",
    "address": {
      "street_line_1": "100 Example St",
      "street_line_2": "Suite 500",
      "city": "Springfield",
      "state": "CA",
      "zip": "90001"
    },
    "account_type": "checking"
  }
}
```

At this point, you can initiate ACH debits or other transactions using these new Addresses.

## Handling Re-Authentication

When Plaid signals that an Item requires user action (e.g., credentials changed), Brale can notify you via webhook and you can present a Plaid update Link flow to the user.

### Receive Brale webhook

Brale will `POST` a JSON payload when re-auth is required to the `customer_webhook` you provide during the exchange step.

```json Example payload theme={null}
{
  "reason": "Plaid item requires re-authentication",
  "timestamp": "2025-09-13T17:17:00Z",
  "event_type": "ITEM_LOGIN REQUIRED",
  "address_id": "address_id123"
}
```

### Check status

**GET** `https://api.brale.xyz/accounts/{account_id}/addresses/{address_id}`

```json Response theme={null}
{
  "status": "active",
  "last_updated": "2025-09-13T17:17:00Z",
  "address_id": "34yxvqP90NfeeYkQGriO6bSfn1K",
  "needs_update": true
}
```

### Request an updated link token

**POST** `https://api.brale.xyz/accounts/{account_id}/addresses/{address_id}/update-link-token`

```json Response theme={null}
{
  "link_token": "link_token_XYZ"
}
```

Open Plaid Link again with this `link_token`. Plaid will streamline the flow and only ask the user to re-authenticate. Run Step 3 again with the new `public_token` (same endpoint). The existing Address is updated in place and retains the same `address_id`.

## Fetching Addresses

Retrieve all addresses associated with the authenticated Account.

This endpoint returns all addresses (whether internal or external) linked to the Account.

**GET** `/accounts/{account_id}/addresses`

```json Response theme={null}
{
  "addresses": [
    {
      "id": "a1b2c3d4-5678-90ab-cdef-1234567890ab",
      "status": "active",
      "name": "Internal Custodial Wallet",
      "type": "Internal",
      "address": "73uyt9HkEqx9bThYXWaUBP67sWsiJEsyJ5rSCieDx5me",
      "created": "2023-03-07T17:31:37.997502Z",
      "transfer_types": ["solana", "solana_devnet"]
    },
    {
      "id": "34yxvqP90NfeeYkQGriO6bSfn1K",
      "name": "THE BANK OF TAMPA",
      "owner": "Jane Doe",
      "status": "active",
      "transfer_types": ["ach_credit", "same_day_ach_credit"],
      "created": "2025-11-03T19:57:25.965990Z",
      "bank_address": {
        "state": "CA",
        "zip": "90001",
        "city": "Springfield",
        "street_line_1": "100 Example St",
        "street_line_2": "Suite 500"
      },
      "beneficiary_address": {
        "state": "CA",
        "zip": "90001",
        "city": "Springfield",
        "street_line_1": "100 Example St",
        "street_line_2": "Suite 500"
      },
      "account_number": "****7890",
      "needs_update": false,
      "last_updated": "2025-11-03T19:57:26.801044Z",
      "routingNumber": "063108680",
      "account_type": "checking"
    },
    {
      "id": "34yGFQf7tP1HJCPAWNGaN4rh4nX",
      "name": "JPMORGAN CHASE BANK, NA",
      "owner": "Alberta Bobbeth Charleson",
      "status": "active",
      "transfer_types": ["ach_debit"],
      "created": "2025-11-03T13:58:14.528239Z",
      "bank_address": null,
      "beneficiary_address": null,
      "account_number": "****1111",
      "needs_update": false,
      "last_updated": "2025-11-03T13:58:14.528239Z",
      "routingNumber": "021000021",
      "account_type": "savings"
    }
  ]
}
```

### Fetching an Internal Balance

You can query the stablecoin balance of an internal address.

**GET** `/accounts/{account_id}/addresses/address_id/balance?transfer_type=chain&value_type=token`

```json Response theme={null}
{
  "address": {
    "id": "2VcUIonJeVQzFoBuC7LdFT0dRe4",
    "address": "0xcdEA458750b9A8D6C4Ba8B3D68CE98Ba2330352A"
  },
  "balance": {
    "value": "45314.07",
    "currency": "USD"
  },
  "value_type": "SBC",
  "transfer_type": "base"
}
```

### Filtering Addresses

You can narrow results on `GET /accounts/{account_id}/addresses` with optional query parameters.

## Query parameters

| Param           | Type              | Description                                                                                                             |
| --------------- | ----------------- | ----------------------------------------------------------------------------------------------------------------------- |
| `address`       | string            | Filters results to addresses whose onchain address exactly matches the provided value (e.g., an EVM or Solana address). |
| `type`          | enum              | Filter by address type: `internal` \| `external`.                                                                       |
| `transfer_type` | enum (repeatable) | Filter by one or more transfer types (e.g., `ethereum`, `base`, `solana`, `stellar`).                                   |

<Tip>
  If you already know the onchain address you are looking for, you can filter the addresses list by passing the exact address in the `address` query parameter. This is intended for exact address matching—partial matches are not supported.
</Tip>

## Examples

Find a specific registered onchain address

```bash theme={null}
curl --request GET \
  --url "https://api.brale.xyz/accounts/${ACCOUNT_ID}/addresses?address=0xcdCfd05B57c6136F090658C123063d12DebaA51D" \
  --header "Authorization: Bearer ${ACCESS_TOKEN}"
```

External addresses usable on Solana OR Base

**GET** `/accounts/{account_id}/addresses?type=external&transfer_type=solana&transfer_type=base`

Internal EVM addresses that support Ethereum

**GET** `/accounts/{account_id}/addresses?type=internal&transfer_type=ethereum`
