CA Remittance Integration Guide
How do I send cross-border remittances from Canadian customers using Cybrid-integrated payouts?
CA Remittance lets Canadian individuals send cross-border remittances using Cybrid-integrated payouts. Your customer funds a Canadian dollar balance from their own bank, Cybrid converts it to a stablecoin, and a remittance plan delivers the funds to a recipient abroad in the local currency — all through a single API integration.
Under the hood, the customer funds a CAD fiat account via Interac e-Transfer (no bank linking required), converts CAD directly to USDC_SOL in a trading account, then a remittance plan pays out to the recipient's foreign bank account over the local rail. Senders are onboarded as individuals with KYC, and recipients are tracked as verified counterparties.
India (INR over IFSC) is the example corridor used throughout. Other corridors are available and follow the same flow with corridor-specific fields.
At a high level, you will:
- Onboard and verify the customer with KYC.
- Create the CAD fiat account, the USDC_SOL trading account, and the customer's deposit bank account.
- Fund the CAD account with an Interac e-Transfer deposit.
- Convert CAD directly to USDC_SOL.
- Create and verify the recipient counterparty and their foreign bank account.
- Create and execute the remittance plan to pay out.
Ready for production?Once you have built and tested this integration in sandbox, the Production Access Checklist covers what it takes to qualify for production access and go live.
Flow of funds
Figure: CA remittance flow of funds.
Funds move left to right across the Cybrid boundary. The customer's external Canadian bank account funds their CAD fiat account inside Cybrid over Interac e-Transfer (no Plaid link required), where KYC and the deposit bank account are held. A trade settles the CAD directly into a USDC_SOL trading account, and a remittance plan converts and pays out to the recipient's foreign external bank account. The recipient is tracked as a verified individual counterparty.

