FAQ

What are the most common questions about the Cybrid platform?

Authentication

What is the difference between Bank and Organization credentials?

Bank credentials (client_id / client_secret) call Bank-level APIs (customers, transfers, trades, accounts, etc.). Organization credentials call the Organization service, which handles webhook subscriptions. Using Bank keys for subscription endpoints returns an error because Bank keys cannot have subscription scopes. For more information, see the API keys and token scopes guides.

What is the TTL for access tokens?

Access tokens are valid for 30 minutes in the production environment and 8 hours in the sandbox environment. For details on generating tokens, see the API keys guide.

What are the rate limits on the OAuth token endpoint?

/oauth/token is limited to 20 requests per IP per 5 minutes. /api/customer_tokens is limited to 200 requests per IP per 5 minutes. These limits are enforced at the infrastructure level and may change.

What scopes should I use when authenticating against the Bank Swagger UI?

Use only Bank-level scopes. Do not include subscription or organization scopes for Bank authentication. Recommended scopes:

banks:read banks:write
accounts:read accounts:execute
customers:read customers:write customers:execute
prices:read
quotes:execute quotes:read
trades:execute trades:read
transfers:execute transfers:read transfers:write
external_bank_accounts:read external_bank_accounts:write external_bank_accounts:execute
external_wallets:read external_wallets:execute
workflows:read workflows:execute
deposit_addresses:read deposit_addresses:execute
deposit_bank_accounts:read deposit_bank_accounts:execute
identity_verifications:read identity_verifications:write identity_verifications:execute

For a complete list of available scopes, see the token scopes guide.

Are Cybrid POST API calls synchronous or asynchronous?

All POST API calls are asynchronous. The API returns a response with the resource in a storing state, but creation may still be processing. Poll the resource or use webhooks to confirm the resource reaches a terminal state. For webhook setup, see the webhooks guide.

Identity Verifications

Is permanent residence in the US or Canada required for KYC?

Yes, permanent residence in the US or Canada is required for Cybrid KYC.

What are the allowable countries for government ID?

The allowable countries for government ID are the US and Canada.

Which forms of government ID are accepted?

The following government IDs are accepted:

  • Passport
  • Passport card
  • Driver's license
  • State ID
  • Permanent resident card
  • Visa
  • Work permit
What is the minimum age for identity verification?

The minimum age for partner end-users is 18 years old.

How long does KYC take in production?

KYC using id_and_selfie typically completes within a few minutes if automated checks pass. If the verification enters reviewing, it may take up to 2 business days due to manual compliance review. The SLA targets are documented in the compliance review targets guide.

What are the main states an identity verification goes through?

storingwaiting (customer has not started) → pending (customer has started but not finished) → reviewing (requires manual compliance review) or completed (with outcome: passed or outcome: failed). A verification that has not started moves to expired after a timeout period controlled by the identity verification provider. For the full verification workflow, see the verifying a customer guide.

What happens if a customer's KYC is rejected?

The customer state becomes rejected and new identity verifications cannot be created. To allow a retry, open a Zendesk ticket and ask the Compliance team to reset the customer state to unverified. This process is intentional fraud prevention. For more details, see the verifying a customer guide.

How many KYC attempts can a customer make before requiring Compliance intervention?

A customer can retry as many times as needed while their state is not rejected. Once they reach rejected, a Zendesk ticket is required to reset their state to unverified.

Does the platform allow repeat identity verifications?

Yes, repeat identity verifications are allowed as long as the same customer account is used. If a new customer account is created for the same individual and a new identity verification is performed, the identity verification is flagged as a repeat and auto-denied.

What are the expirations of the various identity verification types?

The following are the identity verification expirations:

  • Individual customer KYC (type: kyc, method: id_and_selfie): 60 minutes
  • Business customer KYB (type: kyc, method: business_registration): 14 days

For details on handling expired inquiries, see the Persona inquiry expiry guide.

How do I simulate a KYC failure in sandbox?

Pass "expected_behaviours": ["failed_immediately"] in the POST /api/identity_verifications body to produce a rejected customer state with outcome: failed. Use "passed_immediately" to pass instantly. For other sandbox-specific behaviors, see the sandbox environment differences guide.

What causes a KYC to enter the `reviewing` state?

Common reasons include selfie_quality_check_failure, selfie_pose_check_failure, id_quality_check_failure, id_expiration_check_failure, name_check_failure, address_check_failure, and id_country_allowed_check_failure. Other possible reasons include id_check_failure, id_mrz_check_failure, id_barcode_check_failure, database_check_failure, pep_check_failure, watchlist_check_failure, duplicate_person_check_failure, dob_check_failure, phone_number_check_failure, email_address_check_failure, banned_ip_address_check_failure, and others. Customers aged over 70 also go to reviewing for additional fraud checks.

