API Versioning
How do I target a specific API version in my requests?
Overview
API versioning allows Cybrid to evolve the platform without breaking existing integrations.
Specify a version in API requests
Set the Accept-Version header to the desired version:
curl --request GET \
--url https://bank.sandbox.cybrid.app/api/transfers \
--header 'accept: application/json' \
--header 'accept-version: 2025-06-01'
Default versionIf the
Accept-Versionheader is omitted, the API defaults to version2022-01-01.
API version changelog
Each version introduces behavior changes to specific resources, listed below from oldest to newest.
2022-01-01
The baseline version. All existing behavior is unchanged when no version header is sent.
2025-06-01
Added the holding state to transfer state. Transfers in holding represent funds that are held (due to return risk) before processing.
- Backward compatibility: in
2022-01-01,holdingfalls back topending.
2025-10-01
Trade state now exposes a new executed state. In earlier versions, executed trades were returned as pending or settling.
- Filtering behavior change: in older versions, filtering
GET /api/trades?state=pendingorGET /api/trades?state=settlingimplicitly included executed trades. From2025-10-01onward, filtering is exact — passstate=executedto retrieve those records.
The counterparty_bank_account field (an object containing routing_number_type, routing_number, and account_number) for external bank accounts has been replaced by counterparty_bank_account_details, an array of bank account detail objects. This allows supplying multiple routing number formats in a single request (for example, ABA and SWIFT). This change applies only to POST /api/external_bank_accounts when account_kind is raw_routing_details.
Breaking change forraw_routing_detailsRequests using
account_kind: raw_routing_detailsmust sendcounterparty_bank_account_detailsas an array instead of the formercounterparty_bank_accountobject.
2025-12-01
Added the reviewing state to external wallet state. Wallets enter reviewing during compliance checks before being approved or failed.
- Backward compatibility: in versions before
2025-12-01,reviewingfalls back tostoring.
2026-04-01
More granular transfer failure_code values are available. Older versions receive the coarser fallback value listed below.
| New code | Fallback (older versions) |
|---|---|
daily_limit_exceeded | limit_exceeded |
weekly_limit_exceeded | limit_exceeded |
monthly_limit_exceeded | limit_exceeded |
return_risk_exceeded | compliance_rejection |
customer_contact_info_missing | invalid_destination |
recipient_cancelled | external_vendor_error |
invalid_security_question | external_vendor_error |
duplicate_transaction | external_vendor_error |
The customer_contact_info_missing and recipient_cancelled codes apply to e-transfer and EFT transfers. The invalid_security_question and duplicate_transaction codes apply to e-transfer withdrawals. They provide more actionable detail than the generic codes they replace in older versions.
Added the cancelling state to transfer state, along with the Cancel Transfer operation DELETE /api/transfers/{transfer_guid}, which requests best-effort cancellation of an eligible funding transfer or crypto withdrawal. See Cancel a Transfer.
- Backward compatibility: the
cancellingstate falls back topendingin versions before2026-04-01, and the Cancel Transfer operation is not available in those versions (it returns404).
2026-09-01
External bank account onboarding now verifies ownership of the account before the account is stored. POST /api/external_bank_accounts remains the same endpoint, but its preconditions, request shape, and state vocabulary change. Onboarding behavior is fixed per account at creation and does not change afterwards, so accounts created on earlier versions keep their original behavior and a bank can hold accounts of both generations.
Added the pending, reviewing, and expired states to external bank account state. An account is pending while the Platform verifies that the owner owns the account, reviewing when the check is inconclusive, or the account is held for compliance review or repair, before it completes, fails, or expires, and expired when the ownership verification or compliance review lapsed before it completed, so the account was never verified.
- Backward compatibility: in versions before
2026-09-01,pendingandreviewingfall back tostoring, because an account in either state is still in flight.expiredfalls back tofailed, because it is terminal.
A request that includes counterparty_guid, for an individual or a business counterparty, must no longer send counterparty_name, counterparty_address or counterparty_email_address. Sending any of them returns 400 with invalid_parameter. The account is created with the counterparty's own verified details from when the counterparty was created. Ownership of a counterparty account is implied to be the counterparty's, so there is no holder-name match, no bank_account identity verification and no Persona inquiry. The account usually moves storing → pending → completed. If the counterparty matches an existing identity that needs a compliance review, it moves to reviewing and ends completed, failed with compliance_rejection, or expired.
- Backward compatibility: in versions before
2026-09-01,counterparty_nameandcounterparty_addressare required only whencounterparty_guidis omitted.
For a customer-owned account (customer_guid without counterparty_guid) or a bank-owned account_kind: raw_routing_details account, counterparty_name and counterparty_address remain required as holder information; for a customer-owned account, they are the input to the ownership check. The address must meet your bank's counterparty address requirements for its country; country_code is always required. Optional fields are validated when supplied. Leaving either field out returns 400 with invalid_parameter; sending either as an empty object returns 400 with missing_holder_info.
The account owner — the counterparty when one is linked, otherwise the customer — must already be verified before the account is created. A counterparty must have passed counterparty verification, which is the type: counterparty identity verification rather than a customer KYC or KYB verification. A customer must have completed KYC for an individual or KYB for a business. A request for an owner that is not yet verified returns 400 with unverified_counterparty or unverified_customer.
- Exception: at banks that verify individuals non-documentarily, an individual customer whose attested personal details have passed may create an account before verification completes, because the account is what authenticates them.
- Bank-level accounts, created without a
customer_guidor acounterparty_guid, have no owner to verify. The precondition does not apply to them and no automated ownership check runs, because the bank attests the account itself. The account movesstoring→pending→completed; if the provider rejects the bank's legal-entity details, it waits inreviewingwhile Cybrid repairs them.
An Interac e-Transfer entry in counterparty_bank_account_details is addressed by an identifier rather than a bank code. Set payment_rail to ETRANSFER and supply account_identifier_type as EMAIL or PHONE_NUMBER, without bank_code_type. See Add Counterparty External Bank Accounts.
- Backward compatibility: versions before
2026-09-01keep the bank code form for the e-transfer rail, which describes an EFT account at the provider rather than an addressable contact. - On every version, an e-transfer contact must carry an
EMAILentry; a phone-only contact returns400withinvalid_account_number. - An Interac e-Transfer account created on this version, owned by a counterparty or by the customer, can be used on an
etransferfunding transfer throughexternal_bank_account_guidto request or send money. The transfer request is accepted on every version. Requests from and sends to a counterparty require explicit compliance approval from Cybrid before production use. See Interac E-Transfer.
account_kind: plaid_processor_token is not supported on this version. A request using that account kind returns 422 with unsupported_value.
- Backward compatibility:
plaid_processor_tokenremains supported in versions before2026-09-01.
POST /api/identity_verifications with type: bank_account is no longer accepted for accounts created on this version, because ownership is verified while the account is created. Such a request returns 422 with deprecated. See Verify External Bank Accounts.
Added external bank account failure_code values for accounts onboarded on this version. Ownership verification of a customer-owned account reports ownership_mismatch when the holder name did not match or a reviewer denied the verification. On an inconclusive holder-name match, the account stays pending while the customer completes a Persona inquiry, where they can upload a bank statement; the Platform creates the type: bank_account, method: account_ownership identity verification you open the inquiry from. When the customer completes it, the account moves to reviewing, then ends completed, failed with ownership_mismatch, or expired. A declined compliance review reports compliance_rejection. The account creation that follows verification reports missing_holder_info. A verification or compliance review that lapses before it completes is reported as the expired state rather than a failure code. See External Bank Accounts.
missing_holder_infois also returned synchronously as400when a customer-owned or bank-ownedraw_routing_detailsrequest suppliescounterparty_nameorcounterparty_addressas an empty object. In that case the request is rejected and no account is created, so nofailure_codeis reported. It applies to customer-owned or bank-owned accounts only.- Permanent provider or validation errors during account creation now end the account in
failed, withfailure_codecreate_failed, orlegal_entity_incomplete_piiwhere the owner's legal-entity details are incomplete. A bank-owned account whose legal-entity details the provider rejects instead waits inreviewingwhile Cybrid repairs them.
In sandbox, the expected_behaviours field on POST /api/external_bank_accounts deterministically simulates the holder name match outcome. The accepted values are passed_immediately and failed_immediately. The field applies only where ownership is established by a holder name match, which is the case for customer-owned accounts. It is accepted and ignored for accounts whose verification does not include that step, such as bank-owned and counterparty-owned accounts. Sending the field outside sandbox returns 400 with invalid_parameter.
- A simulated
passed_immediatelywrites the same compliance decision a real pass would and can move a customer to Tier Basic. It stands in for the check rather than bypassing its consequences.
Platform changes
The following changes apply to every API version, regardless of the Accept-Version header.
November 2026
POST /api/files now accepts at most 9,900,000 characters of Base64 data (approximately 7.4 MB before encoding), down from 10,485,760 characters (approximately 7.86 MB). For larger files, omit data and use the pre-signed upload_url flow, which is unchanged. See File Upload.
OpenAPI definitions and Swagger UI are no longer served from /api/schema/*. Use the API reference instead.
Bitcoin Lightning is no longer supported. You can no longer create Lightning transfers (type: lightning), Lightning quotes (product_type: lightning_transfer), invoices, payment instructions, or invoice_operations accounts.
- Backward compatibility: existing Lightning transfers, quotes, invoices, payment instructions, and
invoice_operationsaccounts remain readable through theGETand list endpoints. Their response values (lightning,lightning_transfer,invoice_operations) are unchanged. - If you regenerate an API client, the Lightning request values are removed. Update any code that references them.
Updated 6 days ago

