PayIn Flow Diagram
This guide illustrates the complete PayIn flow from initialization to completion, including all API calls, user interactions, and webhook events.
Complete Integration Flow
┌─────────────────────────────────────────────────────────────────────────────┐│ PAYIN INTEGRATION FLOW │└─────────────────────────────────────────────────────────────────────────────┘
┌─────────┐ ┌─────────────┐ ┌─────────────┐ ┌─────────────────┐│ Your │ │ Cashela │ │ Payment │ │ Your Server ││ Client │ │ API │ │ Provider │ │ (Webhooks) │└────┬────┘ └──────┬──────┘ └──────┬──────┘ └────────┬────────┘ │ │ │ │ │ 1. Get Countries │ │ │─────────────────► │ │ │ ◄─────────────── [MEX, BRA, COL] │ │ │ │ │ │ │ 2. Get Payment Methods │ │ │─────────────────► │ │ │ ◄─────────────── [Card, Bank, Cash]│ │ │ │ │ │ │ 3. Get Exchange Rates │ │ │─────────────────► │ │ │ ◄─────────────── FX Rate + Fees │ │ │ │ │ │ │ 4. Create Deposit │ │ │─────────────────► │ │ │ ◄─────────────── Deposit Created │ │ │ (redirect_url) │ │ │ │ │ │ │ 5. Redirect to Payment │ │ │───────────────────────────────────► │ │ │ │ │ │ │ 6. Customer Completes Payment │ │ │ ◄─────────────────────────────────│ │ │ │ │ │ │ │ 7. Payment Result│ │ │ │◄──────────────────│ │ │ │ │ │ │ │ 8. Webhook Notification │ │ │───────────────────────────────────────►│ │ │ │ │ │ │ 9. Acknowledge (200 OK) │ │ │◄───────────────────────────────────────│ │ │ │ │ │ 10. Get Transaction Status │ │ │─────────────────► │ │ │ ◄─────────────── COMPLETED │ │ │ │ │ │Step-by-Step Process
Step 1: Get Available Countries
Retrieve the list of supported countries to display to your users.
GET /api/v1/pay-in/deposit-creation/countriesPurpose: Determine where payments can be collected from.
Step 2: Get Available Payment Methods
For the selected country and amount, fetch available payment methods with fees.
POST /api/v1/pay-in/deposit-creation/available-payment-methodsPurpose: Show the customer their payment options with accurate pricing.
Step 3: Get Exchange Rates (Optional)
If you need to display converted amounts before creating the deposit.
POST /api/v1/pay-in/deposit-creation/exchange-ratePurpose: Show the customer the exact amount they’ll pay in their local currency.
Step 4: Create Deposit
Submit the deposit request with customer and payment details.
POST /api/v1/pay-in/deposit-creationPurpose: Initialize the payment and receive the redirect URL or payment instructions.
Step 5: Customer Payment
Redirect the customer to complete payment or display payment instructions.
| Payment Type | User Experience |
|---|---|
| Card | Redirect to hosted checkout page |
| Bank Transfer | Display bank details or redirect to bank site |
| Cash/Voucher | Display barcode or payment reference number |
| Digital Wallet | Redirect to wallet app or show QR code |
Step 6-9: Payment Processing & Webhooks
The payment is processed asynchronously. Your server receives webhook notifications for status changes.
Step 10: Verify Transaction Status
Optionally query the transaction status for confirmation.
State Machine
┌─────────────┐ │ CREATED │ └──────┬──────┘ │ ┌──────▼──────┐ │ PENDING │ └──────┬──────┘ │ ┌─────────────────┼─────────────────┐ │ │ │ ┌──────▼──────┐ ┌──────▼──────┐ ┌──────▼──────┐ │ COMPLETED │ │ FAILED │ │ EXPIRED │ └─────────────┘ └─────────────┘ └─────────────┘ │ ┌──────▼──────┐ │ REFUNDED │ └─────────────┘| Status | Description | Terminal |
|---|---|---|
CREATED | Deposit initiated, awaiting payment | No |
PENDING | Payment in progress | No |
COMPLETED | Payment received successfully | Yes |
FAILED | Payment failed or declined | Yes |
EXPIRED | Payment window expired | Yes |
REFUNDED | Payment was refunded | Yes |
Integration Patterns
Pattern 1: Server-Side Redirect
Best for: Web applications with server-side rendering
// Server-sideapp.post('/checkout', async (req, res) => { // 1. Create deposit const deposit = await cashelaApi.createDeposit({ amount: req.body.amount, country: req.body.country, payment_method: req.body.paymentMethod, callback_url: `${process.env.BASE_URL}/webhooks/payin`, success_url: `${process.env.BASE_URL}/payment/success`, cancel_url: `${process.env.BASE_URL}/payment/cancel` });
// 2. Redirect to payment res.redirect(deposit.redirect_url);});
// Webhook handlerapp.post('/webhooks/payin', (req, res) => { // Verify signature first if (!verifySignature(req)) { return res.status(401).send(); }
// Process event const event = req.body; handlePaymentEvent(event);
res.status(200).send();});Pattern 2: Client-Side Modal
Best for: Single-page applications (SPAs)
// Client-sideasync function initiatePayment(amount, country) { // 1. Request deposit from your backend const response = await fetch('/api/create-deposit', { method: 'POST', body: JSON.stringify({ amount, country }) });
const deposit = await response.json();
// 2. Open payment in modal or popup const paymentWindow = window.open( deposit.redirect_url, 'cashela_payment', 'width=500,height=700' );
// 3. Listen for completion window.addEventListener('message', (event) => { if (event.data.type === 'payment_complete') { paymentWindow.close(); handlePaymentComplete(event.data); } });}Pattern 3: Mobile App Integration
Best for: Native mobile applications
// iOS Swiftfunc createPayment(amount: Double, country: String) { // 1. Create deposit via your backend API.createDeposit(amount: amount, country: country) { result in switch result { case .success(let deposit): // 2. Open payment URL in SFSafariViewController let safari = SFSafariViewController(url: deposit.redirectUrl) safari.delegate = self present(safari, animated: true)
case .failure(let error): showError(error) } }}
// Handle callback URLfunc application(_ app: UIApplication, open url: URL) -> Bool { if url.scheme == "myapp" && url.host == "payment-callback" { handlePaymentCallback(url) return true } return false}Error Handling Flow
┌─────────────────────────────────────────────────────────────────┐│ ERROR HANDLING FLOW │└─────────────────────────────────────────────────────────────────┘
┌──────────────────────┐│ Make API Request │└──────────┬───────────┘ │ ┌──────▼──────┐ │ Check Status │ └──────┬──────┘ │ ┌──────┴──────────────────┬──────────────────────┐ │ │ │┌───▼───┐ ┌─────▼─────┐ ┌──────▼──────┐│ 2xx │ │ 4xx │ │ 5xx ││Success│ │Client Err │ │ Server Err │└───┬───┘ └─────┬─────┘ └──────┬──────┘ │ │ │ │ ┌─────▼─────┐ ┌──────▼──────┐ │ │ Fix Error │ │ Retry │ │ │ & Retry │ │ w/ Backoff │ │ └───────────┘ └─────────────┘ │┌───▼───────────┐│Process Result │└───────────────┘Best Practices Checklist
- Cache country and payment method lists – Refresh every 24 hours
- Validate amounts client-side – Check min/max before API call
- Use idempotency keys – Prevent duplicate deposits
- Implement webhook handlers – Never rely solely on redirects
- Handle all terminal states – COMPLETED, FAILED, EXPIRED
- Log all API interactions – Include request_id for support
- Test in sandbox first – Verify all flows before production
Related Documentation
- Create Deposit – Full deposit creation reference
- Get Countries – Country list endpoint
- Get Payment Methods – Payment method endpoint
- Webhooks – Webhook integration guide
- Error Handling – Error codes and handling