Withdrawals

Create customer withdrawal bank

Add a new bank account for customer fiat withdrawals.

POST
/api/v2/customers/{customerId}/withdrawal/banks

Adds a new bank account for withdrawals. The customer must be KYC verified, except for AUD withdrawal banks.

Currency and payment rails

  • SEPA (EUR): provide currency: "EUR", paymentRail: "SEPA", iban, and bic.
  • FEDWIRE (USD): provide currency: "USD", paymentRail: "FEDWIRE", accountNumber, and routingNumber.
  • SWIFT (USD): provide currency: "USD", paymentRail: "SWIFT", accountNumber (or IBAN), bic, bankName, bankAddress, and bankCountry.
  • AU_BANK_TRANSFER (AUD): provide currency: "AUD", paymentRail: "AU_BANK_TRANSFER", bsb, accountNumber, the payee's firstName, lastName and dateOfBirth, and the full address (addressLine1, city, postalCode, country). Only for AUD-only customers, verified or not, when AUD functionality is enabled for your organization. The payee is an individual: CUSTOMER and OTHER_INDIVIDUAL are active immediately, and OTHER_BUSINESS is refused. AUD-only customers cannot add EUR or USD accounts.

For backwards compatibility the API still accepts currency without paymentRail (EUR maps to SEPA, USD to FEDWIRE), but new integrations must send paymentRail.

Recipient Types

  • CUSTOMER - The customer themselves. Auto-approved if the beneficiary name matches the customer's verified name (KYC name for individuals, organization name for corporates). Returns 400 on name mismatch. AUD withdrawal banks are not name-checked: they are active immediately.
  • OTHER_INDIVIDUAL - A third-party individual. Requires manual approval, except for AUD withdrawal banks, which are active immediately.
  • OTHER_BUSINESS - A third-party business. Requires manual approval.

If recipientType is not specified, it defaults to CUSTOMER.

Address

For CUSTOMER recipients, addressLine1 and city are optional. If omitted, the address is auto-resolved from the customer's KYC data (individuals) or stored business address (corporates). You can check the available address via GET /customers/{customerId}/kyc/address. For OTHER_INDIVIDUAL and OTHER_BUSINESS, address fields are required. AUD withdrawal banks always require the payee's full address (addressLine1, city, postalCode, country).

Validation

  • EUR: IBAN and BIC/SWIFT formats are validated automatically
  • USD Fedwire: account number and routing number are validated automatically
  • USD SWIFT: BIC/SWIFT format is validated automatically, and bank name/address/country are required
  • AUD: the BSB must be 6 digits and the account number 1–9 digits; the account is checked with the payout provider before it is saved, and nothing is saved if that fails (502, safe to retry)
  • For CUSTOMER: beneficiary name is checked against the customer's verified identity (individual) or organization name (corporate), except for AUD withdrawal banks

Authorization

bearerAuth
AuthorizationBearer <token>

Organization API key obtained on Settings > API Keys page in Compose UI.

In: header

Path Parameters

customerId*string

Unique identifier of the customer

Request Body

application/json

TypeScript Definitions

Use the request body type in TypeScript.

Response Body

application/json

application/json

application/json

application/json

application/json

application/json

application/json

application/json

application/json

curl -X POST 'https://compose.finance/api/v2/customers/{customerId}/withdrawal/banks' \  -H 'Authorization: Bearer YOUR_API_KEY' \  -H 'Content-Type: application/json' \  -d '{    "currency": "EUR",    "paymentRail": "SEPA",    "beneficiaryName": "JOHN DOE",    "iban": "DE89370400440532013000",    "bic": "COBADEFFXXX",    "addressLine1": "123 Main Street",    "city": "Berlin",    "postalCode": "10115"  }'

