Changelog

Track API and documentation updates, including new features, behavior changes, and fixes.

2026-10-28

  • For organizations where verification links are unavailable, POST /customers/{customerId}/kyc returns 400 (A verification link is not available for this customer. Contact support for help.) for AUD-only customers. These customers stay unverified; AUD withdrawals do not need KYC. Standard customers are not affected.

2026-10-27

  • AUD withdrawals are available to organizations with AUD functionality enabled; AUD-only customers do not need KYC to be paid out.
  • POST /customers/{customerId}/withdrawal/banks accepts AUD withdrawal banks for AUD-only customers when AUD functionality is enabled for your organization (otherwise 400): currency: "AUD", paymentRail: "AU_BANK_TRANSFER", bsb (6 digits), accountNumber (1–9 digits, leading zeros kept), the payee's firstName, lastName and dateOfBirth, and the full address. The customer does not need to be KYC verified. The payee is an individual: CUSTOMER and OTHER_INDIVIDUAL are active immediately, and OTHER_BUSINESS returns 400. Standard customers get 400 for AUD withdrawal banks, and AUD-only customers still get 400 for EUR and USD accounts. It returns 502 when the account cannot be added right now; nothing is saved, so the same request can be retried unless the error says to contact support. AUD withdrawal banks get their withdrawal wallet with their first withdrawal from the wallet (until then wallets is empty); USDC sent to it is paid to the account in AUD at the current rate and fees, like other withdrawal wallets. AUD withdrawal banks report fundingSource: "VIRTUAL_ACCOUNT": payments to them are sent on behalf of the customer.
  • GET /customers/{customerId}/withdrawal/banks lists an AUD-only customer's AUD withdrawal banks (with bsb, accountNumber, firstName and lastName) when AUD functionality is enabled for your organization; otherwise the list stays empty. Withdrawal transactions to an AUD withdrawal bank show the same bsb, accountNumber, firstName and lastName in withdrawalBank.
  • POST /customers/{customerId}/withdrawal pays an AUD-only customer's active AUD withdrawal bank when AUD functionality is enabled for your organization (otherwise 400), from the wallet (USDC) or a custodial balance (USDC or USDT; EURC returns 400). The customer does not need to be KYC verified; a withdrawal bank that is not active returns 404. The withdrawal stays PROCESSING until the bank payment settles, then sends withdrawal.status_changed (COMPLETED, or FAILED if the bank payment fails or is returned). A withdrawal that reached COMPLETED can later move to FAILED if the receiving bank returns the payment, with another withdrawal.status_changed. Standard customers get 400 for AUD withdrawal banks, and AUD-only customers still get 400 for EUR and USD accounts. Withdrawal transactions to an AUD withdrawal bank report paymentRail: "AU_BANK_TRANSFER". It returns 503 if the AUD exchange rate is temporarily unavailable; nothing is created, retry shortly.
  • GET /rates quotes USDC->AUD and USDT->AUD on AU_BANK_TRANSFER when AUD functionality is enabled for your organization (otherwise 400), including for an AUD-only customer_id; a standard customer_id returns 400, as AUD withdrawal banks are for AUD-only customers. Any other payment_rail with AUD, or AU_BANK_TRANSFER with another currency, returns 400. AUD-only customers still get 400 for other targets.

2026-10-26

  • AUD payments (paymentRail: "AU_BANK_TRANSFER") from GET /customers/{customerId}/transactions and /transactions/{transactionId} now report fee: the flat AUD fee charged on the payment, null until the payment converts. exchangeRate is now the USDC received per AUD after that fee, rounded to 6 decimal places, so targetAmount ≈ (sourceAmount − fee) × exchangeRate. Earlier payments report the same fee and rate. developerFee stays null.

