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.
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
thecustomer_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} 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 themain
deposit 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-basedfiataccounts.
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 asynchronous
gateway_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. Includeamount
undersource_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 about 16 hours ago

