Funding Accounts

How do I fund an account with fiat?

Learn how to create a transfer on the Cybrid Platform to fund a customer account with fiat currency

Choosing your funding method

There are three different ways to fund an account with fiat currency:

  1. Via a funding transfer from a customer's Plaid connected bank account to the customer's fiat account;
  2. Via a book transfer from the bank's fiat account to the customer's fiat account; or,
  3. Via an ACH, wire transfer, RTP transfer or FedNow transfer to the customer's deposit_bank_account.

Method #1 - Funding from a Plaid-connected account

Creating the quote and transfer

All transfers on the Cybrid Platform first require creating a quote, via the POST /api/quotes endpoint, prior to executing a transfer against via the POST /api/transfers endpoint. Here's an example that creates a funding quote by executing a POST on /api/quotes:

{
  "product_type": "funding",
  "customer_guid": "your-customer-guid",
  "asset": "USD",
  "side": "deposit",
  "receive_amount": 10000
}

❗️

Important: Be careful when entering the receive_amount, as it is in the base units of the currency. In the above example, the base unit of USD is cents, so the value above of 10,000, equates to 10,000 cents, or $100.00 USD. You can always call the /api/assets endpoint to get the number of base decimals in a currency.

In the example above the asset is USD, and you'll set the side to deposit, and the receive_amount to the desired amount. One you've executed the call and have your quote guid, you can proceed to calling the transfers API.

You'll need the customer's external_bank_account_guid for this step in order to create a transfer from the customer's external_bank_account. You can retrieve the guid for an external account by calling the GET /api/external_bank_accounts endpoint, with the customer's guid.

Next, create a transfer by executing a POST on /api/transfers with a transfer_type of funding, and the quote guid and external_bank_account guid.

❗️

Important: If you're using External Bank Accounts with type=plaid, you will be limited to $100.00 funding transfers in the Sandbox environment. You can, however, do an unlimited number of $100.00 transfers.

Here is an example funding transfer:

{
  "quote_guid": "your-quote-guid",
  "transfer_type": "funding",
  "external_bank_account_guid": "your-account-string",
  "payment_rail": "ach",
  "expected_error": "pending" # Only available in Sandbox to simulate errors
}

Payment rails

The Cybrid Platform will default all USD transfers to use same-day ACH, i.e., "payment_rail":"ach", and EFT for all CAD transfers, i.e., "payment_rail":"eft".

Accounts can be funded using other payment rails, see the section Method #3 - Funding via a customer's deposit bank account.

Monitoring for the transfer

Transfers, like many other resources in the Cybrid Platform, are created asynchronously and, therefore, you will need to monitor for the transfer to get to the completed state.

Depending on the payment_rail selected, transfers will take time to enter the completed state in the Production environment. As an example, if you request a transfer with payment_rail=ach at 4pm on a business day, it could be up to 4pm on the next business day before the transfer has completed. The settlement times for transfers are entirely dependent on the payment_rail selected. See https://docs.cybrid.xyz/docs/fiat-settlement for exact settlement time details.

At at any point, you can monitor for the transfer state by querying the GET /api/transfers/{transfer_guid} . Additionally, you can register for webhooks to receive automatic notification on transfer state changes.

Shortly after the transfer is created the state will be pending, but will eventually change to completed when the fiat settles in our bank account.

Cancelling an transfer

Transfers can only be cancelled in the time period between the transfer being posted and the transfer being executed by the bank. This is a very small time window and, currently, we do not provide an API request for our partners to cancel a transfer.

This functionality, however, is available and managed internally by Cybrid. In order to cancel a transfer, please contact us for further assistance.

Handling of errors from Plaid

There are various errors that can occur when attempting to create a funding transfer using an External Bank Account that is of "account_kind": "plaid" or "account_kind": "plaid_processor_token".

The Cybrid Platform makes a best effort to utilize bank accounts connected via Plaid and to inform the caller of any errors or action that they must take for the Plaid-connected account to be used.

Depending on the error received from Plaid, the associated External Bank Account for a transfer can be:

  1. Put into a refresh_required state. This occurs when the customer must re-authenticate to their bank account via Plaid. When this does occur the partner must put their customer through a flow where Plaid Link is initialized in update mode. See the guide Plaid Link Update Mode. The associated External Bank Account cannot be used until the account is re-authorized.
  2. Put into a deleting and eventually deleted state. This occurs when Plaid has lost access to the customer's account completely or the customer has not granted sufficient permissions to Plaid to access their account. When this does occur the partner must instruct the customer to connect a different bank account via Plaid or to grant the required permissions to Plaid while interacting with Plaid Link.