What do `address_check_failure` and `database_check_failure` mean when KYC fails?

The customer failed the database check on the address after they were prompted to submit a supporting document. The address on the provided document does not match the address the customer entered.

What does it mean if a bank IDV has `name_check_failure` or `address_check_failure` but is in the `reviewing` state?

The bank account remains in reviewing because it is undergoing manual compliance review. Typically, the bank verification moves to completed with outcome: failed, unless the customer is prompted to provide additional documents. Once all information is provided, it moves to completed with outcome: failed, or expired if the customer does not complete the process in 60 minutes.

How long does a customer's `verified` status remain valid?

It remains valid as long as the underlying compliance decisions are not expired or invalidated, and the government-issued ID used for KYC is not expired. When the ID expires, the customer state automatically moves to unverified, requiring re-verification.

Can a verified customer go to `frozen`?

Yes. A customer can go to frozen due to security concerns (such as suspicious activity) or a negative balance caused by an ACH return. There is no webhook for customer state changes yet (planned for later); use polling via GET /api/customers/{customer_guid}. See the creating a customer guide for customer state details.

How do I integrate Persona for Flutter or Android apps?

Most partners run the Persona JS SDK inside a WebView, binding the inquiryId (not a templateId). For Android OAuth redirect flows using plaid_flutter, register your Android package name (such as com.yourapp.app) via Cybrid support and pass it in the Plaid workflow request instead of a redirect URI. See the Persona theming and resume Persona inquiry session guides.

Can I create a `tax_id_and_selfie` identity verification before the customer completes `id_and_selfie`?

No. The customer must first complete id_and_selfie and reach verified state. Attempting to create an identity verification with "method": "tax_id_and_selfie" for an unverified customer returns a 422 error with message code unverified_customer. For the SSN/SIN capture workflow, see the capturing SSN/SIN guide.

How do I generate a document submission link for a customer?

Create an identity verification with "method": "document_submission": POST /api/identity_verifications with {"type": "kyc", "method": "document_submission", "customer_guid": "customer_guid"}. This generates a Persona link for the customer to upload documents. For the full workflow, see the document submission guide.

How do I access customer KYC documents and PII via the API?

Add the files:pii:read scope to your API credentials. Call GET /api/identity_verifications/{identity_verification_guid}?include_pii=true to retrieve PII data. Associated document files are accessible through the API or the Partner Portal Documents tab. For more details, see the PII and IDV documents guide.

Why doesn't `include_pii=true` return PII data in production?

Your access token must include the customers:pii:read scope. Without this scope, the API returns the customer record but omits PII fields such as name, address, date of birth, phone number, and email. Add this scope when generating your bank token via POST /oauth/token. See the token scopes and PII and IDV documents guides.

How do I initiate Enhanced Due Diligence (EDD) via the API?

Create an identity verification with "method": "enhanced_due_diligence": POST /api/identity_verifications with {"type": "kyc", "method": "enhanced_due_diligence", "customer_guid": "customer_guid"}. Use the returned persona_inquiry_id to launch the Persona EDD questionnaire. Monitor the identity_verification.completed webhook, then poll GET /api/customers/{customer_guid} to confirm updated activity_limits. For the full EDD workflow, see the enhanced due diligence guide.

How long is an EDD Persona link valid?

The EDD link is valid for 14 days. If a customer starts the Persona flow and abandons it, they cannot resume and see an "expired" screen on return. Create a new EDD identity verification in this case. See the enhanced due diligence and Persona inquiry expiry guides.

Is EDD per transaction or per account?

EDD is per account. When approved, all of the customer's activity limits increase across trades, book transfers, crypto transfers, and funding. EDD limits are valid for 7 days from approval. After expiration, limits revert to the customer's defaults. A new EDD overwrites any previous EDD limits and resets the 7-day window.

Can I change a customer's type from `business` to `individual` or vice versa?

No. The customer type is set at creation via POST /api/customers and cannot be changed. Create a new customer and complete a new KYC/KYB process to switch types. See the creating a customer guide.

How long does KYB verification take?

The standard SLA is 5 business days from when the KYB reaches reviewing state. Raise a Zendesk ticket if the SLA is exceeded. For the full KYB workflow, see the KYB guide.

What triggers the 5-business-day KYB review clock?

The clock starts when the identity verification state updates to reviewing, meaning all business information and associated UBO information has been collected and UBOs have completed their KYC.

Do UBO (Ultimate Beneficial Owner) individuals receive their KYC link automatically?

Yes. Once a KYB is submitted, UBOs are automatically sent an email with a Persona inquiry link. You can also retrieve the inquiry IDs via the API and share them manually.