{
  "id": "bank_123abc",
  "customerId": "550e8400-e29b-41d4-a716-446655440001",
  "beneficiaryName": "JOHN DOE",
  "iban": "DE89370400440532013000",
  "bic": "COBADEFFXXX",
  "addressLine1": "123 Main Street",
  "city": "Berlin",
  "postalCode": "10117",
  "country": "DE",
  "currency": "EUR",
  "paymentRail": "SEPA",
  "recipientType": "CUSTOMER",
  "recipientEmail": "[email protected]",
  "notificationEnabled": false,
  "status": "ACTIVE",
  "fundingSource": "VIRTUAL_ACCOUNT",
  "createdAt": "2024-01-15T10:30:00.000Z",
  "wallets": [
    {
      "id": "wallet_123abc",
      "address": "0x1234567890abcdef1234567890abcdef12345678",
      "currency": "usdc",
      "chain": "base",
      "enabled": true,
      "createdAt": "2024-01-15T10:30:05.000Z",
      "updatedAt": "2024-01-15T10:30:05.000Z",
      "instructions": "Send USDC to this address to automatically receive funds in your bank account. Minimum: 5 USDC."
    }
  ]
}

{
  "error": "iban: Invalid IBAN format"
}

{
  "error": "Unauthorized - Invalid or missing API key or session"
}

{
  "error": "Customers feature is not enabled for your organization"
}

{
  "error": "Customer not found"
}
{
  "message": "Invalid media type."
}
{
  "error": "Rate limit exceeded. Please try again later."
}

{
  "error": "Internal server error"
}

{
  "error": "The bank account could not be added right now. Please try again."
}

Create customer withdrawal POST

Creates a withdrawal to the customer's registered bank account. **Prerequisites** API withdrawals must be enabled for your organization. If not enabled, this endpoint returns `403 Forbidden`. Contact support to enable API withdrawals. This endpoint requires an API key. Browser-session withdrawals must use the dashboard approval flow. **Execution Modes** 1. **Automatic Execution** (`PROCESSING`) — Withdrawal executes immediately when: - Sufficient available allowance - Sufficient USDC balance in wallet 2. **Manual Approval** (`PROPOSED`) — Transaction created for dashboard approval when: - Withdrawal exceeds available allowance - Insufficient USDC balance in wallet (user can deposit funds before signing) - Automatic execution fails (transaction converted to manual approval) `PROPOSED` is only used when the on-chain allowance module is configured. If API withdrawals are enabled but the module or delegate is not configured on your Safe, or the allowance cannot be read, the request fails with `500` `{"error": "Failed to execute withdrawal"}`. If your organization has no Safe wallet, wallet USDC withdrawals fail with `404` (custodial withdrawals do not need a Safe). `GET /customers/withdrawal/allowance` returns `enabled: false` in these cases. **Custodial Balances** USDT and EURC (and USDC when `source` is `custodial`) are held on the customer's custodial balance rather than the wallet. These withdrawals are debited and paid out immediately (`PROCESSING`) when the organization has custodial balances and API withdrawals enabled. There is no manual-approval fallback: an insufficient custodial balance returns `400`, and a disabled feature returns `403`. **AUD Withdrawals** AUD-only customers withdraw to their AUD withdrawal banks (`paymentRail: "AU_BANK_TRANSFER"`) from the wallet or a custodial balance when AUD functionality is enabled for your organization; the customer does not need to be KYC verified, and the account must be active. The withdrawal stays `PROCESSING` until the bank payment settles. A withdrawal that reached `COMPLETED` can later move to `FAILED` if the receiving bank returns the payment; a `withdrawal.status_changed` webhook is sent. Standard customers cannot withdraw to AUD withdrawal banks, and AUD-only customers still get `400` for EUR and USD accounts. AUD withdrawals are funded with USDC or USDT only: EURC returns `400`, as does an AUD withdrawal bank when AUD functionality is not enabled for your organization. **Amount Specification** Specify the withdrawal amount using one of: - `sourceAmount`: Amount in the source currency to withdraw - `targetAmount`: Amount to receive in the bank's currency The target currency is automatically determined by the withdrawal bank's configured currency. **Idempotency** Use the `idempotencyKey` to safely retry requests. Duplicate requests with the same key return the original transaction without creating a new one. Reusing a key for a different customer returns `409`.

List customer withdrawal banks GET

Returns all withdrawal banks configured for the customer. Only ACTIVE banks can be used for withdrawals.