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 version

If the Accept-Version header is omitted, the API defaults to version 2022-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, holding falls back to pending.

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=pending or GET /api/trades?state=settling implicitly included executed trades. From 2025-10-01 onward, filtering is exact — pass state=executed to 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 for raw_routing_details

Requests using account_kind: raw_routing_details must send counterparty_bank_account_details as an array instead of the former counterparty_bank_account object.

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, reviewing falls back to storing.

2026-04-01

More granular transfer failure_code values are available. Older versions receive the coarser fallback value listed below.

New codeFallback (older versions)
daily_limit_exceededlimit_exceeded
weekly_limit_exceededlimit_exceeded
monthly_limit_exceededlimit_exceeded
return_risk_exceededcompliance_rejection
customer_contact_info_missinginvalid_destination
recipient_cancelledexternal_vendor_error
invalid_security_questionexternal_vendor_error
duplicate_transactionexternal_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 cancelling state falls back to pending in versions before 2026-04-01, and the Cancel Transfer operation is not available in those versions (it returns 404).

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, pending and reviewing fall back to storing, because an account in either state is still in flight. expired falls back to failed, 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_name and counterparty_address are required only when counterparty_guid is 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_guid or a counterparty_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 moves storing → pending → completed; if the provider rejects the bank's legal-entity details, it waits in reviewing while 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-01 keep 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 EMAIL entry; a phone-only contact returns 400 with invalid_account_number.
  • An Interac e-Transfer account created on this version, owned by a counterparty or by the customer, can be used on an etransfer funding transfer through external_bank_account_guid to 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_token remains supported in versions before 2026-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_info is also returned synchronously as 400 when a customer-owned or bank-owned raw_routing_details request supplies counterparty_name or counterparty_address as an empty object. In that case the request is rejected and no account is created, so no failure_code is 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, with failure_code create_failed, or legal_entity_incomplete_pii where the owner's legal-entity details are incomplete. A bank-owned account whose legal-entity details the provider rejects instead waits in reviewing while 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_immediately writes 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_operations accounts remain readable through the GET and 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.

Did this page help you?