Can a partner add themselves (their own business entity) as a business customer?

No. Cybrid's Compliance team declines identity verifications where a partner attempts to onboard itself as a business customer.

What documents are accepted for KYB proof of address?

A bank statement, utility bill, or EIN letter. Business formation documents alone are not sufficient for proof of address.

Does bank account verification (`type: bank_account`) apply to business customers?

No. Bank account verifications are only required for individual customers, not business customers. See the verifying external bank accounts guide.

External Bank Accounts

How do I connect an external bank account via Plaid?

Create a workflow with "type": "plaid" and "kind": "link_token_create", launch the Plaid Link SDK with the returned plaid_link_token, then call POST /api/external_bank_accounts with "account_kind": "plaid" passing the plaid_public_token and plaid_account_id. For step-by-step instructions, see the Plaid integration and add customer external bank accounts guides.

What `account_kind` values are available for external bank accounts?

plaid (using Cybrid's Plaid integration), plaid_processor_token (using your own Plaid account with a processor token), and raw_routing_details (manual routing and account number). For counterparty-owned accounts, use raw_routing_details and pass a counterparty_guid parameter. See the external bank accounts guide for details on each account kind.

How do I verify an external bank account after linking?

Call POST /api/identity_verifications with "type": "bank_account". Use "method": "account_ownership" for plaid accounts, or "method": "attested_ownership" for plaid_processor_token accounts. For the full verification workflow, see the verifying external bank accounts guide.

Why is my Plaid-connected external bank account returning `null` for balance?

For accounts connected via Plaid Processor Token, Cybrid cannot query the balance. Use your own Plaid API integration to retrieve balance and account refresh status for processor token accounts.

What is `refresh_required` state and how do I handle it?

refresh_required means the customer's Plaid connection has expired or been revoked. Create a new workflow with "kind": "link_token_update", launch Plaid Link in update mode, and PATCH the external bank account state to completed after the customer re-authenticates. See the Plaid integration guide for the update flow.

What does the transfer failure code `refresh_required` indicate?

The transfer failure code refresh_required means the Plaid-connected bank account must be reconnected by the customer by creating a new workflow with kind set to link_token_update.

What does the transfer API error `invalid_external_bank_account` mean during the creation of an ACH funding transaction?

This error can occur if the external bank account is in refresh_required state. To resolve, the customer needs to reconnect their external bank account by creating a new workflow with kind set to link_token_update.

What does the transfer failure code `plaid_institution_not_responding` indicate?

The failure code plaid_institution_not_responding means Plaid is unable to communicate with the customer's bank. This can happen if the bank is temporarily offline or if there are performance issues on Plaid's side. Retry later. If the issue persists, try a different institution or bank.

What should I do for `plaid_no_accounts`, `plaid_multiple_accounts`, or `plaid_item_not_supported`?

These errors are from Plaid, and in most cases retrying the same account does not help. Delete the account and re-add it (or add a different account).

How do I register a Plaid redirect URI for my application?

Contact Cybrid support with your redirect URI. Sandbox only supports HTTPS URIs. Separate registrations are needed for sandbox and production environments. For Android apps, register your package name (such as com.yourapp) instead of a redirect URI.

Can I connect a bank-level (partner) external bank account via Plaid?

No. Bank-level external bank accounts cannot be connected via Plaid. Provide the raw routing and account number details to Cybrid support, who will add it manually on your behalf.

What action is required when `no_account` or `invalid_account` is returned from `GET /api/external_bank_accounts`?

When either no_account or invalid_account is returned as the message_code on a 422 response, the external bank account must be deleted and re-added, as Cybrid no longer has access to the account.

Can customers add external bank accounts using raw routing details instead of Plaid?

Yes, but with limitations. Raw routing details accounts are disabled by default in production and must be enabled per bank by contacting Cybrid support. You cannot initiate a funding deposit (ACH pull) via API on these accounts — deposits must be initiated externally by the customer. Funding withdrawals (ACH push) work on all rails with no difference. Contact Cybrid support.

When does a bank account identity verification go to the `waiting` state?

A bank account identity verification transitions to waiting only when the system cannot make an automated decision and the case requires analyst review (such as a name_check_failure requiring a bank statement upload via Persona). If the verification passes automatically, it goes directly from storing to completed.

Does deleting an external bank account affect existing transfers?

No. Deleting an external bank account does not affect transfers that have already been initiated. You cannot create new transfers to the deleted account.

What does the `invalid_routing_number` error mean when linking a bank account via Plaid?

This error occurs when Plaid does not have access to the most recent routing details for the customer's bank. The account creation always fails in this case. The customer can try a different bank account or financial institution.

Transfers

What is the difference between `funding` and `instant_funding` transfer types?

A standard funding transfer initiates an ACH pull that settles in a few hours on the same business day. An instant_funding transfer immediately credits the customer's fiat account using a pre-funded bank-level float account; the ACH pull settles later. Instant funding requires passing "bank_fiat_account_guid" in the POST /api/transfers call. For setup details, see the instant funding and transfer process guides.

How are API amounts specified (dollars or cents)?

All amounts are in base units: cents for USD (100 = $1.00), satoshis for BTC, wei for ETH, etc.

What is the minimum transfer amount?

$0.50 USD (50 cents). Transfers or quotes below this threshold are rejected. See the limits and minimums guide for all platform limits.

What payment rails are supported?

ACH (same-day ACH for Plaid pulls; standard ACH for push), Wire, RTP/FedNow, EFT, and Interac e-Transfer. In the API payment_rail field, valid values are ach, wire, rtp, eft, and etransfer. The rtp rail represents real-time payment rails (RTP and FedNow) at the payment processor level. EFT and e-Transfer are available for Canadian banking operations. See the platform rails guide.

Which payment rail is used for Plaid pull transfers?

Only ACH (same-day). There is no option to specify the rail for Plaid pull deposits.

What does the `reviewing` transfer state indicate?

The reviewing state may occur after pending, indicating the transfer requires compliance review. After reviewing, the transfer progresses to either completed or failed.

Is there an API to cancel ACH transactions in a pending state?

There is no API to cancel ACH transactions. Cybrid can manually cancel ACH transactions provided the cancellation request is received quickly enough while the transaction is still in pending state.

How do I apply fees to book transfers?

There is no built-in fee mechanism for book transfers. Perform two transfers: (1) a book transfer of the fee amount from the customer's account to your partner fiat account, then (2) the customer's actual book transfer. See the book transfers guide.

How do I withdraw fees collected in my bank-level *Fee* account?

Book transfer the fees to your bank-level fiat account (if not already there), connect a bank-level external bank account via raw routing details, then perform a funding withdrawal transfer from the bank-level fiat account to that external bank account. See the platform accounts guide for account types and fee collection.

Why do I get `invalid_external_bank_account` when sending a funding withdrawal from a customer's fiat account to a bank-level external bank account?

You cannot use a bank-level external bank account as the target for a transfer originating from a customer's fiat account. Either (a) add the external bank account at the customer level, or (b) book transfer the funds to the bank-level fiat account first, then perform the withdrawal from there.

How does the ACH hold work after a funding deposit?

Cybrid can apply an internal 48-hour hold on ACH-pulled funds even after same-day settlement. The platform_balance field on GET /api/accounts shows total funds including held amounts; platform_available shows funds immediately available for transactions. Contact support to configure the hold period for your production bank. See the funding accounts guide.

What is the difference between account `platform_balance` and `platform_available`?

platform_available is the balance that has already settled, whereas platform_balance includes pending transfers that have not yet settled.

What happens to a funding transfer if it is returned?

If you have a two-day ACH hold configured: (1) If the ACH return occurs within the two-day hold window, the funding transfer goes into failed state with the error in the failure_code field and the NACHA return code in the return_code field. (2) If the ACH return occurs outside the two-day hold window, the original funding transfer remains completed but has the return_code set. Additionally, a new transfer of type funding_return is created with a reference to the original transfer in reference_transfer_guid.

What do R03 and R04 return codes mean?

Plaid verifies the bank account during online banking sign-in, but this does not guarantee the ability to send or receive money. If Cybrid receives an R03 or R04 return code, the external bank account must be removed. Notify the customer that their account details caused an ACH return. They should contact their bank to confirm the account information is accurate before attempting another transaction.

What does the `invalid_payment_rail_for_direction` error indicate?

This 422 error means the RTP payment rail is not supported for the direction of the transfer you are attempting. For withdrawals (side: withdrawal), RTP withdrawal transfers from bank-level external bank accounts are not yet supported. For deposits (side: deposit), RTP transfers cannot be initiated on the Cybrid platform — they must be initiated externally by customers (for customer-level accounts) or by partners (for bank-level accounts).

Can Cybrid accounts receive or send international wires?

International wires are not currently supported. ACH, domestic Wire, and RTP/FedNow are supported for US customers. EFT and Interac e-Transfer are supported for Canadian customers.

Is the Cybrid platform affected by bank holidays?

Yes, all US and Canadian bank holidays affect the platform. Every holiday adds an additional business day for all fiat transfer and trade settlements. Crypto transfers are unaffected.

What is the difference between `fiat_account_guid`, `customer_fiat_account_guid`, and `bank_fiat_account_guid` in the transfer API?

fiat_account_guid is for funding transfers where only one fiat account is involved. customer_fiat_account_guid and bank_fiat_account_guid are for instant_funding and lightning transfers where multiple fiat accounts are involved (both customer and bank level).

How do I prevent duplicate transfers?

The quote GUID acts as an idempotency key. Each quote can only be used for one transfer. Attempting to create a second transfer with the same quote returns a 409 error with message code quote_already_exists. See the generate quote guide.

How long can a customer file an ACH return after a deposit?

A customer can file an ACH return up to 60 days after the settlement date. If you issue a refund via a funding withdrawal, it is not connected to the original deposit in the banking system, so the customer could still file a return on the original transaction.

Why did my transfer fail with `limit_exceeded`?

The limit_exceeded failure code means the customer has exceeded their activity limits. View a customer's activity_limits by calling GET /api/customers/{customer_guid} or checking the Customer Details in the Partner Portal. Limits are based on calendar days. See the limits and minimums guide for default limits and how to request increases.

What is the ACH pulls processing cutoff time?

ACH transfers are processed on business days only (Monday through Friday, excluding US bank holidays). The cutoff time is 3:00 PM Eastern Time. Transfers initiated after 3:00 PM ET or on weekends and holidays are processed on the next business day.

What are the per-transaction limits for each payment rail?

ACH has a per-transaction limit of $6,000 (can be increased up to $25,000 but requires a higher reserve amount). RTP has a per-transaction limit of $25,000 (can be increased up to $500,000). Wire has a per-transaction limit of $750,000. These are rail-level limits and apply regardless of the customer's activity limits. For amounts exceeding the ACH limit, use "payment_rail": "wire" or split the transfer into multiple ACH transactions. See the limits and minimums guide for the complete limits reference.

Are there deposit limits when customers push funds to their deposit bank account?

No. There is no limit on receiving funds when customers push funds to their deposit bank account via wire, ACH push, or RTP. Activity limits for deposit transfers only apply to ACH pull (debit) transfers.

Do new customer accounts have additional deposit restrictions?

Sometimes risky customer accounts created within the previous 60 days have different ACH pull deposit limits to protect against excessive ACH returns. Transfers that exceed these limits or are flagged by Plaid Signal for high risk receive a compliance_rejection failure. For customers who need to transact above these limits within their first 60 days, wire transfers to deposit bank accounts are an option.

Why are my ACH transfers stuck in `reviewing` state?

Multiple ACH transfers with the same dollar amount can be flagged as potential duplicate transfers by the partner bank's compliance system. The transfers are held for review before being released. Consider varying transfer amounts when splitting larger transactions.

Can I confirm that an outgoing wire or ACH transfer has been received by the counterparty's bank?

No. There is no way to confirm that an outgoing transfer has landed in the recipient's bank account, except providing the trace number to the customer to follow up with their bank. For incoming deposits via deposit bank accounts, you receive a transfer webhook when funds arrive on the platform. See the settlement process guide for fiat transfer settlement timelines.

How do I get the IMAD and OMAD for wire transfers?

Wire transfer identifiers (IMAD and OMAD) are available in the identifiers array on the transfer resource. Retrieve them via GET /api/transfers/{transfer_guid} or view them in the Partner Portal under the Identifiers tab on a transfer's detail page.

How do I detect incoming deposits to a customer's deposit bank account?

Monitor your webhook subscription for transfer.completed events. Call GET /api/transfers/{transfer_guid} and check if transfer_type is funding and side is deposit. The transfer_details field contains additional information such as beneficiary_name (sender name), transaction_type, and routing details. Use destination_account.guid to match the transfer to a customer. See the deposit bank accounts and webhooks guides.

What types of external wallets can I create?

External wallets can be owned by a customer (pass customer_guid), a counterparty (pass counterparty_guid), or the bank (omit both). The address field is the on-chain blockchain address and is required. See the add external wallets guide.

Why don't I provide a network when creating an external wallet?

The network is inherent in the asset specified when creating an external wallet, so the network is predetermined when specifying the asset for quotes and external withdrawals.

Can a customer send crypto directly to a bank-level external wallet?

Yes. Use POST /api/quotes with product_type: crypto_transfer and customer_guid, then POST /api/transfers with transfer_type: crypto, external_wallet_guid pointing to the bank-level wallet, and source_participants / destination_participants set to the customer. See the withdraw crypto and transfer participants guides.

How long does it take to move crypto assets between `trading` and `storage` accounts?

Transfers from trading to storage go on-chain immediately and are subject to the normal blockchain confirmation period. On the platform, a transaction is considered settled after 4 confirmations. Transfers from storage to trading can take up to 24 hours to process, followed by the normal blockchain confirmation time. See the crypto cold storage guide.

Why did my BTC crypto transfer fail with `network_fee_too_low`?

Cybrid executes BTC transactions at medium priority to balance confirmation speed and cost. During periods of high network fee volatility, the estimated fee may be insufficient, causing the transfer to fail. Retry the transfer — it uses a new fee estimate. Cybrid does not currently expose an option to select fee priority via the API.

Do Lightning Network transfers count toward the crypto transfer limit?

No. Lightning transfers do not currently contribute to the crypto transfer limit. Independent limits for Lightning may be introduced in the future. See the send Lightning payment and receive Lightning payment guides.

What does the `prohibited_address` failure code mean when adding an external wallet?

The prohibited_address failure code means the wallet address did not pass Cybrid's on-chain wallet screening. The wallet's state is failed. Open a Zendesk compliance ticket if you believe this is an error. Wallet addresses with no transaction history may occasionally trigger false positives.

Trades

Why do trades stay in `executed` state in sandbox?

In sandbox, trades always remain in executed state and never move to settling. This is by design. See the sandbox environment differences guide.

What is the `symbol` field for quotes, and when is it required?

The symbol field (such as BTC-USD) is only required for trading product type quotes. For crypto transfers, omit symbol and use asset instead. Use "product_type": "crypto_transfer" (not "crypto") for withdrawal quotes. See the generate quote guide.

How does trade fee billing work?

Cybrid applies a trading fee per your contract in BPS. For example, at 50 BPS on a $9.95 trade: fee = 9.95 x 0.005 = ~$0.05. This fee appears as a fee field in the quote response. Trade fees are collected on every quote and appear on your monthly invoice. See the trade fees guide.

Why are trade fees zero when I use a customer token instead of a bank token?

Only bank tokens (generated via POST /oauth/token) can set fees on trades and transfers. Customer tokens (generated via POST /api/customer_tokens) cannot set fees for security reasons. Always use a bank token when initiating trades or transfers on behalf of customers if you need to apply spread or fixed fees. See the trade fees and token scopes guides.

What is the correct trading symbol format for USDT on Tron?

The trading symbol for USDT on Tron is USDT_TRX-USD. When adding trading symbols to your bank configuration via PATCH /api/banks/{bank_guid}, use the full symbol format that includes the fiat pair (such as USDT_TRX-USD). Using only the asset code returns a "Trading symbol not supported" error. See the assets and symbols guide for all supported symbols.

Should I use the `/api/prices` endpoint or create a quote to get an accurate trading rate?

Use quotes (POST /api/quotes) for accurate trading rates. Quotes query multiple liquidity providers and lock the best rate for that trade. The /api/prices endpoint values may be temporarily cached and are not always the most up to date. Unused quotes are periodically cleaned up by the platform. See the generate quote and smart order router guides.

Webhooks

Why am I not receiving webhook events?

Verify that you are using Organization credentials (not Bank credentials) to create subscriptions. Check the Partner Portal Developer tab for subscription state. Ensure your endpoint is publicly accessible over HTTPS and returns a 2xx status quickly. Use GET /api/subscription_deliveries to inspect recent delivery attempts. See the webhooks guide for complete setup instructions.

What information is included in a webhook event payload?

For security, webhook events only contain the object_guid of the changed resource and the event type. Always perform a GET /api/{resource}/{object_guid} after receiving a webhook to retrieve the full details.

Which events does Cybrid send webhooks for?

trade, transfer, and identity_verification state changes. Customer state changes do not currently trigger webhooks (planned for a future release).

What happens if my webhook endpoint is down and events fail to deliver?

Cybrid retries delivery according to the webhook retry schedule. After a configurable number of failures, the subscription is marked failed. Delete old or dead subscriptions (such as expired ngrok sessions) promptly to avoid impacting platform performance.

How do I get an Organization Bearer token for subscriptions?

Call POST /oauth/token with your Organization client_id, client_secret, and appropriate scopes (such as subscriptions:execute subscriptions:read). This is the same endpoint used for Bank tokens, with Organization credentials. See the API keys guide.

What is the limit on active subscriptions?

The limit is 5 active subscriptions (webhook endpoints).

How can webhooks detect if a transfer has been returned?

Set up webhooks to monitor for transfer.completed events, then retrieve the transfer details using GET /api/transfers/{transfer_guid}. Check whether (1) the return_code field has a value other than null, indicating the underlying transfer has been returned, or (2) the transfer_type field is set to funding_return, indicating a return transfer associated with the original transfer GUID in reference_transfer_guid.

Are there webhook events for external bank account state changes?

No. Webhook events currently only cover trade, transfer, and identity_verification resources. As a workaround, monitor bank_account type identity verifications, since external bank accounts transition to completed only after a successful bank IDV.

Why am I receiving duplicate or repeated webhook events?

Your endpoint must respond with a 2xx status code within 2 seconds. If the response takes longer, the system treats it as a timeout and retries delivery. Move any processing logic (such as API calls to retrieve the full resource) to a background job so your endpoint can return 200 immediately. Verify delivery status by calling GET /api/subscription_deliveries?subscription_event_guid={subscription_event_guid} and checking the response field.

Deposit Bank Accounts

What is a deposit bank account and when do I need one?

A deposit bank account generates routing and account numbers that allow partners or their customers to receive ACH, Wire, and RTP/FedNow push deposits. Create one with POST /api/deposit_bank_accounts linked to a fiat account. See the deposit bank accounts guide.

What are `main` vs `sub_account` deposit bank accounts?

A main deposit bank account creates a unique account number. A sub_account shares the parent account number but uses a unique memo ID to route funds to the correct fiat account. Sub-accounts are free; main accounts have an opening fee and ongoing maintenance cost. See the deposit bank accounts guide.

How do I retrieve wire deposit instructions for my bank-level deposit account?

Call GET /api/deposit_bank_accounts/{deposit_bank_account_guid}. The response includes account_details (account number) and routing_details (routing number). Beneficiary details on bank-level accounts require a manual update — provide your legal business name, registered address, contact email, and phone number to Cybrid support. See the partner deposit bank account guide.

Can individual and business customers receive deposits from third parties?

Yes. Both individual and business customers can receive ACH, Wire, and RTP deposits to their deposit bank account from third parties (such as payroll, receivables, or other financial institutions). As long as the sender uses the customer's assigned deposit account details (routing number and account number), the funds post automatically.

Counterparties

What is a counterparty and how does it differ from a customer?

Counterparties are third-party participants (businesses or individuals) that can receive payments from your platform. They undergo sanctions screening but do not go through the full Persona KYC/KYB flow. Use POST /api/counterparties then POST /api/external_bank_accounts (with account_kind: raw_routing_details and counterparty_guid) to add their bank details. See the counterparties and creating a counterparty guides.

What address format does the Counterparty API require for subdivision?

The subdivision field must be an ISO 3166-2 subdivision code (such as CA for California, 30 for Kenya's Nairobi County). Country-specific requirements apply — for some countries the field is nullable, but for others (such as US and Kenya) it is required.

How do I add counterparties in countries outside the US?

Your bank configuration must explicitly allow the destination country for counterparties. Update your Compliance board (Jurisdiction of Customers / counterparties) and contact support to have it added to your bank configuration. See the sending cross-border payments and supported corridors guides.

What is the maximum length for a counterparty business name?

The counterparty name must not exceed 15 words. Names longer than 15 words fail AML screening. Shorten the name before submitting the counterparty creation request.

How do I create a counterparty in a country that does not use postal codes (such as Hong Kong)?

Omit the postal_code field entirely from the address object. Do not send empty strings or placeholder values. For example, a Hong Kong address should include only street, city, and country_code.

Is the counterparty `name` field mandatory, and does counterparty verification expire?

Yes, the name field (with first and last) is mandatory for AML/Sanctions screening. Counterparty verification does not expire, but the system periodically re-runs AML checks in the background. After creating a counterparty, create an identity verification with "type": "counterparty" and "method": "watchlists" to verify them. See the verifying a counterparty guide.

Implementation, Production Testing, and Going Live

What are the requirements to go live on Cybrid?

You must: (1) complete a compliance review via the Compliance board, (2) pass an implementation review call demonstrating your full flow of funds, (3) implement MFA on account creation and on each transaction, (4) display and link the Cybrid User Agreement in your application, and (5) test the complete on-ramp and off-ramp flow in production with the $100/day testing limits. See the securely implementing Cybrid guide.

What is the production testing bank and its limits?

When approved for production testing, a production bank is created with a $100 USD daily activity limit. You can test real KYC and money movement against this bank. Limits are removed after Cybrid reviews your full-flow test results.

What does Cybrid check during the implementation review?

Cybrid verifies: (1) MFA is enforced on account creation and each financial transaction, (2) the Cybrid User Agreement is accessible and acknowledged by customers, (3) the demonstrated flow matches the approved flow of funds, and (4) security requirements (credentials stored server-side, encrypted at rest). See the securely implementing Cybrid guide for full security requirements.

How do I get production testing limits removed to go fully live?

Once you have tested the complete flow (deposit, trade, and crypto withdrawal if applicable) within the $100/day production testing limits, inform your Cybrid contact. Cybrid conducts an internal go-live review and removes the limits when satisfied.

How can I access the Cybrid User Agreement or share it with customers?

The Cybrid User Agreement is available at the link above. Ensure customers accept this agreement before completing sign-up and can access it at any time through your platform.

Fees & Billing

How are KYC fees charged?

KYC fees are charged per successful verification as a line item on your monthly invoice. At the Starter Tier, the fee is $1.50 per successful KYC (Cybrid subsidizes the actual cost).

What are the typical per-transaction fees for fiat rails?

Typical costs (vary by contract): ACH $0.25-$1.00/transaction, RTP/FedNow $1.00/transaction, Wire $20.00-$25.00/transaction. Exact rates are specified in your contract fee schedule.

Where do trading fees land and how do I collect them?

Cybrid collects its platform trading fee automatically. To charge your own spread, pass a fees array in the POST /api/quotes request. Your fee lands in the quote fee field and is collected from the customer at trade execution. To withdraw collected fees, book transfer from your bank-level fee account to your bank-level fiat account, then perform a funding withdrawal to your external bank. See the trade fees and platform accounts guides.

What is the gas account and how do crypto network fees work?

The gas account accumulates crypto network fees for on-chain transactions. ACH and wire fees are invoiced monthly based on volume per your contract schedule. Before withdrawing funds from your fee account, you must first clear any outstanding balance on the gas account by transferring funds from your fee or fiat account to the gas account. Alternatively, the gas account balance is billed and zeroed out at the end of each month. See the platform accounts and finance guides.

Compliance

How long does Cybrid retain KYC information?

Cybrid retains all KYC information used to identify customers for a minimum of 5 years after the account is closed, as required by the Bank Secrecy Act.

Is there a customer delete API?

No. Customers cannot be deleted. You can delete external bank accounts and external wallets. Deposit bank accounts can be closed by contacting support.

How do I handle a compliance issue for a live customer?

Create a Zendesk ticket. See the support ticketing system guide. Do not use Slack for Compliance requests after going live.

Is there a way to bulk export customer data from the platform?

There is no built-in data export feature. Write a script that uses the API to retrieve data — for example, use GET /api/accounts to list accounts and check platform_available balances, and GET /api/identity_verifications/{identity_verification_guid}?include_pii=true to retrieve customer PII.

Can records be deleted in the production environment?

No. Cybrid cannot delete any records in the production environment. If you created a resource in error, you must work around it (such as abandoning the incorrect customer GUID and creating a new one).

How can I detect when a customer account is frozen?

There is no webhook event for customer state changes. As a workaround, listen for the transfer.completed webhook, check if transfer_type is funding_return, extract the customer_guid, and call GET /api/customers/{customer_guid} to check if the customer state is frozen.

Bank and Organization configuration

Can I update my bank name and CORS values after creation?

Yes. Bank name and CORS values can be modified after creation. Organization name changes are not exposed in the Partner Portal and require a manual update by Cybrid support.

Can I have multiple bank-level fiat accounts?

Yes, but it requires Cybrid to update your bank configuration. Multiple bank-level fiat accounts are generally discouraged as they complicate the flow of funds audit trail. Clearly justify the business reason when requesting this.

How do I add a new trading asset to my bank?

Some assets can be added via Partner Portal under Bank Details. For assets that cannot be added via the UI (such as USDC-SOL), provide your Bank GUID to Cybrid support and they will configure it. See the assets and symbols guide.

How do I enable business customers on my bank?

Business customers must be explicitly enabled on each bank. Contact Cybrid support to enable the business_customers feature. Verify the configuration in the Partner Portal under your bank's Configuration tab, where "Business Customers" should be listed if enabled.

Can a customer belong to multiple banks?

No. Customers can only belong to one bank. To use a customer in a second bank, create a new customer resource in that bank and complete KYC/KYB verification again. Identity verifications do not transfer between banks.

Attested KYC / KYB

What is Attested KYC and when is it available?

Attested KYC allows you to pass customer PII and ID images directly to Cybrid without requiring your customers to go through the Persona SDK flow (under development). See the verifying a customer guide for current verification methods.

Sandbox vs production

How does sandbox differ from production?

Key differences: (1) Sandbox trades never fully settle (stay in executed); (2) ACH transfers do not trigger real bank transactions; (3) the Persona expected_behaviours parameter works in sandbox but not in production; (4) Plaid uses test credentials. See the sandbox environment differences guide for full details.

How do I simulate a funding deposit in sandbox to test my webhook flow?

You cannot simulate an externally-initiated deposit to a deposit bank account in sandbox. Alternatives: (1) execute a Plaid ACH pull via API using a connected Plaid test account, or (2) book transfer funds from your bank-level fiat account (book transfers process even with a $0 balance in sandbox).