Skip to content

Search is only available in production builds. Try building and previewing the site to test it out locally.

Payout Flow Diagram

This guide illustrates the complete PayOut flow from quotation to completion, including all API calls, validations, and webhook events.


Complete Integration Flow

┌─────────────────────────────────────────────────────────────────────────────┐
│ PAYOUT INTEGRATION FLOW │
└─────────────────────────────────────────────────────────────────────────────┘
┌─────────┐ ┌─────────────┐ ┌─────────────┐ ┌─────────────────┐
│ Your │ │ Cashela │ │ Payer │ │ Your Server │
│ Client │ │ API │ │ Network │ │ (Webhooks) │
└────┬────┘ └──────┬──────┘ └──────┬──────┘ └────────┬────────┘
│ │ │ │
│ 1. Get Countries/Services │ │
│─────────────────► │ │
│ ◄─────────────── [BRA, MEX, COL] │ │
│ │ │ │
│ 2. Get Available Payers │ │
│─────────────────► │ │
│ ◄─────────────── [Banks, Wallets] │ │
│ │ │ │
│ 3. Create Quotation │ │
│─────────────────► │ │
│ ◄─────────────── Locked Rate + Fees│ │
│ (quotation_id, expires_at) │ │
│ │ │ │
│ 4. Collect Beneficiary Details │ │
│ (Based on payer requirements) │ │
│ │ │ │
│ 5. Create Transaction │ │
│─────────────────► │ │
│ ◄─────────────── Transaction Created│ │
│ │ │ │
│ │ 6. Submit to Payer │
│ │─────────────────► │ │
│ │ │ │
│ │ 7. Payer Confirms │ │
│ │◄──────────────────│ │
│ │ │ │
│ │ 8. Webhook Notification │
│ │───────────────────────────────────────►│
│ │ │ │
│ │ 9. Acknowledge (200 OK) │
│ │◄───────────────────────────────────────│
│ │ │ │
│ 10. Get Transaction Status │ │
│─────────────────► │ │
│ ◄─────────────── COMPLETED │ │
│ │ │ │

Step-by-Step Process

Step 1: Get Countries & Services

Retrieve supported destination countries and available payout services.

GET /api/v1/pay-out/countries
GET /api/v1/pay-out/services

Purpose: Determine where you can send money and through which channels.


Step 2: Get Available Payers

Fetch the list of banks, wallets, and cash pickup locations for the destination.

GET /api/v1/pay-out/payers?country_iso_code=BRA&currency=BRL

Purpose: Show the beneficiary their delivery options with requirements.


Step 3: Create Quotation

Lock in the exchange rate and calculate fees before the user commits.

POST /api/v1/pay-out/quotation

Purpose: Display the exact amount the beneficiary will receive with all fees disclosed.

Important: The quotation is valid for a limited time (typically 1 hour). Complete the transaction before expiration.


Step 4: Collect Beneficiary Details

Based on the selected payer, collect required information:

Delivery MethodRequired Fields
Bank TransferAccount number, branch code, account type
Mobile WalletMobile number, wallet type
Cash PickupID type, ID number, pickup location

Step 5: Create Transaction

Submit the payout request with all sender and beneficiary details.

POST /api/v1/pay-out/transaction

Purpose: Initiate the money transfer using the locked quotation.


Steps 6-9: Processing & Webhooks

The payout is processed through the payer network. Your server receives webhook notifications for status changes.


Step 10: Verify Transaction Status

Optionally query the transaction status for confirmation.

GET /api/v1/pay-out/transaction/{id}

State Machine

┌─────────────┐
│ CREATED │
└──────┬──────┘
┌──────▼──────┐
│ PROCESSING │
└──────┬──────┘
┌──────▼──────┐
│ SUBMITTED │
└──────┬──────┘
┌─────────────────┼─────────────────┐
│ │ │
┌──────▼──────┐ ┌──────▼──────┐ ┌──────▼──────┐
│ COMPLETED │ │ FAILED │ │ CANCELLED │
└─────────────┘ └─────────────┘ └─────────────┘
│ │
┌──────▼──────┐ ┌──────▼──────┐
│ (Final) │ │ REFUNDED │
└─────────────┘ └─────────────┘
StatusDescriptionTerminal
CREATEDTransaction created, being validatedNo
PROCESSINGSubmitted to internal processingNo
SUBMITTEDSent to payer networkNo
COMPLETEDFunds delivered to beneficiaryYes
FAILEDTransaction failed (see reason)Yes
CANCELLEDTransaction was cancelledYes
REFUNDEDFunds returned to your accountYes