Moreover, when an error is received when a funding transfer is executed, the transfer will have "state":"failed"and the failure_code set on the transfer.

Below is a description of each failure code and and how the caller should handle them, if applicable:

  1. cancelled: The transfer was manually cancelled.
  2. compliance_rejection: The transfer was rejected for compliance reasons
  3. internal_error: An internal error occurred while processing the transfer. The transfer should be attempted again.
  4. limit_exceeded: The customer is over the limits that have been set for them for this activity.
  5. non_sufficient_funds: The customer does not have enough funds to complete the transfer.
  6. party_name_invalid: The transfer's associated external bank account has an invalid party name.
  7. payment_rail_invalid: The payment rail specified for the transfer is not supported by the external bank account.
  8. plaid_access_not_granted: The transfer was rejected due to the external bank account needing to be added again via Plaid with the correct permissions. The external bank account will be put in the state deleted. See the description from Plaid here.
  9. plaid_institution_not_responding: The balance on the customer account could not be retrieved and the transfer should be re-attempted. See the description from Plaid here.
  10. plaid_internal_server_error: The balance on the customer account could not be retrieved and the transfer should be re-attempted. See the description from Plaid here
  11. plaid_item_not_found: The transfer was rejected due to the external bank account needing to be added again via Plaid. The external bank account will be put in the state deleted. See the description from Plaid here.
  12. plaid_item_not_supported: The transfer was rejected because the account is not supported. A different account should be connected via Plaid. The external bank account will be put in the state deleted. See the description from Plaid here.
  13. plaid_multiple_accounts: The transfer was rejected because multiple accounts were selected through Plaid Link. Only one account must be selected. The external bank account will be put in the state deleted.
  14. plaid_no_accounts: The transfer was rejected because no compatible accounts could be found. The external bank account will be put in the state deleted. See the description from Plaid here.
  15. plaid_none_balances_error: The transfer was rejected due to an error with the balances retrieved by Plaid. The transfer should be re-attempted.
  16. plaid_unknown_error: The balance on the customer account could not be retrieved and the transfer should be re-attempted. See the description from Plaid here
  17. refresh_required: The transfer's associated external_bank_account needs to be reconnected via Plaid.
  18. reversed: The transfer was reversed, i.e., there was a return.

Method #2 - Funding via book transfer

Funding via a book transfer is similar to funding from a Plaid connected account, however, the settlement time is significantly reduced as the funds are settled instantly.

Creating the quote and transfer

Funding an account via book transfer involves creating a quote, via the POST /api/quotes endpoint, then executing a transfer against that quote via the POST /api/transfers endpoint.

Create a book transfer quote by executing a POST on /api/quotes:

{
  "product_type": "book_transfer",
  "customer_guid": "your-customer-guid",
  "asset": "USD",
  "side": "deposit",
  "receive_amount": 10000
}

In our example the asset is USD, and you'll set the side to deposit, and the receive_amount to the desired amount. One you've executed the call and have your quote guid, you can proceed to the transfers API.

Create a transfer by executing a POST on /api/transfers endpoint with a transfer_type of funding, and the quote GUID and external_bank_account GUID. It will look like this:

{
"quote_guid": "your-quote-guid",
"transfer_type": "book",
"expected_error": "pending" # Only available in Sandbox to simulate errors
}

Even though book transfers are virtually instant, all transfer calls are executed asynchronously so you will need to monitor the state of the transfer to ensure it gets to completed before attempting to utilize the funds in the customer's fiat account.

Method #3 - Funding via a customer's deposit bank account

Customer's can receive funds directly into their fiat account via their deposit bank account. For details on how to create a deposit bank account, please see this guide.

Customer's can receive funds into their deposit bank account via: ACH push, wire transfer, RTP or FedNow. Any funds sent to a customer's deposit bank account are automatically reconciled to the linked fiat account.

❗️

Important: Deposits less than $0.50 will not be accepted by the platform and will not be returned to the depositor. DO NOT send transfers to deposit bank accounts that are less than $0.50.

When a deposit is reconciled by the Cybrid Platform, the platform_balance in the fiat account will reflect the deposit amount.