2026-10-25

  • AUD-only customers. POST /customers accepts product: "aud_only" for individuals when AUD functionality is enabled for your organization (otherwise 403; a corporate accountType returns 400). aud_only requires the customer's email (a missing one returns 400). It may be replaced after KYC approval by the email the customer verified. GET /customers and GET /customers/{customerId} return product (standard or aud_only), and banking.supportedFiatCurrencies is ["AUD"] for AUD-only customers. For AUD-only customers, address is the residential address they entered during KYC, with any unit leading addressLine1, and null for those who get a new kycFlowLink on every call.
  • GET /customers/{customerId}/deposit?currency=aud (or paymentRail=AU_BANK_TRANSFER) returns an AUD-only customer's AUD deposit details, which give the BSB and account number, with paymentRail: "AU_BANK_TRANSFER". It returns 409 while the customer's AUD account is being set up after KYC approval; poll the deposit endpoint until it stops returning 409. It also returns 409 once the account is closed or being closed (payers should stop sending to it; a payment sent before the closure completes may still arrive), and when the account was never set up and AUD functionality is no longer enabled for your organization (stop polling and contact support). One set of details accepts NPP/Osko and BECS transfers, and the scheme is not reported per transaction. AUD converts to USDC on Base and is sent to your organization's embedded wallet. Requesting AUD for a standard customer returns 400. It can return 502 when AUD deposit details are temporarily unavailable.
  • GET /customers/{customerId}/transactions and /transactions/{transactionId} return an AUD-only customer's AUD payments as DEPOSIT transactions with paymentRail: "AU_BANK_TRANSFER" and a new payerName field (the name on the paying bank account). Payments on hold, and returns still in flight, report PROCESSING; a returned payment reports REVERSED once the return settles, and one returned after it completed keeps its completedAt. In the deposit response schema these are the AU_BANK_TRANSFER variant, where reference, fee, depositInstructions and developerFee are always null, and exchangeRate is the USDC received per AUD, to 4 decimal places.
  • EUR/USD deposit details, creating or changing virtual accounts, deposit wallets and withdrawal banks, withdrawals, developer fees, GET /rates with an AUD-only customer_id, POST /customers/{customerId}/kyc/submit, GET /customers/{customerId}/kyc/address and POST /customers/{customerId}/documents return 400 with Not available for AUD-only customers for AUD-only customers. Listing an AUD-only customer's virtual accounts, deposit wallets or withdrawal banks returns an empty list, and looking one up returns 404.
  • Some AUD-only customers get a new kycFlowLink on every call to POST /customers/{customerId}/kyc; call it again whenever you send them a link. It returns 400 once such a customer is verified or their verification is rejected, and GET /customers/{customerId} reports their progress in kyc.stepsStatus with empty steps.
  • POST /customers/{customerId}/kyc returns 400 (Customer is already KYC verified) for an already verified customer with no verification to link to, for organizations that receive a Sumsub WebSDK link, instead of starting a new verification.
  • AUD-only customers' AUD payments send deposit.created and deposit.status_changed webhooks like other deposits.
  • AUD-only customers who get a new kycFlowLink on every call send the same customer.kyc.submitted, customer.kyc.approved and customer.kyc.rejected webhooks as other customers; customer.kyc.submitted is sent when their first KYC link is generated, and again when they continue after being asked for more information.
  • POST /customers/{customerId}/kyc returns 400 for an AUD-only customer who gets a new kycFlowLink on every call when the customer is disabled or closed, or has not started verifying while AUD functionality is not enabled for your organization.

2026-10-21

  • POST /customers/kyc-share carries a selfie over only when your Sumsub level records it as a short video (your level's configuration, not each customer's recording). Otherwise reuse.steps.selfie is to_do and the customer records it through kycFlowLink.
  • POST /customers/kyc-share now usually recognises a customer already imported to your organization from the same applicant in your Sumsub account, and returns 409 DUPLICATE_CUSTOMER with existingCustomerId. If that earlier import isn't finished, the request finishes it instead.
  • POST /customers/kyc-share dry-run responses include freshSelfieRequired.

2026-10-18

  • Customer withdrawals through this endpoint now require an API key. Dashboard withdrawals continue to use passkey approval.

2026-10-09

  • Too many authentication attempts now return 429 with a Retry-After header instead of 401. Wait the indicated number of seconds and retry; a 429 does not mean the API key is invalid. All other authentication failures still return 401.

