Skip to main content
Key rules
  • All IDs are KSUIDs (26-char, time-sortable); copy/paste carefully.
  • address_id is the universal source/destination primitive (covers wallets and fiat endpoints).
  • Always send Idempotency-Key on create POSTs; never on GETs. Do not reuse a key with a different payload/URI.
Each transfer requires both a source and a destination, which can be:
  • Fiat sources (e.g., a bank account for ACH or wire)
  • On-chain wallet addresses
Each source and destination includes:
  • value_type: The currency being transferred (USD, USDC, USDT, MXN, etc.)
  • transfer_type: The payment rail used (Wire, ACH, Polygon, Solana, SPEI, etc.)

Required Fields

Optional Fields

Response-only fields

source.payment_details

source.payment_details appears when Brale has underlying payment metadata to expose for the source leg of a transfer. This is primarily relevant for inbound fiat-funded transfers (e.g., wire or ACH on-ramps, automation-triggered mints). The object is optional and may not be present on every transfer. Wire transfers typically include the fuller set of fields, while ACH transfers may include only a subset — fields may be null or omitted depending on available rail metadata.
source.payment_details is a response-only field. It is not accepted as input when creating a transfer. Do not confuse it with destination.wire_memo, which is a request field for outbound wire transfers.

destination.payment_details

destination.payment_details appears when Brale has underlying payment metadata to expose for the destination leg of a transfer. This is primarily relevant for outbound wire transfers (stablecoin-to-fiat offramps and wire payouts). The object is optional and may be absent immediately after a transfer is created. For outbound wires, the IMAD is assigned by the sending bank and may not be available until after the wire has been submitted — Brale populates destination.payment_details later when the underlying bank metadata arrives.
destination.payment_details is a response-only field. It is not accepted as input when creating a transfer. Do not confuse it with destination.wire_memo, which remains a request field for outbound wire transfers.

Transfer scenarios: understanding value_type and transfer_type

Every request is scoped to an account, so the path always starts with: POST https://api.brale.xyz/accounts/{account_id}/transfers // The ID of your or your customer's account

USD to Stablecoin (Wire Transfer)

Accept a USD deposit to mint stablecoins. POST https://api.brale.xyz/accounts/account_id/transfers
When initiating a fiat to stablecoin transfer via wire, we will return a set of wire_instructions so you can provide them to your customer.
Response

USD to Stablecoin (ACH Debit)

Onramp to your stablecoin by debiting a Plaid connected address. POST https://api.brale.xyz/accounts/account_id/transfers
Request
Optional brand object You can specify which Account’s name appears on the receiver’s bank statement line items for ACH only. It is not supported for wire or RTP.

Stablecoin to USD (Wire Offramp or Payout)

Offramp your stablecoin to USD via wire transfer. POST https://api.brale.xyz/accounts/account_id/transfers
Request
For outbound wire transfers, you can optionally pass destination.wire_memo to include a memo or payment reference for the receiving bank or recipient.

Stablecoin to USD (ACH)

Offramp your stablecoin to USD via ACH Credit. POST https://api.brale.xyz/accounts/account_id/transfers
Request

Stablecoin Swaps

Swap USDC to your own stablecoin (YSBC). All stablecoin swaps are 1:1 with no slippage. POST https://api.brale.xyz/accounts/account_id/transfers
Request

Stablecoin Payout

Process stablecoin payouts to one or many external addresses (EOAs). POST https://api.brale.xyz/accounts/account_id/transfers
Request

Retrieving a single transfer

GET https://api.brale.xyz/accounts/{account_id}/transfers/{transfer_id}

On-chain transfer response

Response

Wire-funded transfer response (with payment_details)

For inbound wire-funded transfers, the response includes source.payment_details with metadata about the underlying payment. This helps you identify the sender and reconcile inbound fiat payments.
Response

Outbound wire transfer response (with destination.payment_details)

For outbound wire transfers (e.g., stablecoin-to-fiat offramps via wire), the response may include destination.payment_details with the wire IMAD once Brale has received the underlying bank metadata. The object may be absent immediately after the transfer is created and appear later when the wire is submitted.
Response

ACH-funded transfer response (with payment_details)

ACH transfers may include only a subset of payment_details fields. Fields may be null or omitted depending on available rail metadata.
Response (source excerpt)
transaction_id is a response-only field on source and destination. It contains the on-chain transaction hash or off-chain payment reference once the leg has been submitted to the network. It is not present in create requests. You can use transaction_id as a query-parameter filter on the list transfers endpoint.

Listing transfers

GET https://api.brale.xyz/accounts/{account_id}/transfers Returns a paginated list of transfers for the account. You can narrow results with query-parameter filters.

Filters

All filters are exact match and case-sensitive. When you combine multiple filters they apply with AND semantics.
value_type and transfer_type use canonical identifiers listed on the Value types and Transfer types coverage pages.
If no transfers match, the API returns 200 with an empty transfers array.

Filtering by transaction_id

transaction_id is an exact-match filter. Pass the full on-chain transaction hash or off-chain payment reference as the value. The filter matches against the transaction_id field on either the source or destination leg of each transfer.
  • The value must match exactly (case-sensitive, no partial matches).
  • If no transfer matches, the API returns 200 with an empty transfers array.
  • You can combine transaction_id with other filters (transfer_type, value_type, automation_id). Multiple filters use AND semantics — only transfers matching every filter are returned.

Example: filter by automation

Example: combined filters

Pagination

Only one of page[after] or page[prev] may be present per request. Filters persist across pages — you do not need to resend them when paging. Use the pagination.next value from the previous response as the page[after] query parameter in the next request.

Reconciliation best practices

  • Store transfer id, Idempotency-Key, timestamps, status, and any provider references.
  • For inbound fiat-funded transfers, check source.payment_details to identify the sender and match payments. Wire transfers typically include sender_name, sender_bank_name, and imad; ACH transfers may include only a subset of these fields.
  • For outbound wire transfers, check destination.payment_details.imad to record the wire’s IMAD for reconciliation and tracing. It may be absent immediately after the transfer is created and populated later once Brale has the underlying bank metadata.
  • Poll with backoff; avoid tight loops. Reuse the same Idempotency-Key when retrying the same logical transfer.
  • On 401, refresh the token and retry idempotently.
  • Production integrations can subscribe to transfer.completed and transfer.failed webhooks to receive signed events when a transfer reaches complete or failed. Use polling or retrieval endpoints for development, fallback handling, and reconciliation.

Transfer Statuses

Transfer Flow

A transfer will progress from pendingprocessingcomplete. Transfers include an updated_at field denoting the last time the status updated.

Transfer Limits

  • Inbound ACH transactions are limited to $50,000 per transaction.
  • There are no limits for wire or stablecoin transactions.