Funding via a deposit bank account involves the following steps:

  1. Create a fiat account for the customer or bank
  2. Create a deposit bank account associated with the fiat account
  3. If the deposit bank account is for a bank-level fiat account, provide the deposit bank account account holder details to the Cybrid team: holder name, holder address, email address and phone number. If the deposit bank account is for a customer-level fiat account then this step is not required.
  4. If the deposit bank account is for a bank-level fiat account, wait for the Cybrid team to configure the deposit bank account with the holder details. If the deposit bank account is for a customer-level fiat account then this step is not required and the deposit bank account can be used right away.
  5. Send funds to the deposit bank account using Wire, ACH Push, RTP or FedNow.
  6. Wait for the funds to settle on the Cybrid Platform.

Create a fiat account

To create a USD fiat account, use the POST /api/accounts endpoint.

The following is an example of a request for the POST /api/accounts endpoint:

{
  "type": "fiat",
  "customer_guid": "<insert customer_guid>",
  "asset": "USD",
  "name": "<insert a descriptive account name>"
}

The is the response schema from the above request:

{
  "type": "string",
  "guid": "string",
  "created_at": "2024-06-07T15:17:37.355Z",
  "updated_at": "2024-06-07T15:17:37.355Z",
  "asset": "string",
  "name": "string",
  "bank_guid": "string",
  "customer_guid": "string",
  "platform_balance": 0,
  "platform_available": 0,
  "state": "string",
  "labels": [
    "string"
  ]
}

You'll use the guid from the response above when creating the deposit bank account.

Create a deposit bank account

To create a routable deposit bank account, use the POST /api/deposit_bank_accounts endpoint.

The following is an example of a request for the POST /api/deposit_bank_accounts endpoint:

{
  "type":"main",
  "account_guid": "<insert account_guid>",
  "customer_guid": "<insert customer_guid>"
}

The following is the response schema from the above request:

{
  "guid": "string",
  "type": "string",
  "bank_guid": "string",
  "customer_guid": "string",
  "account_guid": "string",
  "created_at": "2024-06-07T15:17:37.355Z",
  "updated_at": "2024-06-07T15:17:37.355Z",
  "asset": "string",
  "state": "string",
  "unique_memo_id": "string",
  "counterparty_name": "string",
  "counterparty_address": {
    "street": "string",
    "street2": "string",
    "city": "string",
    "subdivision": "string",
    "postal_code": "string",
    "country_code": "string"
  },
  "account_details": [
    {
      "account_number": "string"
    }
  ],
  "routing_details": [
    {
      "routing_number_type": "string",
      "routing_number": "string"
    }
  ],
  "labels": [
    "string"
  ]
}

Provide deposit bank account counterparty details to the Cybrid team (ONLY required for bank-level fiat accounts)

You'll notice that the counterparty_name and counterparty_address returned in this response are placeholder data if the deposit bank account was created from a bank-level fiat account.

When created from a customer-level fiat account, you'll notice the counterparty_name and counterparty_address match the KYC information of the customer.

For bank-level accounts, you'll need to provide the guid from the response above, as well as the following deposit bank account counterparty details to the Cybrid team in your partner channel:

  • Counterparty name
  • Counterparty address:
    • Street
    • Street2
    • City
    • Subdivision (i.e. state/province)
    • Postal code/zip code
    • Country code
  • Counterparty email
  • Counterparty phone

Wait for the Cybrid team to configure the deposit bank account with the counterparty details (ONLY required for bank-level fiat accounts)

After providing the deposit bank account guid and counterparty details to Cybrid team, the Cybrid team will confirm when the configuration of your deposit bank account is complete.

Once the Cybrid team has confirmed the configuration is complete, you may then initiate a transfers to this deposit bank account.

Sending funds to the deposit bank account

To initiate a transfer to the deposit bank account, retrieve the routing details for this deposit bank account using GET /api/deposit_bank_accounts/{deposit_bank_account_guid} endpoint.

❗️

Important: As a reminder, deposits less than $0.50 will not be accepted by the platform and will not be returned to the depositor. DO NOT send wires or ACHs to deposit bank accounts that are less than $0.50.

When the funds are received by the Cybrid Platform and reconciled, a new funding deposit transfer will be automatically created. This funding deposit transfer will progress through the typical sequence of states (i.e. pending, completed).

As with all transfers, you can use the GET /api/transfers/{transfer_guid} endpoint to retrieve the details of the transfer or you can register for webhooks.