2026-10-08

  • New POST /customers/kyc-share creates a customer from a Sumsub share token. Verification steps the customer already completed carry over, and the response's kycFlowLink lets the customer finish the rest. idempotencyKey is required unless dryRun is set; reuse it on retries so they return the same customer. Set dryRun to check a token without using it. Errors include a machine-readable code. Returns 403 when share-token imports are not enabled for your organization.
  • GET /customers/{customerId} now returns kyc.onboardedViaKycShare, true for customers created from a Sumsub share token once the import finished.
  • POST /customers/{customerId}/kyc can return 400 while that customer's share-token import is still being finished, for organizations using Sumsub-hosted verification links.

2026-10-07

  • POST /customers/{customerId}/kyc can return a Sumsub-hosted kycFlowLink for organizations set up for Sumsub-hosted verification links. That link expires after 7 days; call the endpoint again to get a fresh link for the same verification. For these organizations, a verified customer receives a link to their completed verification, and the endpoint returns 400 when that is unavailable or when the customer's identity matches an already verified identity.

2026-09-15

  • GET /deposit-addresses returns available custodial deposit destinations, with standard checksum formatting for EVM addresses. Use the returned destinations to determine which deposit routes to display.

2026-09-11

  • GET /deposit-addresses continues to return available custodial deposit destinations when a self-custody wallet is unavailable.

2026-09-03

  • Virtual accounts can now be closed. GET /customers/{customerId}/virtual-account and GET /customers/{customerId}/virtual-accounts return a new terminal status CLOSED with a closedAt timestamp; a closed account returns no virtualAccount bank details. Money that still arrives on that IBAN is booked to the same owner. Update any integration that treats APPROVED as final.
  • New webhook virtual_account.closed, sent when a customer's virtual account is closed. Payload: virtualAccountId, customerId, currency, status (CLOSED), closedAt.
  • POST /customers/{customerId}/virtual-account now returns 409 when a previous virtual account for that currency was closed. A replacement cannot be requested through the API; contact support.
  • Shared EUR and USD deposit accountAddress now includes the full postal code (V6A 1A4).

2026-08-28

  • Custodial EURC balances can now receive supported on-chain EURC deposits and be withdrawn to supported EUR or USD bank accounts.
  • GET /rates now supports EURC -> USD indicative withdrawal quotes.

2026-08-21

  • Deposits gain a new terminal status REVERSED, returned by transaction endpoints and in deposit.status_changed webhooks when a deposit is returned to the sender's bank account. While a return is in flight the deposit reports PROCESSING — including on deposits that previously reported COMPLETED — before settling at REVERSED. Update any integration that treats COMPLETED as unconditionally final.

2026-08-18

  • Custodial stablecoin balances: organizations can now hold USDT (received on Ethereum, Tron or Solana) and USDC (received on Ethereum, Arbitrum or Solana) as a custodial balance, credited when the deposit is allocated by Compose. Received balances are held at the organization level and can be paid out to customers' bank accounts through the withdrawal endpoint below.
  • POST /customers/{customerId}/withdrawal accepts sourceCurrency values USDT and EURC in addition to USDC, and a new optional source field (wallet | custodial) to withdraw USDC held on the custodial balance. Custodial withdrawals are debited and paid out immediately (PROCESSING) when custodial balances and API withdrawals are enabled for your organization; they return 400 for an insufficient balance and 403 when the feature is not enabled. sourceAmount is now denominated in the chosen source currency.
  • GET /rates accepts USDT as a source currency for USDT -> EUR and USDT -> USD, and now also supports USDC -> USD. USDT rates are withdrawal-only.

2026-08-13

  • Customer deposit wallets accept an ownership declaration: walletType (SELF_CUSTODY or CUSTODIAL) and ownershipAttested: true, plus vaspName and optional vaspAccountRef for custodial wallets. These fields are optional today and will become required in a future release — start sending them now to avoid a breaking change later.
  • When you supply walletType, ownershipAttested: true is required, and custodial wallets also require vaspName. Omitting the declaration on an update leaves any existing declaration unchanged, except when you change the wallet address: a declaration covers the address it was made about, so changing the address without supplying a new declaration clears walletType, vaspName, vaspAccountRef and ownershipAttestedAt. Send the declaration alongside the new address to keep the wallet declared.
  • Wallet responses now include walletType, vaspName, vaspAccountRef and ownershipAttestedAt. They are null on wallets with no declaration on file. Existing wallets continue to receive deposits without this information.

