Skip to content

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

Settlement Times & Processing Flows

Settlement and processing times vary based on payment method, destination country, payer network, and transaction time. This guide helps you set accurate expectations for your users and manage your treasury operations.


PayIn Settlement

When a Pay-In deposit reaches COMPLETED, the net amount (net_amount, in settlement_currency, as reported in the notification) is credited to your Cashela account. Credited funds are released for use according to Cashela’s settlement schedule and your agreement with Cashela.

  • Reconcile money only on COMPLETED and REVERSED deposits. DECLINED, CANCELLED and FAILED deposits move no money.
  • A full void or refund of a card deposit takes the principal plus the Cashela fee back from your balance. See Voids and refunds.
  • How long your customer takes to pay depends on the payment method; card payments must be completed within the checkout’s validity_period (about one hour).

PayOut Settlement

Overview

PayOut settlement refers to when funds are delivered to the beneficiary’s account or available for pickup.

Settlement by Delivery Method

Delivery MethodTypical SettlementCutoff Impact
Bank Transfer (ACH)1 – 2 business daysNext day if before cutoff
Bank Transfer (Instant)Minutes to 4 hours24/7 availability
PIX (Brazil)Instant24/7 availability
SPEI (Mexico)Minutes to 2 hoursExtended hours (6AM-11PM)
Cash Pickup15 min – 4 hoursPartner location hours
Mobile WalletMinutes to 1 hour24/7 availability
SWIFT2 – 5 business daysBanking hours only

Processing Cutoff Times

Many payers have daily cutoff times. Transactions submitted after cutoff are processed the next business day.

function getExpectedDelivery(payer, submissionTime) {
const cutoffTime = payer.cut_off_time; // e.g., "16:00"
const timezone = payer.cut_off_timezone; // e.g., "America/Sao_Paulo"
// Convert submission time to payer's timezone
const localTime = submissionTime.toLocaleString('en-US', { timeZone: timezone });
const [cutoffHour, cutoffMinute] = cutoffTime.split(':').map(Number);
// Check if after cutoff
const localHour = new Date(localTime).getHours();
const isAfterCutoff = localHour >= cutoffHour;
// Calculate expected delivery
let deliveryDate = new Date(submissionTime);
if (isAfterCutoff) {
// Add one business day
deliveryDate = addBusinessDays(deliveryDate, 1, timezone);
}
// Add payer's typical processing time
const minHours = payer.estimated_delivery.minimum_hours;
const maxHours = payer.estimated_delivery.maximum_hours;
return {
earliest: new Date(deliveryDate.getTime() + minHours * 3600000),
latest: new Date(deliveryDate.getTime() + maxHours * 3600000),
isAfterCutoff
};
}

Real-Time Processing

Processing Flow

All transactions go through a real-time processing pipeline:

┌─────────────┐ ┌──────────────┐ ┌────────────────┐
│ Transaction │────►│ Validation & │────►│ Provider/Payer │
│ Created │ │ Compliance │ │ Submission │
└─────────────┘ └──────────────┘ └───────┬────────┘
│
▼
┌─────────────┐ ┌──────────────┐ ┌────────────────┐
│ Webhook │◄────│ Status │◄────│ Provider │
│ Delivered │ │ Update │ │ Processing │
└─────────────┘ └──────────────┘ └────────────────┘

Status Updates

Receive real-time status updates via webhooks:

StatusDescriptionWebhook Event
CREATEDTransaction initializedtransaction.created
PROCESSINGBeing processedtransaction.processing
SUBMITTEDSent to providertransaction.submitted
COMPLETEDSuccessfully deliveredtransaction.completed
FAILEDProcessing failedtransaction.failed

Business Day Considerations

Holidays and Weekends

Processing times are affected by:

  • Local bank holidays – Destination country holidays
  • Weekends – Most bank transfers pause
  • Provider maintenance – Scheduled downtime

Handling Non-Business Days

function isBusinessDay(date, countryCode) {
const holidays = getHolidays(countryCode, date.getFullYear());
const dayOfWeek = date.getDay();
// Weekend check (0 = Sunday, 6 = Saturday)
if (dayOfWeek === 0 || dayOfWeek === 6) {
return false;
}
// Holiday check
const dateStr = date.toISOString().split('T')[0];
if (holidays.includes(dateStr)) {
return false;
}
return true;
}
function addBusinessDays(date, days, countryCode) {
let result = new Date(date);
let addedDays = 0;
while (addedDays < days) {
result.setDate(result.getDate() + 1);
if (isBusinessDay(result, countryCode)) {
addedDays++;
}
}
return result;
}

Displaying Estimates to Users

Best Practice: Show Range

Always show a range rather than a specific time:

function formatDeliveryEstimate(payer) {
const { minimum_hours, maximum_hours } = payer.estimated_delivery;
if (minimum_hours === 0 && maximum_hours === 0) {
return 'Instant delivery';
}
if (minimum_hours === 0) {
return `Up to ${formatDuration(maximum_hours)}`;
}
return `${formatDuration(minimum_hours)} to ${formatDuration(maximum_hours)}`;
}
function formatDuration(hours) {
if (hours < 1) {
return `${Math.round(hours * 60)} minutes`;
}
if (hours < 24) {
return `${hours} hour${hours > 1 ? 's' : ''}`;
}
const days = Math.round(hours / 24);
return `${days} business day${days > 1 ? 's' : ''}`;
}
// Output examples:
// "Instant delivery"
// "Up to 4 hours"
// "1 to 2 business days"

Reconciliation

Daily Reconciliation Process

async function dailyReconciliation() {
// 1. Get all transactions from the previous day
const yesterday = new Date();
yesterday.setDate(yesterday.getDate() - 1);
const transactions = await api.getTransactions({
created_after: startOfDay(yesterday),
created_before: endOfDay(yesterday)
});
// 2. Group by status
const byStatus = groupBy(transactions, 'status');
// 3. Check for stuck transactions
const processing = byStatus['PROCESSING'] || [];
const stuckTransactions = processing.filter(tx => {
const age = Date.now() - new Date(tx.created_at).getTime();
const maxAge = tx.payer.estimated_delivery.maximum_hours * 3600000;
return age > maxAge * 1.5; // 50% over expected time
});
if (stuckTransactions.length > 0) {
alertOperations('Stuck transactions detected', stuckTransactions);
}
// 4. Generate report
return {
total: transactions.length,
completed: (byStatus['COMPLETED'] || []).length,
failed: (byStatus['FAILED'] || []).length,
pending: processing.length,
stuck: stuckTransactions.length
};
}

Best Practices

  1. Set accurate expectations – Show realistic delivery times based on payer data
  2. Account for cutoffs – Warn users about approaching cutoff times
  3. Monitor webhooks – Don’t rely solely on polling for status updates
  4. Implement reconciliation – Run daily checks to catch stuck transactions
  5. Handle time zones – Display times in user’s local timezone
  6. Plan for holidays – Warn users during holiday periods