Arrow colors in the diagram: green is fiat movement, orange is crypto movement, blue is trade settlement, and tan is a book transfer.
Table of Contents
- Prerequisites
- Customer onboarding
- Create accounts
- Create deposit bank account
- Fund the CAD account via Interac e-Transfer
- Convert CAD to USDC_SOL
- Create the recipient counterparty
- Create the recipient external bank account
- Create and execute the remittance plan
- Webhooks
- Additional resources
1. Prerequisites
Before integrating the CA Remittance flow, configure your sandbox bank with the required features.
Bank configuration
When creating your bank in the sandbox environment, configure these settings:
Customer type support:
Enable individual customers:
- Individual customers (
individual_customers)
Fiat account assets:
Enable the fiat currency for the funding country:
- CAD
Trading symbols:
Enable the USDC_SOL-CAD trading pair for direct CAD to USDC_SOL conversion.
Canada: zero balances requiredDue to regulatory requirements in Canada, Cybrid cannot hold balances in customer accounts on the platform. All funds submitted to the platform in Canada must have instructions assigned to keep the funds in transit, with zero balances maintained once transactions complete.
Enable the payout symbols for your corridorsContact Cybrid support to enable the payout symbols for the payout corridors you require (for example,
INR-USDC_SOL). Confirm corridor support viasupported_payout_symbols. This is the only enablement step for Cybrid-integrated remittance payouts — Interac e-Transfer funding and direct CAD to USDC_SOL conversion require no separate bank feature toggles.
Supported corridors for C2C remittancesThis guide implements a consumer-to-consumer (C2C) remittance. For the full list of destination corridors and the participant types each supports, see Supported Corridors. Some corridors originate from the US only (for example, Pakistan) and are not available from Canada.
2. Customer onboarding
Create the customer, then verify their identity with KYC through the Persona SDK.
Create the customer
Endpoint: POST /api/customers Reference: Create Customer
Set type to individual. Only type is required at creation.
POST /api/customers
Content-Type: application/json
Authorization: Bearer YOUR_TOKEN
{
"type": "individual",
"email_address": "[email protected]",
"phone_number": "555-0100"
}{
"guid": "customer_guid",
"type": "individual",
"state": "storing",
"created_at": "2026-07-19T12:00:00.000Z",
"updated_at": "2026-07-19T12:00:00.000Z"
}
PII fields are optional at creationNot all fields are required to create a customer. Email and phone help identify customers beyond the
customer_guid. Do not provide the customer's name at creation — Persona collects it during KYC, and the legal name returned by Persona becomes the customer's name on file.
Customer states
| State | Description |
|---|---|
storing | Platform is storing customer details |
unverified | Customer created, awaiting identity verification |
verified | Customer identity verified |
rejected | Customer verification rejected |
frozen | Customer account frozen |
Poll GET /api/customers/{customer_guid} until state transitions to unverified.
Polling intervalUse exponential backoff starting at 1 second. In sandbox, state transitions typically complete within seconds. In production, some operations may take longer.
Verify the customer
Endpoint: POST /api/identity_verifications Reference: Create Identity Verification
Create the Persona inquiry. Cybrid returns a persona_inquiry_id you pass to the Persona SDK to launch the capture flow — government ID and selfie (KYC). Use method: id_and_selfie:
POST /api/identity_verifications
Content-Type: application/json
Authorization: Bearer YOUR_TOKEN
{
"type": "kyc",
"method": "id_and_selfie",
"customer_guid": "customer_guid"
}{
"guid": "identity_verification_guid",
"type": "kyc",
"method": "id_and_selfie",
"customer_guid": "customer_guid",
"state": "storing",
"outcome": null,
"created_at": "2026-07-19T12:00:00.000Z",
"updated_at": "2026-07-19T12:00:00.000Z"
}
Preparing customers before verificationPreparing customers before verification greatly increases success rates. See: Verify an Individual Customer
Customer must be unverifiedIdentity verification can only be initiated for customers in the
unverifiedstate. The customer state transitions fromstoringtounverifiedbefore you can start the verification process.
Identity verification states
| State | Description |
|---|---|
storing | Platform is storing verification details |
waiting | Waiting for the customer to complete verification |
pending | Verification submitted, awaiting processing |
reviewing | Verification under manual review |
expired | Verification session expired |
completed | Verification completed (check the outcome field) |
Poll GET /api/identity_verifications/{identity_verification_guid} until state transitions to completed, then confirm outcome is passed.
Integrate the Persona SDK
Persona offers Hosted Flow, Embedded Flow, and native iOS/Android SDKs. The example below uses the Embedded Flow via NPM — see Persona's integration methods to pick the option that fits your app.
Recommended integrationCybrid recommends the embedded flow with the native iOS and Android SDKs for the best customer experience.
Install the SDK:
npm install [email protected] --saveInitialize the client with the persona_inquiry_id from the identity verification response:
import Persona from 'persona';
const client = new Persona.Client({
inquiryId: 'persona_inquiry_id',
language: 'en',
onReady: () => client.open(),
onComplete: ({ inquiryId, status, fields }) => {
// Poll Cybrid or subscribe to identity_verification.completed
},
onCancel: ({ inquiryId, sessionToken }) => { /* user dismissed */ },
onError: (error) => { /* log SDK error */ }
});Key callbacks:
onReady— SDK ready to open.onComplete— user finished the flow; verification can still fail downstream, confirm via the Cybrid API.onCancel— user dismissed the flow.onError— SDK error.
The language parameter accepts ISO 639-1 codes. See Persona's supported languages for the full list.
Resume incomplete sessionsIf the customer abandons the flow before completing, generate a new session token via
POST /api/persona_sessionsand pass it to the SDK assessionTokeninstead ofinquiryId. See Resume Persona Inquiry Session.
Sandbox testing withexpected_behavioursIn sandbox, set
expected_behaviourson the identity verification request to force a deterministic outcome — useful for end-to-end tests without driving the Persona flow.
Value Effect passed_immediatelyVerification completes with outcome: passed.failed_immediatelyVerification completes with outcome: failed.tax_id_not_checkedTax ID check is skipped during verification.
Example expected_behaviours request body:
{
"type": "kyc",
"method": "id_and_selfie",
"customer_guid": "customer_guid",
"expected_behaviours": ["passed_immediately"]
}
Sandbox onlyThe
expected_behavioursfield is rejected in production with a 400 error:Parameter expected_behaviours not permitted in production. Remove the field before deploying.
When the customer returns from the Persona SDK workflow, confirm the customer record has transitioned to verified by querying GET /api/customers/{customer_guid}. Once verified, the customer can proceed with account funding and trading.
Related: Create a Customer · Verify an Individual Customer
CheckpointThe customer is
verified. You can now create their accounts and move on to funding.
3. Create accounts
Create the CAD fiat account and the USDC_SOL trading account for the customer.
Endpoint: POST /api/accounts Reference: Create Account
Create the CAD fiat account
POST /api/accounts
Content-Type: application/json
Authorization: Bearer YOUR_TOKEN
{
"type": "fiat",
"customer_guid": "customer_guid",
"asset": "CAD",
"name": "CAD Account"
}{
"guid": "fiat_account_guid",
"type": "fiat",
"customer_guid": "customer_guid",
"asset": "CAD",
"name": "CAD Account",
"state": "storing",
"created_at": "2026-07-19T12:00:00.000Z",
"updated_at": "2026-07-19T12:00:00.000Z"
}Create the USDC_SOL trading account
POST /api/accounts
Content-Type: application/json
Authorization: Bearer YOUR_TOKEN
{
"type": "trading",
"customer_guid": "customer_guid",
"asset": "USDC_SOL",
"name": "USDC_SOL Trading Account"
}{
"guid": "trading_account_usdc_sol_guid",
"type": "trading",
"customer_guid": "customer_guid",
"asset": "USDC_SOL",
"name": "USDC_SOL Trading Account",
"state": "storing",
"created_at": "2026-07-19T12:00:00.000Z",
"updated_at": "2026-07-19T12:00:00.000Z"
}Account states
| State | Description |
|---|---|
storing | Platform is storing account details |
created | Account created and ready for use |
Poll GET /api/accounts/{account_guid}?include_balances=false until each account's state transitions to created.
Account typesFiat accounts hold currencies like CAD, while trading accounts hold cryptocurrencies like USDC_SOL. The USDC_SOL trading account is the source account for the remittance plan in step 9.
Customer fiat accounts require a deposit bank accountEvery customer fiat account requires a
maindeposit bank account before any funding transfer can complete. Create it immediately after the fiat account — see step 4 and Customer Deposit Bank Accounts.
Related: Creating Platform Accounts
4. Create deposit bank account
Create a main deposit bank account for the customer's CAD fiat account. This is required before any funding transfer can complete.
Endpoint: POST /api/deposit_bank_accounts Reference: Create Deposit Bank Account
POST /api/deposit_bank_accounts
Content-Type: application/json
Authorization: Bearer YOUR_TOKEN
{
"type": "main",
"account_guid": "fiat_account_guid",
"customer_guid": "customer_guid"
}{
"guid": "deposit_bank_account_guid",
"type": "main",
"customer_guid": "customer_guid",
"account_guid": "fiat_account_guid",
"asset": "CAD",
"state": "storing",
"unique_memo_id": "unique_memo_id",
"counterparty_name": "John Doe",
"account_details": [
{ "account_number": "111222333" }
],
"routing_details": [
{ "routing_number_type": "CPA", "routing_number": "000100002" }
],
"created_at": "2026-07-19T12:00:00.000Z",
"updated_at": "2026-07-19T12:00:00.000Z"
}Deposit bank account states
| State | Description |
|---|---|
storing | Platform is storing account details |
created | Deposit bank account created |
Poll GET /api/deposit_bank_accounts/{deposit_bank_account_guid} until state transitions to created.
Deposit bank account enforcement (effective 2026-06-17)From 2026-06-17, every customer fiat account must have a
maindeposit bank account before any funding transfer (deposit or withdrawal) can be created. Provision the deposit bank account immediately after creating the customer's fiat account — see Customer Deposit Bank Accounts.
Routing detailsThe response includes
account_details(account number),routing_details(CPA routing number),counterparty_name(account holder name), andcounterparty_address(account holder address) for incoming EFT deposits.
No deposit bank account errorFunding transfers against a customer fiat account that has no
maindeposit bank account fail with HTTP 422 and message_codeno_deposit_bank_account. Remediate by creating themaindeposit bank account on the fiat account, then retry the transfer.
Related: Customer Deposit Bank Accounts
5. Fund the CAD account via Interac e-Transfer
Fund the CAD fiat account with an Interac e-Transfer deposit. No Plaid bank linking is required — the customer authorizes the deposit through their own bank using a gateway_url.
AvailabilityInterac e-Transfer is only available to Canadian banks on the Cybrid Platform and only works with CAD on CAD-based
fiataccounts.
Create the funding quote
Endpoint: POST /api/quotes Reference: Create Quote
POST /api/quotes
Content-Type: application/json
Authorization: Bearer YOUR_TOKEN
{
"product_type": "funding",
"customer_guid": "customer_guid",
"asset": "CAD",
"side": "deposit",
"deliver_amount": 10000
}{
"guid": "quote_guid",
"product_type": "funding",
"customer_guid": "customer_guid",
"asset": "CAD",
"side": "deposit",
"deliver_amount": 10000,
"receive_amount": 10000,
"fee": 0,
"expires_at": "2026-07-19T12:00:30.000Z",
"created_at": "2026-07-19T12:00:00.000Z",
"updated_at": "2026-07-19T12:00:00.000Z"
}
Amounts are in base unitsAmounts are in base units. For CAD,
10000= $100.00 (cents). For USDC_SOL,10000000= 10.00 USDC_SOL (micro-dollars).
Deliver vs receive amountUse
deliver_amountby default — this is the amount the customer inputs (what they are sending). The response returnsreceive_amountwith fees deducted (in production; no fees in sandbox). Alternatively, specifyreceive_amountto lock in the amount the recipient receives after fees, meaning the customer paysreceive_amount+ fees.
Quotes expire in 30 secondsQuotes are valid for 30 seconds. Use the
expires_atfield on the quote response to determine when a quote expires. Trades or transfers against expired quotes fail.
Execute the transfer
Endpoint: POST /api/transfers Reference: Create Transfer
Create the transfer with transfer_type set to funding and payment_rail set to etransfer. Do not include external_bank_account_guid — it is not used on the e-transfer rail.
POST /api/transfers
Content-Type: application/json
Authorization: Bearer YOUR_TOKEN
{
"quote_guid": "quote_guid",
"transfer_type": "funding",
"payment_rail": "etransfer",
"source_participants": [
{"type": "customer", "guid": "customer_guid", "amount": 10000}
],
"destination_participants": [
{"type": "customer", "guid": "customer_guid", "amount": 10000}
]
}{
"guid": "transfer_guid",
"transfer_type": "funding",
"customer_guid": "customer_guid",
"quote_guid": "quote_guid",
"asset": "CAD",
"side": "deposit",
"state": "storing",
"estimated_amount": 10000,
"fee": 0,
"payment_rail": "etransfer",
"identifiers": [],
"created_at": "2026-07-19T12:00:00.000Z",
"updated_at": "2026-07-19T12:00:00.000Z"
}Display the gateway URL
Wait for the transfer to transition to the pending state. Once pending, read the gateway_url from the identifiers array on the transfer — the identifier has type set to gateway_url and value set to the URL. Display it to the customer so they can select their bank and authorize the deposit.
Domain allowlistingThe
gateway_urluses the domainetransfer.interac.ca. Allowlist this domain in your application if needed.
Asynchronous processingGenerating the
gateway_urlcan take time in both sandbox and production due to sponsor bank response times. Use webhook registration and polling as a backup to handle the asynchronousgateway_urlgeneration.
Deposit request expiryThe customer must authorize the deposit before the e-transfer request expires. Deposit requests are valid for 1 day.
Sandbox behaviorIn sandbox, Interac e-Transfer deposits complete automatically and the
gateway_urlreturned is not a valid URL because the sponsor bank does not support the interactive flow in sandbox.
Wait for completion
Poll GET /api/transfers/{transfer_guid} or subscribe to the transfer.completed webhook. Once the transfer is completed, the CAD funds are available on the platform.
Transfer states
| State | Description |
|---|---|
storing | Platform is storing transfer details |
pending | Transfer pending; gateway_url is available in identifiers |
holding | Transfer on hold (compliance review) |
reviewing | Transfer under manual review |
completed | Transfer completed |
failed | Transfer failed |
cancelling | Cancellation requested (transient); resolves to failed (failure_code cancelled) or completed |
Webhook Events: transfer.pending, transfer.completed, transfer.failed, transfer.cancelling
Handle terminal failed states via the failure_code:
payment_request_expired— the customer did not authorize before the URL expired.cancelled— the customer rejected the e-transfer request.
Related: Interac e-Transfer · Transfer Process · Transfer Participants
CheckpointThe e-Transfer funding transfer is
completedand CAD is available in the customer's fiat account. You are ready to convert it to USDC_SOL.
6. Convert CAD to USDC_SOL
Convert CAD directly to USDC_SOL in the USDC_SOL trading account using the USDC_SOL-CAD trading symbol. Direct conversion is enabled for Canada — no intermediate USDC swap is required. This settlement funds the source account for the remittance plan.
Create the trading quote
Endpoint: POST /api/quotes Reference: Create Quote
POST /api/quotes
Content-Type: application/json
Authorization: Bearer YOUR_TOKEN
{
"product_type": "trading",
"customer_guid": "customer_guid",
"symbol": "USDC_SOL-CAD",
"side": "buy",
"deliver_amount": 10000
}{
"guid": "quote_guid",
"product_type": "trading",
"customer_guid": "customer_guid",
"symbol": "USDC_SOL-CAD",
"side": "buy",
"receive_amount": 7200000,
"deliver_amount": 10000,
"fee": 0,
"issued_at": "2026-07-19T12:00:00.000Z",
"expires_at": "2026-07-19T12:00:30.000Z",
"created_at": "2026-07-19T12:00:00.000Z",
"updated_at": "2026-07-19T12:00:00.000Z"
}
Quotes expire in 30 secondsQuotes are valid for 30 seconds. Use the
expires_atfield on the quote response to determine when a quote expires. Trades or transfers against expired quotes fail.
Execute the trade
Endpoint: POST /api/trades Reference: Create Trade
POST /api/trades
Content-Type: application/json
Authorization: Bearer YOUR_TOKEN
{
"quote_guid": "quote_guid"
}{
"guid": "trade_guid",
"trade_type": "platform",
"customer_guid": "customer_guid",
"quote_guid": "quote_guid",
"symbol": "USDC_SOL-CAD",
"side": "buy",
"state": "storing",
"receive_amount": 7200000,
"deliver_amount": 10000,
"fee": 0,
"created_at": "2026-07-19T12:00:00.000Z",
"updated_at": "2026-07-19T12:00:00.000Z"
}Trade states
| State | Description |
|---|---|
storing | Platform is storing trade details |
pending | Trade pending execution |
executed | Trade executed on exchange |
settling | Trade settling |
completed | Trade completed; USDC_SOL is available in the trading account |
cancelled | Trade cancelled |
failed | Trade failed |
Webhook Events: trade.pending, trade.completed, trade.failed
Poll GET /api/trades/{trade_guid} or subscribe to the trade.completed webhook until state transitions to completed.
Related: Execute Trades
CheckpointThe trade is
completedand USDC_SOL is available in the trading account. This balance is the source for the remittance plan.
7. Create the recipient counterparty
Create the recipient as a customer-level individual counterparty and verify it via watchlists. The counterparty must reach the verified state before you can create the recipient external bank account and the remittance plan.
Create the counterparty
Endpoint: POST /api/counterparties Reference: Create Counterparty
Include only the required fields: type, name, address.city, and address.country_code. Add customer_guid for the customer-scoped counterparty.
POST /api/counterparties
Content-Type: application/json
Authorization: Bearer YOUR_TOKEN
{
"type": "individual",
"customer_guid": "customer_guid",
"name": {
"first": "John",
"last": "Doe"
},
"address": {
"city": "Mumbai",
"country_code": "IN"
}
}{
"guid": "recipient_counterparty_guid",
"type": "individual",
"customer_guid": "customer_guid",
"state": "storing",
"created_at": "2026-07-19T12:00:00.000Z",
"updated_at": "2026-07-19T12:00:00.000Z"
}
Required fields onlyFor individual counterparties the required fields are
type,name.first,name.last,address.city, andaddress.country_code. Addcustomer_guidfor customer-scoped counterparties created with a bank token. The API spec marks onlycountry_codeas required onaddress, but the Cybrid platform enforcescity+country_codetogether — see Create a Counterparty.
Corridor-specific fieldsFor Cybrid-managed remittance corridors, the destination country may require additional fields on the recipient counterparty (
date_of_birth,identification_numbers, addressstreet+subdivision, etc.). Refer to the relevant payout guide for the destination country before omitting fields in production. See Supported Corridors.
Verify the counterparty
Endpoint: POST /api/identity_verifications Reference: Create Identity Verification
Counterparty verification screens the recipient's PII through watchlist checks against government sanctions lists, PEP databases, and adverse media sources. It is an API call that does not require an SDK.
POST /api/identity_verifications
Content-Type: application/json
Authorization: Bearer YOUR_TOKEN
{
"type": "counterparty",
"method": "watchlists",
"counterparty_guid": "recipient_counterparty_guid"
}{
"guid": "identity_verification_guid",
"type": "counterparty",
"method": "watchlists",
"counterparty_guid": "recipient_counterparty_guid",
"customer_guid": "customer_guid",
"state": "storing",
"outcome": null,
"failure_codes": [],
"created_at": "2026-07-19T12:00:00.000Z",
"updated_at": "2026-07-19T12:00:00.000Z"
}Counterparty states
| State | Description |
|---|---|
storing | Platform is storing counterparty details |
unverified | Counterparty created, awaiting verification |
verified | Counterparty verified via watchlist check |
rejected | Counterparty rejected |
Poll GET /api/identity_verifications/{identity_verification_guid} until state transitions to completed. When outcome is passed, the counterparty transitions to verified; when failed, inspect failure_codes (for example watchlist_check_failure, pep_check_failure, media_check_failure) and the counterparty transitions to rejected. The platform checks counterparty verification results at one-minute intervals, so completion may take up to one minute.
Webhook Events: identity_verification.waiting, identity_verification.completed
Related: Verify a Counterparty · Creating Counterparties
8. Create the recipient external bank account
Create the recipient's foreign external bank account tied to the verified counterparty. The example below uses India (INR over IFSC); required fields vary by destination corridor.
Endpoint: POST /api/external_bank_accounts Reference: Create External Bank Account
Use raw routing details for foreign payoutsUse
account_kindraw_routing_detailsfor the recipient's foreign bank account and tie it to the verifiedcounterparty_guid. Thepayment_railandbank_code_typedepend on the destination corridor —IFSCfor India, and other rails (SPEI,PIX,SEPA, and so on) for other corridors.
Accept-Version for foreign raw-routing accountsCreating foreign raw-routing external bank accounts requires
Accept-Version: 2025-10-01or later. Corridor-specific bank-account fields vary by destination; refer to the relevant payout guide before omitting fields in production.
POST /api/external_bank_accounts
Content-Type: application/json
Accept-Version: 2025-10-01
Authorization: Bearer YOUR_TOKEN
{
"name": "Recipient INR Account",
"account_kind": "raw_routing_details",
"customer_guid": "customer_guid",
"counterparty_guid": "recipient_counterparty_guid",
"asset": "INR",
"counterparty_bank_account_details": [
{
"account_identifier": "account_number",
"payment_rail": "IFSC",
"bank_code": "bank_ifsc_code",
"bank_code_type": "IFSC"
}
]
}{
"guid": "recipient_external_bank_account_guid",
"name": "Recipient INR Account",
"asset": "INR",
"account_kind": "raw_routing_details",
"environment": "sandbox",
"bank_guid": "bank_guid",
"customer_guid": "customer_guid",
"counterparty_guid": "recipient_counterparty_guid",
"state": "storing",
"created_at": "2026-07-19T12:00:00.000Z",
"updated_at": "2026-07-19T12:00:00.000Z"
}
Counterparty must be verifiedThe referenced counterparty must be in the
verifiedstate. Creating an external bank account against an unverified counterparty fails with theunverified_counterpartyfailure code.
External bank account states
| State | Description |
|---|---|
storing | Platform is storing external bank account details |
completed | External bank account created |
unverified | External bank account created but not yet verified |
failed | External bank account creation failed |
refresh_required | External bank account needs to be refreshed |
deleting | Platform is deleting the external bank account |
deleted | External bank account deleted |
Poll GET /api/external_bank_accounts/{external_bank_account_guid} until state transitions to completed.
Related: Foreign Fiat External Bank Accounts · Add External Bank Accounts
CheckpointThe recipient counterparty is
verifiedand their foreign external bank account iscompleted. You have everything needed to create and execute the remittance plan.
9. Create and execute the remittance plan
Create a remittance plan with the USDC_SOL trading account as the source and the recipient's foreign external bank account as the destination, then execute it. Cybrid converts USDC_SOL to INR and pays out over the local rail.
Create the remittance plan
Endpoint: POST /api/plans Reference: Create Plan
POST /api/plans
Content-Type: application/json
Authorization: Bearer YOUR_TOKEN
{
"type": "remittance",
"customer_guid": "customer_guid",
"source_account": {
"guid": "trading_account_usdc_sol_guid",
"amount": 7200000
},
"destination_account": {
"guid": "recipient_external_bank_account_guid"
},
"purpose_of_transaction": "family_support"
}{
"guid": "plan_guid",
"type": "remittance",
"customer_guid": "customer_guid",
"state": "storing",
"expires_at": "2026-07-19T12:00:30.000Z",
"source_account": {
"guid": "trading_account_usdc_sol_guid",
"type": "trading",
"asset": "USDC_SOL",
"requested_amount": 7200000
},
"destination_account": {
"guid": "recipient_external_bank_account_guid",
"type": "external_bank_account",
"asset": "INR"
},
"stages": [],
"fees": [],
"created_at": "2026-07-19T12:00:00.000Z",
"updated_at": "2026-07-19T12:00:00.000Z"
}Plan states
| State | Description |
|---|---|
storing | Platform is storing plan details |
planning | Platform is building the plan |
completed | Plan is ready for execution |
failed | Plan creation failed |
Poll GET /api/plans/{plan_guid} until state transitions to completed, then execute it before it expires.
Webhook Events: plan.planning, plan.completed, plan.failed
Enable the remittance featureContact Cybrid support to enable the remittance feature on your bank before using this operation.
Specify the amount on the source accountYou must specify an amount on either the source or destination account — the amount drives the plan's quote. If source amount is specified, the plan ensures that amount is debited. If destination amount is specified, the plan ensures that exact amount is deposited. Include
amountundersource_accountby default, expressed in the source account asset's base units (USDC_SOL).
Purpose of transaction
purpose_of_transactionis corridor-dependent. Some destinations reject a plan without an accepted purpose (invalid_purpose_of_transaction). Refer to the destination payout guide for accepted values.
Supporting documents (corridor-dependent)Some corridors require supporting documents attached to the plan's
supporting_documents(for example, aninvoicecarrying adocument_reference_number). This is most common for B2B payouts — see the "Upload a supporting document" step in the CA B2B and US B2B integration guides, and File Upload, before going live.
Travel rule informationTravel rule information is required only when the originator is not the holder of the trading account or when the receiver is not the holder of the external bank account.
Reversals may incur feesIf the final withdrawal to the destination bank account fails after currency conversions have occurred, any reversals may incur fees.
Execute the plan
Endpoint: POST /api/executions Reference: Create Execution
POST /api/executions
Content-Type: application/json
Authorization: Bearer YOUR_TOKEN
{
"plan_guid": "plan_guid"
}{
"guid": "execution_guid",
"type": "remittance",
"plan_guid": "plan_guid",
"customer_guid": "customer_guid",
"state": "storing",
"source_account": {
"guid": "trading_account_usdc_sol_guid",
"type": "trading",
"asset": "USDC_SOL"
},
"destination_account": {
"guid": "recipient_external_bank_account_guid",
"type": "external_bank_account",
"asset": "INR"
},
"stages": [],
"fees": [],
"created_at": "2026-07-19T12:00:00.000Z",
"updated_at": "2026-07-19T12:00:00.000Z"
}Execution states
| State | Description |
|---|---|
storing | Platform is storing execution details |
executing | Platform is executing the plan |
completed | Plan execution completed successfully |
failed | Plan execution failed |
Webhook Events: execution.executing, execution.completed, execution.failed
Poll GET /api/executions/{execution_guid} or subscribe to the execution.completed webhook until state transitions to completed. On failure, inspect the failure_code (for example compliance_rejection, invalid_destination, party_name_invalid, external_vendor_error).
Creating an execution initiates the transactionCreating an execution initiates the actual transaction. Ensure the plan has been reviewed and is ready before executing.
Plans expire quicklyRemittance plans expire (default ~60 seconds,
plan_expirederror). Use theexpires_atfield on the plan response to confirm when the plan expires, and execute it before then.
Executed amountsThe executed amounts in the response represent the actual amounts transferred, which should match the quoted amounts from the plan.
Related: Sending Cross-Border Payments · Payout Prices
Webhooks
Subscribe to webhooks for real-time notifications instead of polling. Configure webhook endpoints in your bank settings. Accounts, deposit bank accounts, and external bank accounts have no webhook events in this integration — use polling for those resources.
Webhook eventsThis integration uses the following webhook events:
Event Trigger identity_verification.waitingIdentity verification is waiting for the customer to start. identity_verification.completedIdentity verification completed (check outcome). transfer.pendingE-Transfer funding transfer is pending; gateway_urlavailable.transfer.completedFunding transfer completed. transfer.failedFunding transfer failed. transfer.cancellingFunding transfer is being cancelled. trade.pendingCAD to USDC_SOL trade is pending. trade.completedTrade completed. trade.failedTrade failed. plan.planningRemittance plan is being built. plan.completedRemittance plan is ready for execution. plan.failedRemittance plan creation failed. execution.executingRemittance execution is running. execution.completedRemittance payout completed. execution.failedRemittance execution failed. See: Webhook Events
Additional resources
- Introduction
- Interac e-Transfer
- Sending Cross-Border Payments
- Supported Corridors
- Foreign Fiat External Bank Accounts
- Customer Deposit Bank Accounts
Updated 19 days ago

