Sending Cross-Border Payments
How do I send cross-border payments?
This guide walks you through sending funds from a Cybrid trading account to a foreign bank account using the remittance product. Cross-border payments include automatic currency conversion and competitive exchange rates.
Enable remittanceContact Cybrid support to enable the remittance feature on your bank.
Overview
The remittance process involves four main steps:
- Create a remittance plan
- Wait for planning to complete
- Execute the plan
- Monitor execution completion
flowchart LR
%% Subgraph
subgraph RP["Remittance Process"]
direction LR
A("📝 Create Remittance Plan")
B("⏳ Planning In Progress")
C("⚙️ Execute Plan")
D("📊 Monitor Execution Completion")
A --> B --> C --> D
end
%% Styling
classDef step fill:#F5F7FF,stroke:#5B6CFF,stroke-width:1.5px,color:#1A1A1A;
classDef container fill:#EEF1FF,stroke:#3F51FF,stroke-width:2px,color:#1A1A1A;
class A,B,C,D step;
class RP container;
Prerequisites
Before you begin, ensure you have:
- A verified customer entity
- A verified counterparty entity (as the recipient)
- A trading account with sufficient funds
- An external bank account in
completedstate with raw routing details
The source trading account must:
- Be in
createdstate - Belong to a verified customer (not frozen, not rejected)
The destination external bank account must:
- Have
kind: raw_routing_details - Be in
completedstate - Meet KYC requirements for the destination country and currency
Step 1: Create a remittance plan
Create a plan that calculates estimated amounts, fees, and exchange rates.
Request
POST /api/plans
Authorization: Bearer YOUR_TOKEN
Content-Type: application/json
{
"type": "remittance",
"customer_guid": "customer_guid",
"source_account": {
"guid": "source_account_guid"
},
"destination_account": {
"guid": "destination_account_guid",
"amount": 10000
},
"purpose_of_transaction": "family_support",
"travel_rule_info": {
"ultimate_originating_party_guid": "originating_party_guid",
"ultimate_receiving_party_guid": "receiving_party_guid"
}
}Request fields
-
type (required) - Set to
remittancefor cross-border payments. -
customer_guid or bank_guid (required) - The owner of the plan. Use
customer_guidfor customer-owned plans orbank_guidfor bank-owned plans. These fields are mutually exclusive. -
source_account (required) - The trading account funding the remittance.
guid- Required. The trading account identifier.amount- Optional. The amount to withdraw from the source account in base units.
-
destination_account (required) - The external bank account receiving the funds.
guid- Required. The external bank account identifier.amount- Optional. The amount to deposit in the destination account in base units.
Amount specificationYou must specify EITHER
source_account.amountORdestination_account.amount, but not both or neither. When you specify the destination amount, the system calculates the required source amount (including fees and exchange rates). When you specify the source amount, the system calculates the resulting destination amount.
-
purpose_of_transaction (conditionally required) - Required for certain destination countries. Example values include:
family_support,education,gift,medical_treatment,salary_payment,loan_payment, andother. See the API reference for the complete list of 30+ options. -
travel_rule_info (optional) - Required when the originator or receiver differs from the account holders. Valid entity types for parties:
customer,counterparty,bank.ultimate_originating_party_guid- Required when the funds originate from someone other than the trading account holder (for example, a bank acting on behalf of a customer).ultimate_receiving_party_guid- Required when the final beneficiary differs from the external bank account holder.
Response
Initially, the plan returns in storing state while the system calculates rates and fees.
Step 2: Wait for planning to complete
Poll the plan endpoint until the state changes to completed, indicating it's ready for execution.
GET /api/plans/plan_guid
Authorization: Bearer YOUR_TOKEN{
"created_at": "2025-10-04T12:59:15.732645Z",
"updated_at": "2025-10-04T12:59:17.249897Z",
"guid": "4384639658a5970ca442030d4d1eae98",
"state": "completed",
"type": "remittance",
"customer_guid": "customer_guid",
"failure_code": null,
"stages": [
{
"created_at": "2025-10-04T12:59:17.132720Z",
"updated_at": "2025-10-04T12:59:17.132720Z",
"guid": "05a518360c38ea017eb8fb539665fdc6",
"type": "payout",
"failure_code": null,
"state": "planned",
"source_account": {
"guid": "source_account_guid",
"asset": "USDC",
"type": "trading",
"bank_guid": "bank_guid",
"customer_guid": "customer_guid",
"counterparty_guid": null,
"requested_amount": null,
"quoted_amount": 5531070,
"executed_amount": null
},
"destination_account": {
"guid": "destination_account_guid",
"asset": "MXN",
"type": "external_bank_account",
"bank_guid": "bank_guid",
"customer_guid": "customer_guid",
"counterparty_guid": "counterparty_guid",
"requested_amount": 10000,
"quoted_amount": 10000,
"executed_amount": null
},
"fees": [
{
"type": "bank",
"asset": "USDC",
"quoted_amount": 27518,
"executed_amount": null
},
{
"type": "platform",
"asset": "USDC",
"quoted_amount": 27518,
"executed_amount": null
},
{
"type": "network",
"asset": "ETH",
"quoted_amount": 100000000000,
"executed_amount": null
}
]
}
],
"source_account": {
"guid": "source_account_guid",
"asset": "USDC",
"type": "trading",
"bank_guid": "bank_guid",
"customer_guid": "customer_guid",
"counterparty_guid": null,
"requested_amount": null,
"quoted_amount": 5531070,
"executed_amount": null
},
"destination_account": {
"guid": "destination_account_guid",
"asset": "MXN",
"type": "external_bank_account",
"bank_guid": "bank_guid",
"customer_guid": "customer_guid",
"counterparty_guid": "counterparty_guid",
"requested_amount": 10000,
"quoted_amount": 10000,
"executed_amount": null
},
"fees": [
{
"type": "bank",
"asset": "USDC",
"quoted_amount": 27518,
"executed_amount": null
},
{
"type": "platform",
"asset": "USDC",
"quoted_amount": 27518,
"executed_amount": null
},
{
"type": "network",
"asset": "ETH",
"quoted_amount": 100000000000,
"executed_amount": null
}
],
"travel_rule_info": {
"originating_party": {
"participant_guid": "customer_guid",
"type": "customer"
},
"receiving_party": {
"participant_guid": "counterparty_guid",
"type": "counterparty"
},
"ultimate_originating_party": {
"participant_guid": "bank_guid",
"type": "bank"
},
"ultimate_receiving_party": {
"participant_guid": "counterparty_guid",
"type": "counterparty"
}
}
}
Plan expirationPlans expire after a configured period (see the
expires_atfield in the response). An expired plan cannot be executed and results in aplan_expirederror. Check the plan state before execution.
Polling recommendationsPoll every 2-5 seconds for plan completion. Plans typically complete within 10-30 seconds. Implement exponential backoff for longer-running operations. The platform does not currently support webhook events for plans.
Step 3: Execute the remittance plan
Execute the plan by creating an execution.
Currency conversion feesThe remittance process involves currency conversions to facilitate the cross-border payment. If the final withdrawal to the destination bank account fails after conversions occur, any reversals may incur fees.
Verify routing detailsPerform test deposits for new bank accounts and double-check all external bank account routing details before execution. Common issues that cause withdrawal failures include:
- Incorrect CLABE numbers or routing codes
- Mismatched account holder names
- Invalid or closed bank accounts
- Incorrect bank identifiers
POST /api/executions
Authorization: Bearer YOUR_TOKEN
Content-Type: application/json
{
"plan_guid": "plan_guid"
}Response
The response returns a storing state while the platform executes the remittance.
Step 4: Monitor execution completion
Poll the execution endpoint until the state changes to completed.
Polling recommendationsPoll every 5-10 seconds for execution completion. Executions can take several minutes depending on the destination country and payment rail. Implement exponential backoff for longer operations. The platform does not currently support webhook events for executions.
GET /api/executions/execution_guid
Authorization: Bearer YOUR_TOKEN{
"created_at": "2025-10-04T14:25:22.816775Z",
"updated_at": "2025-10-04T14:28:48.663787Z",
"guid": "execution_guid",
"state": "completed",
"type": "remittance",
"plan_guid": "plan_guid",
"customer_guid": "customer_guid",
"failure_code": null,
"stages": [
{
"created_at": "2025-10-04T14:24:55.865059Z",
"updated_at": "2025-10-04T14:28:48.562584Z",
"guid": "stage_guid",
"type": "payout",
"failure_code": null,
"state": "completed",
"source_account": {
"guid": "source_account_guid",
"asset": "USDC",
"type": "trading",
"bank_guid": "bank_guid",
"customer_guid": "customer_guid",
"counterparty_guid": null,
"requested_amount": null,
"quoted_amount": 5532205,
"executed_amount": 5532205
},
"destination_account": {
"guid": "destination_account_guid",
"asset": "MXN",
"type": "external_bank_account",
"bank_guid": "bank_guid",
"customer_guid": "customer_guid",
"counterparty_guid": "counterparty_guid",
"requested_amount": 10000,
"quoted_amount": 10000,
"executed_amount": 10000
},
"fees": [
{
"type": "bank",
"asset": "USDC",
"quoted_amount": 27524,
"executed_amount": 27524
},
{
"type": "platform",
"asset": "USDC",
"quoted_amount": 27524,
"executed_amount": 27524
},
{
"type": "network",
"asset": "ETH",
"quoted_amount": 100000000000,
"executed_amount": 100000000000
}
]
}
],
"source_account": {
"guid": "source_account_guid",
"asset": "USDC",
"type": "trading",
"bank_guid": "bank_guid",
"customer_guid": "customer_guid",
"counterparty_guid": null,
"requested_amount": null,
"quoted_amount": 5532205,
"executed_amount": null
},
"destination_account": {
"guid": "destination_account_guid",
"asset": "MXN",
"type": "external_bank_account",
"bank_guid": "bank_guid",
"customer_guid": "customer_guid",
"counterparty_guid": "counterparty_guid",
"requested_amount": 10000,
"quoted_amount": 10000,
"executed_amount": 10000
},
"fees": [
{
"type": "bank",
"asset": "USDC",
"quoted_amount": 27524,
"executed_amount": 27524
},
{
"type": "platform",
"asset": "USDC",
"quoted_amount": 27524,
"executed_amount": 27524
},
{
"type": "network",
"asset": "ETH",
"quoted_amount": 100000000000,
"executed_amount": 100000000000
}
],
"travel_rule_info": {
"originating_party": {
"participant_guid": "customer_guid",
"type": "customer"
},
"receiving_party": {
"participant_guid": "counterparty_guid",
"type": "counterparty"
},
"ultimate_originating_party": {
"participant_guid": "bank_guid",
"type": "bank"
},
"ultimate_receiving_party": {
"participant_guid": "counterparty_guid",
"type": "counterparty"
}
}
}Understanding the response
Plan and execution responses share a common structure with the following key fields:
Source account
- quoted_amount - The cryptocurrency amount calculated at planning time
- executed_amount - The actual cryptocurrency amount withdrawn (populated after execution)
If you specified source_account.amount in the request, the quoted amount matches the requested
amount. For the remittance product, the executed amount matches the quoted amount.
Destination account
- quoted_amount - The destination currency amount calculated at planning time
- executed_amount - The actual amount deposited in the external bank account
If you specified destination_account.amount in the request, the quoted amount matches the
requested amount.
Fees
Remittance fees include platform fees, bank fees, and network fees:
- quoted_amount - The estimated fee at planning time
- executed_amount - The actual fee charged at execution time
Fee variabilityNetwork fees, especially for cryptocurrency conversions, may vary between quote and execution due to blockchain network conditions. The
executed_amountreflects the actual fees charged.
Stages
Stages provide a view into the lifecycle of a plan. For the remittance product, there is only one
stage payout where the funds transfer from the trading account to the external bank account.
Error handling
Plan creation errors (HTTP 422)
| Error code | Description |
|---|---|
| unknown_bank_exception | Bank not found |
| no_customer_exception | Customer not found |
| frozen_customer_exception | Customer is frozen |
| rejected_customer_exception | Customer is rejected |
| unverified_customer_exception | Customer not verified |
| no_source_account_exception | Source account not found |
Execution creation errors
| Error Code | Description |
|---|---|
plan_expired | Plan has expired and cannot be executed |
invalid_parameter | Plan not in valid state or already executed |
List plans and executions
List plans
Retrieve plans filtered by customer, state, or other criteria.
GET /api/plans?customer_guid=customer_guid&state=completed
Authorization: Bearer YOUR_TOKENList executions
Retrieve executions for a specific plan or customer.
GET /api/executions?plan_guid=plan_guid
Authorization: Bearer YOUR_TOKENSee the Plans API reference and Executions API reference for all available filters.
Reference
Supported corridors
Cybrid supports the following destination currencies and payment rails:
| Currency | Country | Payment Rail | Routing Details |
|---|---|---|---|
| MXN | Mexico | SPEI | CLABE |
| ARS | Argentina | COELSA | CVU/CBU |
| COP | Colombia | PSE | PSE (requires account_type) |
| BRL | Brazil | PIX | PIX key (phone, email, CPF, CNPJ, random) |
| INR | India | IFSC | IFSC code + account number |
For details on creating external bank accounts with these routing details, see Foreign Fiat External Bank Accounts.
Country-specific requirementsSome corridors have country-specific requirements (KYC fields, purpose restrictions, participant types). See the corridor-specific guides:
- Payouts to India — C2C only, restricted purpose values
Upcoming corridors
| Country | Status | Currency |
|---|---|---|
| Bangladesh | Coming soon | BDT |
| Ghana | Coming soon | GHS |
| Kenya | Coming soon | KES |
| Nigeria | Coming soon | NGN |
| Pakistan | Coming soon | PKR |
Amount base units
The API specifies all amounts in base units (the smallest denomination of the currency):
| Currency | Decimals | Example |
|---|---|---|
| USDC | 6 | 1 USDC = 1,000,000 base units |
| MXN | 2 | 1 MXN = 100 centavos |
| BRL | 2 | 1 BRL = 100 centavos |
| INR | 2 | 1 INR = 100 paise |
| ARS | 2 | 1 ARS = 100 centavos |
| COP | 2 | 1 COP = 100 centavos |
To send 100 MXN, specify amount: 10000 (100 × 100 centavos).
Plan states
| State | Description |
|---|---|
storing | Initial state while the system creates the plan |
planning | The system calculates rate quotes and fees |
completed | Plan is ready for execution |
failed | Planning failed (check failure_code) |
Execution states
| State | Description |
|---|---|
storing | Initial state while the system creates the execution |
executing | Remittance is in progress |
completed | Remittance completed successfully |
failed | Execution failed (check failure_code) |
Updated 4 days ago