2026-08-04

  • Withdrawal bank create and list responses now include postalCode. It is null when no postal code is on file for that beneficiary yet.
  • Creating a withdrawal bank now requires postalCode whenever you send an address: always for OTHER_INDIVIDUAL and OTHER_BUSINESS recipients, and for CUSTOMER recipients if you supply addressLine1 or city. Omit those fields to keep resolving the address from the customer's verified address.
  • Note that country is unchanged — it is still resolved from verified data when omitted, and sending country on its own does not require a postalCode.

2026-08-01

  • GET /customers/{customerId} now returns a banking object describing what that customer can transact in: supportedFiatCurrencies and whether a dedicated virtual account is available to them. Use it instead of assuming every customer in your organization supports the same currencies.

2026-07-30

  • POST /customers/{customerId}/withdrawal now returns 400 when the selected withdrawal bank's currency is unavailable for your organization, instead of failing later in processing.
  • POST /customers/{customerId}/virtual-account now returns customer-specific 403 wording when virtual accounts are unavailable for that customer.
  • Deposit details, rate availability, and withdrawal bank availability now use the banking configuration effective for the requested customer.

2026-07-29

  • POST /customers/{customerId}/virtual-account now returns 403 when virtual accounts are unavailable for your organization.
  • GET /customers/{customerId}/deposit now returns 404 when EUR deposit details are unavailable for your organization, matching the existing USD behavior.

2026-07-28

  • Corporate customers who request a KYC link are now directed to [email protected] to complete onboarding.

2026-07-23

  • Customer deposit details: EUR/SEPA responses may reference a different receiving bank (for example PayDo EU Ltd. in Malta) depending on your organization's banking configuration. USD deposit details continue to return 404 when USD is not available for your organization.
  • GET /rates: requests for a USD rate now return 400 "USD is not available for your organization" when USD is not offered for your organization.
  • POST /customers/{customerId}/withdrawal/banks: now returns 400 when a withdrawal bank is created in a currency that is not available for your organization.

2026-07-13

  • Withdrawal bank list and create responses now include fundingSource, indicating whether withdrawals are expected to use a customer virtual account or the Compose shared account.

2026-07-09

  • USD FedWire deposit details now include the beneficiary bank BIC in addition to account and routing numbers.
  • USD SWIFT deposit details now include the ClearBank IBAN on shared reference account responses.
  • USD SWIFT deposit details now identify the ClearBank account with iban instead of also duplicating that value in accountNumber.

2026-07-07

  • Added Wallets and Allowance guides to Getting Started, and clarified that GET /customers/withdrawal/allowance returns 200 with { "enabled": false, "allowance": null } when API withdrawals are unavailable.

2026-07-03

  • USD SWIFT deposit details now return a dedicated iban and depositModel: "virtual_account" when the customer has an active USD virtual account; otherwise the shared reference account is returned with depositModel: "reference".

2026-07-02

  • expectedMonthlyVolume on customer create is deprecated for KYC routing: all new customers now start basic KYC and enter their expected volume during the verification flow.
  • Optional email on customer create is deprecated but remains accepted and stored on the customer record. Email for KYC verification is collected during the verification flow.

