GuidesRecipesAPI ReferenceChangelog
Guides

Transfer Process

Understand fiat and crypto transfer types, lifecycle states, and how transfers fit into the Cybrid trading flow.

Overview

The Cybrid platform enables fund transfers for both fiat currencies (USD, CAD) and cryptocurrencies (BTC, USDC) through the transfers endpoints.

Transfer types

TypeDescription
FundingFiat deposits and withdrawals to Plaid-connected bank accounts via EFT or ACH.
BookInternal transfers between accounts on the platform. Typically used with a pre-funded account model. See Trade Process for details.
CryptoCrypto withdrawals to pre-registered external wallets. Crypto deposits are not initiated from Cybrid, but transfers are created to record incoming deposits.

Where transfers fit in

Transfers bookend the trading activity on the platform. Transfers follow this flow:

Diagram showing the transfer flow: fund fiat account, trade, then withdraw crypto
⚠️

Compliance routing requirement

For compliance tracking, transfers from a customer's external bank account to a business or partner (bank) fiat account must first be routed through the customer's fiat account on Cybrid. Direct transfers from a customer's external bank account to a business/partner fiat account are not supported.

Transfer states

After creating a transfer via POST /api/transfers, it progresses through these states:

  1. storingreviewing — immediate transition after creation.
  2. reviewingpending — the payment processor completes initial processing (typically a few minutes).
  3. pendingcompleted or failed — the payment processor finishes processing the transfer.
ℹ️

Compliance review

If a transfer is flagged for compliance review, it remains in reviewing until the review completes, then transitions directly to completed or failed.

When a transfer reaches failed, the failure_code field contains the reason for failure.

ACH returns

ACH transfers may be returned by the customer's bank after processing. How Cybrid handles the return depends on when it occurs relative to the transfer's holding period:

  • Within the holding period: If the bank initiates a return while the transfer is still in the holding state, the original transfer transitions to failed.
  • After the holding period: If the bank returns a transfer that has already reached completed, the original transfer's state remains completed. A return_code is added to the transfer record, and Cybrid automatically creates a new funding_return transfer to reconcile the returned funds.

ACH return codes and troubleshooting

When a funding transfer is returned, the API response may include a return_code field. For ACH transfers, these codes follow the NACHA standard. For example, an R01 return code indicates "Insufficient Funds" in the source bank account.

Common ACH return codes:

CodeNameDescription
R01Insufficient FundsThe available balance is not sufficient to cover the debit entry.
R02Account ClosedA previously active account has been closed by action of the customer or the RDFI.
R03No Account/Unable to Locate AccountThe account number structure is valid, but does not correspond to the individual identified in the entry.

Troubleshooting steps:

  • Check the return_code in the transfer details for the specific reason.
  • For R01 (Insufficient Funds), verify the balance in the linked external bank account.
  • For other codes, refer to the NACHA ACH return code documentation or contact support for further assistance.
  • Include all required participant information in the API request.
  • If the error relates to Plaid or bank connectivity, try reconnecting the bank account.

Transfer limits and failure reasons

All transfers are subject to transaction limits that may vary by payment rail. For example, the default ACH rail may have a per-transfer limit (e.g., $6,000). Transfers above this limit fail. To resolve, either:

  • Break the transfer into smaller amounts within the limit (e.g., three transfers of $6,000, $6,000, and $3,000 for a $15,000 total), or
  • Use a different payment rail such as wire by setting "payment_rail": "wire" in your request.

Other common failure reasons include insufficient funds or exceeding a customer's transaction limits. You can check a customer's current limits and transaction history using the Get Customer and List Transfers endpoints.