Quotation Expiration Handling

Quotations have a limited validity window. Implement proper handling:

async function createPayoutWithQuotation(payoutData) {
// 1. Create quotation
const quotation = await api.createQuotation({
source_currency: 'USD',
destination_currency: 'BRL',
amount: payoutData.amount,
payer_id: payoutData.payerId
});
// 2. Check if quotation will expire soon
const expiresAt = new Date(quotation.expiration_date);
const now = new Date();
const minutesRemaining = (expiresAt - now) / (1000 * 60);
if (minutesRemaining < 5) {
// Refresh quotation if expiring soon
return createPayoutWithQuotation(payoutData);
}
// 3. Display quotation details to user
await displayQuotationToUser(quotation);
// 4. User confirms - create transaction
const transaction = await api.createTransaction({
quotation_id: quotation.id,
...payoutData
});
return transaction;
}

Integration Patterns

Pattern 1: Form-Based Flow

Best for: Step-by-step wizard interfaces

// Step 1: Select destination
const countries = await api.getCountries();
const selectedCountry = await showCountrySelector(countries);
// Step 2: Select payer
const payers = await api.getPayers({ country_iso_code: selectedCountry });
const selectedPayer = await showPayerSelector(payers);
// Step 3: Enter amount and get quote
const quotation = await api.createQuotation({
destination_country: selectedCountry,
payer_id: selectedPayer.id,
source_amount: amount
});
await showQuotationReview(quotation);
// Step 4: Collect beneficiary details
const beneficiaryFields = selectedPayer.required_receiving_entity_fields;
const beneficiaryData = await collectBeneficiaryData(beneficiaryFields);
// Step 5: Submit transaction
const transaction = await api.createTransaction({
quotation_id: quotation.id,
beneficiary: beneficiaryData,
sender: senderData
});

Pattern 2: Saved Beneficiary Flow

Best for: Repeat transfers to same beneficiary

// User has saved beneficiaries
const savedBeneficiaries = await db.getSavedBeneficiaries(userId);
// Select beneficiary
const beneficiary = await showBeneficiarySelector(savedBeneficiaries);
// Create quotation with known payer
const quotation = await api.createQuotation({
payer_id: beneficiary.payer_id,
source_amount: amount
});
// Direct to confirmation - skip data collection
const transaction = await api.createTransaction({
quotation_id: quotation.id,
beneficiary: beneficiary.details,
sender: senderData,
external_identifier: `repeat_${beneficiary.id}_${Date.now()}`
});

Error Handling

Common Errors and Resolutions

ErrorCauseResolution
QUOTATION_EXPIREDRate lock expiredCreate new quotation
INSUFFICIENT_FUNDSLow account balanceTop up balance
INVALID_ACCOUNTWrong account numberVerify beneficiary details
PAYER_UNAVAILABLEPayer temporarily downTry alternative payer
COMPLIANCE_HOLDRequires reviewContact support

Retry Strategy

function isRetryable(error) {
const retryableCodes = [
'RATE_LIMITED',
'INTERNAL_ERROR',
'PAYER_TIMEOUT',
'SERVICE_UNAVAILABLE'
];
return retryableCodes.includes(error.code);
}
async function createTransactionWithRetry(data, maxRetries = 3) {
const idempotencyKey = crypto.randomUUID();
for (let attempt = 1; attempt <= maxRetries; attempt++) {
try {
return await api.createTransaction(data, { idempotencyKey });
} catch (error) {
if (error.code === 'QUOTATION_EXPIRED') {
// Need new quotation - cannot retry
throw error;
}
if (isRetryable(error) && attempt < maxRetries) {
const delay = Math.pow(2, attempt) * 1000;
await sleep(delay);
continue;
}
throw error;
}
}
}

Best Practices Checklist

  • Always use quotations – Never assume exchange rates
  • Validate beneficiary data – Check format before submitting
  • Handle quotation expiry – Refresh if close to expiration
  • Use idempotency keys – Prevent duplicate transactions
  • Implement webhook handlers – Process all status updates
  • Store transaction references – Keep both your ID and Cashela’s
  • Log all API calls – Include request_id for support
  • Test with sandbox – Verify all corridors before production