2026-07-01

  • POST /customers/{customerId}/documents now accepts DRIVERS (driver's license) and RESIDENCE_PERMIT (residence permit) as idDocType values, in addition to PASSPORT, ID_CARD, and PROOF_OF_ADDRESS.
  • Verification links returned by POST /customers/{customerId}/kyc are now referred to as "KYC flow links".
  • Deprecated legacy KYC levels (customers-flow, customers-ui-flow, customers-ui-flow-enhanced, customers-api-basic, customers-api-enhanced). Existing customers on these levels are unaffected.
  • Customers with an EU/EEA proof of address now complete an additional EU declaration step, surfaced as an extra questionnaire step in kyc.steps.

2026-06-29

  • When the verification link (kycFlowLink) is embedded in an iframe, the page now forwards Sumsub verification events to the parent window via window.postMessage (idCheck.onApplicantSubmitted, idCheck.onApplicantStatusChanged, and idCheck.onError), so your UI can detect submission, approval, rejection, and errors. See "Detecting events in an iframe" in the integration guide.

2026-06-27

  • POST /customers/{customerId}/kyc now returns the stable Compose-hosted verification link for hosted customer verification, including customers with an existing applicant record.

2026-06-26

  • POST /customers/{customerId}/kyc now continues returning a Sumsub WebSDK link for existing customers with an in-progress legacy verification, while new customers receive the hosted Compose verification link when available.

2026-06-19

  • POST /customers/{customerId}/virtual-account now supports corporate customers via API key. Corporate customers must have KYC approved and a complete business address and registration number on file before creation. Contact support if onboarding is incomplete.
  • POST /customers/{customerId}/documents no longer accepts DRIVERS (driver's license) or RESIDENCE_PERMIT (residence permit) as idDocType values. The accepted values are now PASSPORT, ID_CARD, and PROOF_OF_ADDRESS. Requests using the removed types will receive a 400 response.

2026-06-07

  • GET /customers/{customerId} now includes an identity object with nationality, countryOfResidence, and dateOfBirth (ISO YYYY-MM-DD) for licensed organizations.

2026-06-01

  • POST /customers/{customerId}/kyc now returns a stable Compose-hosted verification link (https://www.auth.compose.finance/en/signup?c={customerId}) instead of a time-limited Sumsub WebSDK URL.

2026-05-28

  • Fiat deposit, withdrawal bank, and transaction payloads are keyed by paymentRail (SEPA, FEDWIRE, SWIFT) rather than currency alone. Each response variant includes only the bank identifiers for that rail: SEPA uses iban and bic; Fedwire uses accountNumber and routingNumber; SWIFT uses accountNumber, bic, and beneficiary bank details (bankName, bankAddress, bankCountry where applicable).
  • USD SWIFT is supported end to end. GET /customers/{customerId}/deposit can return SWIFT deposit instructions (account number and BIC). Create USD withdrawal banks with paymentRail: "SWIFT"; bankName, bankAddress, and bankCountry are required. You may pass an IBAN in accountNumber for SWIFT banks.
  • POST /customers/{customerId}/withdrawal/banks requires currency (EUR or USD) and paymentRail. Existing integrations that send only currency continue to work and receive the default rail for that currency (EUR → SEPA, USD → FEDWIRE).
  • GET /customers/{customerId}/deposit accepts paymentRail as the primary query parameter. The currency parameter remains supported and selects the default rail when paymentRail is omitted.
  • GET /customers/{customerId}/transactions and GET /customers/{customerId}/transactions/{transactionId} include paymentRail on each transaction. For withdrawals, rail-specific bank fields are on the nested withdrawalBank object.
  • GET /rates accepts optional payment_rail (SEPA, FEDWIRE, or SWIFT) so USD quotes can use Fedwire or SWIFT fee rules. Responses include payment_rail for the rail used in the quote (your request value or the currency default).

2026-05-24

  • GET /rates responses may now include an optional developer_fee object (amount, currency, developerSpreadFeeBps) when quoting a fiat-to-crypto deposit with customer_id and the customer has an enabled deposit wallet with a spread fee configured. Platform fees remain in fee / fee_currency; quote amounts are unchanged.

2026-05-18

  • GET /rates now accepts an optional deposit_model query parameter (REFERENCE or VIRTUAL_ACCOUNT, case-insensitive). When omitted, the cheapest available deposit channel is selected automatically so the quote matches the price you will actually pay. Ignored for withdrawals.

2026-05-15

  • POST /customers now accepts both individual and corporate values for accountType.
  • Corporate customers requesting a KYC link now receive guidance that onboarding will be completed by email.
  • Added kyc.rejection object to GET /customers/{customerId} response. Populated with rejectLabels[] and reviewRejectType (FINAL or RETRY) when the customer is currently in a rejected KYC state; null otherwise.
  • GET /customers/{customerId} may now include an optional kyc.rejection.clientComment string with a human-readable rejection reason when the verification provider supplied one.

2026-04-29

  • Added USD rails across customer deposit and withdrawal APIs.
  • GET /customers/{customerId}/deposit now supports both currency=eur and currency=usd. EUR responses include iban/bic; USD responses include FedWire accountNumber/routingNumber.
  • POST /customers/{customerId}/withdrawal/banks now accepts currency-specific bank details: EUR uses iban/bic, while USD uses accountNumber/routingNumber. GET /customers/{customerId}/withdrawal/banks returns the same currency-specific format.
  • Withdrawal responses from POST /customers/{customerId}/withdrawal, GET /customers/{customerId}/transactions, and GET /customers/{customerId}/transactions/{transactionId} now return withdrawalBank details in the correct format for the withdrawal currency (EUR or USD).
  • GET /rates now supports USD quotes for the USD->USDC pair.

2026-03-17

  • Added GET /api/v2/rates endpoint for indicative exchange rate quotes. Returns a stateless quote for fiat↔crypto currency pairs (EUR ↔ USDC, EURC) including fees.
  • source_currency and target_currency query parameters on GET /api/v2/rates are case-insensitive
  • exchangeRate description on deposit, withdrawal, and rate quote responses now clarifies the formula: targetAmount = sourceAmount × exchangeRate (before fees)

2026-03-12

  • POST /customers/{customerId}/documents and POST /customers/{customerId}/kyc/submit now return 403 when manual KYC upload is unavailable for your organization.

2026-03-09

  • Added reference field to deposit and withdrawal transaction responses. For deposits, this is the inbound bank reference included in the transfer. For withdrawals, this is the reference included in the outbound bank transfer (transaction id).

2026-03-04

  • Added GET /balances endpoint to retrieve custodial and non-custodial (Safe wallet) balances for your organization, including availableBalance and lockedBalance
  • Added nullable address object (addressLine1, city, country) to GET /customers/{customerId} response. Returns verified address from KYC or stored metadata when available, null otherwise.
  • Added optional country field to POST /customers/{customerId}/withdrawal/banks request body (ISO 3166-1 alpha-2 code). Auto-resolved from KYC/metadata for CUSTOMER recipients; required explicitly for OTHER_INDIVIDUAL and OTHER_BUSINESS. Returns 400 if address cannot be resolved.
  • Standardized error response descriptions and examples for 401, 403, and 500 across all endpoints
  • Renamed currencyTicker to currency (lowercased) in GET /developer-fees response
  • sourceCurrency in POST /customers/{customerId}/withdrawal is now case-insensitive
  • accountType in POST /customers is now case-insensitive
  • recipientType in POST /customers/{customerId}/withdrawal/banks is now case-insensitive

2026-02-25

  • Added addressLine1, city, and country to GET /customers/{customerId}/withdrawal/banks responses

2026-02-24

  • Renamed ticker to currency across deposit wallet request/response payloads (/customers/{customerId}/deposit/wallets and /customers/{customerId}/deposit/wallets/{walletId})
  • Renamed deposit wallet filter query parameter ticker to currency on GET /customers/{customerId}/deposit/wallets
  • Renamed withdrawal bank wallet field ticker to currency in GET /customers/{customerId}/withdrawal/banks and POST /customers/{customerId}/withdrawal/banks responses

2026-02-23

  • Added wallets to GET /customers/{customerId}/withdrawal/banks and POST /customers/{customerId}/withdrawal/banks responses
  • POST /customers/{customerId}/withdrawal/banks now auto-creates a linked withdrawal wallet and returns it when successful

2026-02-20

  • Added GET /customers/{customerId}/kyc/address endpoint to retrieve a customer's verified address
  • Made addressLine1 and city optional for CUSTOMER recipient type — address is auto-resolved from KYC data when not provided
  • Changed recipientType enum values from MYSELF/INDIVIDUAL/BUSINESS to CUSTOMER/OTHER_INDIVIDUAL/OTHER_BUSINESS

2026-02-19

  • Added isThirdParty field to withdrawal bank responses
  • Third-party withdrawal banks now require approval (PENDING_APPROVAL status)

On this page