Skip to main content

Overview

This guide explains the complete transaction flow for accepting payments via card (Payin API) and delivering funds to recipients (Payout API). This integrated flow allows you to accept payments from customers and automatically transfer funds to recipients.

Complete Transaction Flow

Step-by-Step Process

Phase 1: Card Payment (Payin)

1

Customer enters card details

Customer fills out the payment form on your website with their card information
Card data is entered directly into Approvely’s secure iframe, never touching your servers.
2

Tokenize card data

Your frontend calls Approvely’s tokenization API to convert card data into a secure nonce token
const result = await cardForm.getNonceToken();
const nonceToken = 'nonce-' + result.nonce;
Nonce token received (e.g., nonce-pft4uav4cker5g8bk3db)
3

Submit payment to backend

Frontend sends the nonce token to your backend server along with payment details
const response = await fetch('/api/process-payment', {
  method: 'POST',
  body: JSON.stringify({
    nonce: nonceToken,
    amount: 100,
    recipient_phone: '5551234568',
    cardholder_name: 'John Doe'
  })
});
4

Charge the card

Your backend calls Approvely’s charge endpoint with the nonce token
const chargeResponse = await fetch(
  'https://api.sandbox.approvelygateway.com/api/v2/transactions/charge',
  {
    method: 'POST',
    headers: {
      'Authorization': `Basic ${credentials}`,
      'Content-Type': 'application/json'
    },
    body: JSON.stringify({
      amount: 100,
      source: nonceToken,
      expiry_month: 10,
      expiry_year: 2028,
      billing_info: { /* ... */ }
    })
  }
);

const chargeData = await chargeResponse.json();
const approvelyId = chargeData.id; // Save this ID
Payment approved and approvelyId received (e.g., txn_1234567890)

Phase 2: Fund Transfer (Payout)

1

Verify recipient KYC

Check if the recipient is KYC verified and can receive the transfer amount
const kycResponse = await fetch(
  `https://api.cashqbot.com/api/kyc/${recipientPhone}`,
  {
    headers: { 'API-KEY': cashqApiKey }
  }
);

const kycData = await kycResponse.json();

if (parseFloat(kycData.money_limit) < amount) {
  throw new Error('Amount exceeds recipient limit');
}
Recipient KYC verified and can receive the amount
2

Check transfer

Validate the transfer details before executing
const checkResponse = await fetch(
  'https://api.cashqbot.com/api/checkTransfer',
  {
    method: 'POST',
    headers: {
      'API-KEY': cashqApiKey,
      'Content-Type': 'application/json'
    },
    body: JSON.stringify({
      id: generateTransferId(),
      sender_phone: merchantPhone,
      receiver_phone: recipientPhone,
      amount: amount.toString(),
      receiver_country: 'MX',
      attribute: [
        {
          name: 'approvelyId',
          value: {{approvelyId}}
        },
         /* other attributes... */
      ]
    })
  }
);
The approvelyId is included in the attribute array with name 'approvelyId' to link the payout with the payin transaction.
3

Execute transfer

Execute the money transfer to the recipient
const transferResponse = await fetch(
  'https://api.cashqbot.com/api/transfer',
  {
    method: 'POST',
    headers: {
      'API-KEY': cashqApiKey,
      'Content-Type': 'application/json'
    },
    body: JSON.stringify({
      id: transferId,
      sender_phone: merchantPhone,
      receiver_phone: recipientPhone,
      amount: amount.toString(),
      receiver_country: 'MX',
      attribute: [
        {
          name: 'approvelyId',
          value: {{approvelyId}}
        },
        /* other attributes... */
      ]
    })
  }
);

const transferData = await transferResponse.json();
Transfer initiated successfully
4

Monitor transfer status

Poll the transfer status until completion
const finalStatus = await pollTransferStatus(transferId);

if (finalStatus.state === 60) {
  // Transfer successful - funds delivered to recipient
  console.log('Transfer completed successfully');
} else if (finalStatus.state === 80) {
  // Transfer failed - may need to refund the card charge
  console.error('Transfer failed');
}
Funds successfully delivered to recipient

Linking Transactions

The approvelyId is crucial for linking the card payment with the money transfer. Include it in the attribute array:
{
  "attribute": [
    {
      "name": "approvelyId",
      "value": "1234567890"
    },
    /* other attributes... */
  ]
}
This allows you to:
  • Track which card payment funded which transfer
  • Reconcile transactions across both systems
  • Handle refunds if transfers fail
  • Generate accurate financial reports

Error Handling

Action: Return error to customer, don’t proceed with transfer
if (chargeData.status !== 'approved') {
  return res.status(400).json({
    error: 'Card declined',
    message: chargeData.error.message
  });
}
Action: Refund the card charge, inform customer
if (parseFloat(kycData.money_limit) < amount) {
  await refundCharge(approvelyId);
  return res.status(400).json({
    error: 'Recipient limit exceeded',
    kyc_url: kycData.kyc_url
  });
}
Action: Refund the card charge, return error
if (!checkData.success) {
  await refundCharge(approvelyId);
  return res.status(400).json({
    error: 'Transfer validation failed'
  });
}
Action: Refund the card charge, log for investigation
if (!transferData.success) {
  await refundCharge(approvelyId);
  logFailedTransfer(approvelyId, transferId);
  return res.status(400).json({
    error: 'Transfer failed'
  });
}

API References