Payouts in Cashfree
Beneficiary Integration
Section titled “Beneficiary Integration”This document provides a detailed description for creating beneficiaries used for integrating with Cashfree Payouts - Version 2 APIs, including data flow, constraints, validation, and backend responsibilities.
1. Overview
Section titled “1. Overview”When creating a beneficiary using Cashfree APIs, the system must:
- Collect details from frontend.
- Validate and store the data internally.
- Generate a
beneficiary_id. - Prepare the Cashfree-compliant payload.
- Send the API request and store the returned status and metadata.
A two-table architecture where:
userstable stores your application’s user identity data.beneficiariestable stores payout-related bank/UPI details.
This separation supports:
- Multiple beneficiaries per user.
- Cleaner user profile management.
- Better audit logging and traceability.
2. Data Flow Summary
Section titled “2. Data Flow Summary”Step 1 — Frontend Input (Raw User Inputs)
Section titled “Step 1 — Frontend Input (Raw User Inputs)”{ "beneficiary_name": "", "beneficiary_phone": "", "beneficiary_email": "", "beneficiary_country_code": "", "beneficiary_address": "", "beneficiary_city": "", "beneficiary_state": "", "beneficiary_postal_code": "", "bank_account_number": "", "bank_ifsc": "", "vpa": ""}Step 2 — Backend Validates & Stores Preliminary Data
Section titled “Step 2 — Backend Validates & Stores Preliminary Data”- Validate formats (email, phone, IFSC, account number).
- Create DB entry with status =
PENDING.
Step 3 — Prepare Cashfree Payload
Section titled “Step 3 — Prepare Cashfree Payload”Mapped fields:
- Personal details →
beneficiary_contact_details - Bank/UPI details →
beneficiary_instrument_details - System-generated →
beneficiary_id
Step 4 — Send to Cashfree API
Section titled “Step 4 — Send to Cashfree API”POST /payout/beneficiary
Step 5 — Store Cashfree Response
Section titled “Step 5 — Store Cashfree Response”Save:
beneficiary_statusadded_on- Error fields if applicable
3. Database Schema (Two-Table Model)
Section titled “3. Database Schema (Two-Table Model)”3.1 Users Table
Section titled “3.1 Users Table”| Column | Type | Description | Notes |
|---|---|---|---|
id | BIGINT PK | Internal unique user ID | Auto-increment |
name | VARCHAR | User’s display name | From frontend/user account |
email | VARCHAR | User email | Unique if needed |
phone | VARCHAR | User phone | Optional uniqueness |
country_code | VARCHAR | Country dialing code | Default +91 |
created_at | TIMESTAMP | Row creation time | Auto |
updated_at | TIMESTAMP | Row update time | Auto |
Purpose
Section titled “Purpose”The users table represents your platform’s real user accounts. Beneficiaries belong to users but are independent payout entities.
3.2 Beneficiaries Table
Section titled “3.2 Beneficiaries Table”| Column | Type | Description | Notes |
|---|---|---|---|
id | BIGINT PK | Internal primary key | Auto-increment |
user_id | BIGINT FK | FK → users.id | Required |
beneficiary_id | VARCHAR UNIQUE | Unique ID sent to Cashfree | Must never change once created |
beneficiary_name | VARCHAR | Person/entity receiving payout | From frontend |
bank_account_number | VARCHAR | Bank account number | Optional if VPA used |
bank_ifsc | VARCHAR | IFSC code | Validate with regex |
vpa | VARCHAR | UPI ID | Optional if bank details used |
email | VARCHAR | Beneficiary email | Required by Cashfree |
phone | VARCHAR | Beneficiary phone | Required |
country_code | VARCHAR | +91 etc | Default from user |
address | TEXT | Beneficiary address | Required |
city | VARCHAR | Required | |
state | VARCHAR | Required | |
postal_code | VARCHAR | Required | |
beneficiary_status | VARCHAR | Status from Cashfree | VERIFIED / PENDING / FAILED |
added_on | TIMESTAMP | From Cashfree response | Save as-is |
last_error_code | VARCHAR | Optional | Useful for debugging |
last_error_message | TEXT | Optional | Useful for debugging |
raw_response | JSON | Optional full Cashfree payload | Helpful for audits |
created_at | TIMESTAMP | Auto | |
updated_at | TIMESTAMP | Auto |
Key Design Notes
Section titled “Key Design Notes”- At least one of the following must exist:
bank_account_number+bank_ifscvpa
- The backend should enforce that one payout instrument is present.
beneficiary_idmust be unique, stable, deterministic.
6. Backend Behavior & Error Handling
Section titled “6. Backend Behavior & Error Handling”6.1 On Create Request
Section titled “6.1 On Create Request”- Save beneficiary → status =
PENDING. - Call Cashfree.
- Update:
beneficiary_statusadded_onlast_error_code/message
6.2 If Cashfree Returns Error
Section titled “6.2 If Cashfree Returns Error”Store:
last_error_codelast_error_messageMark status as:
FAILED6.3 Idempotency
Section titled “6.3 Idempotency”If frontend retries:
- Do not create duplicate beneficiaries.
- Check:
beneficiary_id- OR
(user_id, bank_account_number, bank_ifsc)combination
7. Cashfree Payload Mapping
Section titled “7. Cashfree Payload Mapping”Outbound Request
Section titled “Outbound Request”{ "beneficiary_id": "<generated>", "beneficiary_name": "<name>", "beneficiary_instrument_details": { "bank_account_number": "...", "bank_ifsc": "...", "vpa": "..." }, "beneficiary_contact_details": { "beneficiary_email": "...", "beneficiary_phone": "...", "beneficiary_country_code": "+91", "beneficiary_address": "...", "beneficiary_city": "...", "beneficiary_state": "...", "beneficiary_postal_code": "..." }}Inbound Response
Section titled “Inbound Response”{ "beneficiary_id": "BEN_123_ABC", "beneficiary_name": "John Doe", "beneficiary_instrument_details": { "bank_account_number": "1223334444", "bank_ifsc": "HDFC0000001", "vpa": "test@upi" }, "beneficiary_contact_details": { "beneficiary_email": "sample@cashfree.com", "beneficiary_phone": "9876543210", "beneficiary_country_code": "+91", "beneficiary_address": "177A Bleecker Street", "beneficiary_city": "New York City", "beneficiary_state": "New York", "beneficiary_postal_code": "560011" }, "beneficiary_status": "VERIFIED", "added_on": "2023-12-04T15:50:00Z"}Standard Transfer V2 Integration
Section titled “Standard Transfer V2 Integration”This document provides a detailed description for initiating standard transfers using Cashfree Payouts - Version 2 APIs, including data flow, constraints, validation, and backend responsibilities.
8. Overview
Section titled “8. Overview”When initiating a standard transfer using Cashfree APIs, the system must:
- Collect transfer details from frontend (amount, beneficiary, transfer mode).
- Validate the data internally (amount, beneficiary status, fund source).
- Generate a unique
transfer_id. - Prepare the Cashfree-compliant payload.
- Send the API request (async by default).
- Store the returned status and metadata.
- Poll or use webhooks to track transfer status updates.
Key Characteristics:
- Async by default: The API returns immediately with a status, but the transfer processes asynchronously.
- Status tracking: Use Get Transfer Status V2 API or webhooks to monitor transfer progress.
- Idempotency: Use unique
transfer_idto prevent duplicate transfers. - Multiple transfer modes: Supports banktransfer, IMPS, NEFT, RTGS, UPI, Paytm, AmazonPay, and card transfers.
9. Data Flow Summary
Section titled “9. Data Flow Summary”Step 1 — Frontend Input (Raw User Inputs)
Section titled “Step 1 — Frontend Input (Raw User Inputs)”{ "transfer_amount": 1000.0, "beneficiary_id": "BEN_123_ABC", "transfer_mode": "banktransfer", "transfer_remarks": "Payment for services", "fundsource_id": "FUND_001"}Alternative: If beneficiary is not pre-created, include full beneficiary details inline.
Step 2 — Backend Validates & Stores Preliminary Data
Section titled “Step 2 — Backend Validates & Stores Preliminary Data”- Validate transfer amount (>= 1.00).
- Verify beneficiary exists and is
VERIFIED. - Check fund source availability.
- Validate transfer mode compatibility with beneficiary instrument.
- Create DB entry with status =
PENDING.
Step 3 — Prepare Cashfree Payload
Section titled “Step 3 — Prepare Cashfree Payload”Mapped fields:
- Transfer details →
transfer_id,transfer_amount,transfer_currency,transfer_mode,transfer_remarks - Beneficiary reference →
beneficiary_id(if pre-created) OR fullbeneficiary_detailsobject - Fund source →
fundsource_id
Step 4 — Send to Cashfree API
Section titled “Step 4 — Send to Cashfree API”POST /payout/transfers
Headers:
x-api-version: 2024-01-01(or latest)x-client-id: <api-key>x-client-secret: <api-key>Content-Type: application/json
Step 5 — Store Cashfree Response
Section titled “Step 5 — Store Cashfree Response”Save:
cf_transfer_id(Cashfree’s unique transfer ID)status(initial status from response)transfer_utr(if available)transfer_service_chargetransfer_service_taxadded_on,updated_on
Step 6 — Status Tracking
Section titled “Step 6 — Status Tracking”- Poll Get Transfer Status V2 API periodically, OR
- Use webhooks to receive status updates automatically.
10. Database Schema (Transfers Table)
Section titled “10. Database Schema (Transfers Table)”10.1 Transfers Table
Section titled “10.1 Transfers Table”| Column | Type | Description | Notes |
|---|---|---|---|
id | BIGINT PK | Internal primary key | Auto-increment |
user_id | BIGINT FK | FK → users.id | Required |
beneficiary_id | BIGINT FK | FK → beneficiaries.id | Required |
transfer_id | VARCHAR UNIQUE | Unique ID sent to Cashfree | Must never change once created |
cf_transfer_id | VARCHAR | Cashfree’s transfer ID | From Cashfree response |
transfer_amount | DECIMAL(18,2) | Transfer amount | >= 1.00 |
transfer_currency | VARCHAR | Currency code | Default: INR |
transfer_mode | VARCHAR | Transfer mode | banktransfer/imps/neft/rtgs/upi/paytm/amazonpay/card |
transfer_remarks | VARCHAR | Transfer remarks | Max 70 characters |
fundsource_id | VARCHAR | Fund source ID | From Cashfree |
status | VARCHAR | Transfer status | PENDING/SUCCESS/FAILED/APPROVAL_PENDING/etc |
status_code | VARCHAR | Detailed status code | From Cashfree response |
status_description | TEXT | Status description | From Cashfree response |
transfer_utr | VARCHAR | Unique Transaction Reference | From bank/Cashfree |
transfer_service_charge | DECIMAL(18,2) | Service charge | From Cashfree response |
transfer_service_tax | DECIMAL(18,2) | Service tax | From Cashfree response |
added_on | TIMESTAMP | Transfer creation time | From Cashfree response |
updated_on | TIMESTAMP | Last update time | From Cashfree response |
last_error_code | VARCHAR | Error code if failed | Useful for debugging |
last_error_message | TEXT | Error message if failed | Useful for debugging |
raw_request | JSON | Full request payload | Helpful for audits |
raw_response | JSON | Full Cashfree response | Helpful for audits |
created_at | TIMESTAMP | Auto | |
updated_at | TIMESTAMP | Auto |
Key Design Notes
Section titled “Key Design Notes”transfer_idmust be unique, stable, deterministic (max 40 characters, alphanumeric + underscore).- Link to
beneficiariestable viabeneficiary_idforeign key. - Store both request and response payloads for audit trails.
statusfield should be updated via polling or webhooks.
11. Transfer Modes & Validation
Section titled “11. Transfer Modes & Validation”11.1 Supported Transfer Modes
Section titled “11.1 Supported Transfer Modes”| Transfer Mode | Description | Required Beneficiary Instrument |
|---|---|---|
banktransfer | Standard bank transfer (default) | bank_account_number + bank_ifsc |
imps | Immediate Payment Service | bank_account_number + bank_ifsc |
neft | National Electronic Funds Transfer | bank_account_number + bank_ifsc |
rtgs | Real Time Gross Settlement | bank_account_number + bank_ifsc |
upi | UPI transfer | vpa |
paytm | Paytm wallet transfer | Paytm-specific instrument |
amazonpay | Amazon Pay transfer | Amazon Pay-specific instrument |
card | Card transfer | card_details object |
cardupi | Card UPI transfer | Card or UPI instrument |
11.2 Validation Rules
Section titled “11.2 Validation Rules”Transfer Amount
Section titled “Transfer Amount”- Minimum:
1.00 - Type:
number<double> - Decimal values allowed
Transfer ID
Section titled “Transfer ID”- Maximum length:
40characters - Allowed characters: Alphanumeric and underscore (
_) - Must be unique across all transfers
- Recommended format:
TXN_<userId>_<timestamp>orTXN_<userId>_<random>
Transfer Remarks
Section titled “Transfer Remarks”- Maximum length:
70characters - Allowed: Alphanumeric and whitespaces
Transfer Currency
Section titled “Transfer Currency”- Default:
INR - String format
Beneficiary Requirements
Section titled “Beneficiary Requirements”- If
beneficiary_idis provided: Beneficiary must exist and beVERIFIEDin Cashfree. - If
beneficiary_idis not provided: Fullbeneficiary_detailsobject must be included in request.
12. Backend Behavior & Error Handling
Section titled “12. Backend Behavior & Error Handling”12.1 On Transfer Request
Section titled “12.1 On Transfer Request”- Validate input data (amount, beneficiary, mode).
- Check beneficiary status (must be
VERIFIED). - Verify fund source availability.
- Generate unique
transfer_id. - Save transfer → status =
PENDING. - Call Cashfree API.
- Update:
cf_transfer_idstatusstatus_codestatus_descriptiontransfer_utr(if available)transfer_service_chargetransfer_service_taxadded_on,updated_on
12.2 If Cashfree Returns Error
Section titled “12.2 If Cashfree Returns Error”Store:
last_error_codelast_error_messagestatus = FAILEDImportant: On 5XX errors, do NOT retry immediately. Check status using Get Transfer Status V2 API first.
12.3 Status Handling
Section titled “12.3 Status Handling”Common statuses:
PENDING: Transfer initiated, processingSUCCESS: Transfer completed successfullyFAILED: Transfer failedAPPROVAL_PENDING: Requires manual approval (velocity check or limit breach)REJECTED: Transfer was rejected
Status Codes:
VELOCITY_CHECK_FAILED: Transfer count to beneficiary breached limit → requires approvalTRANSFER_LIMIT_BREACH: Transfer amount breached limit → requires approval
12.4 Idempotency
Section titled “12.4 Idempotency”If frontend retries:
- Use the same
transfer_idto prevent duplicate transfers. - Check if
transfer_idalready exists in database. - If exists, return existing transfer record instead of creating new one.
12.5 Status Polling
Section titled “12.5 Status Polling”Since transfers are async:
- Poll Get Transfer Status V2 API every 30-60 seconds for pending transfers.
- Stop polling once status is
SUCCESSorFAILED. - Alternatively, use webhooks for real-time status updates.
13. Cashfree Payload Mapping
Section titled “13. Cashfree Payload Mapping”Outbound Request (Using Pre-created Beneficiary)
Section titled “Outbound Request (Using Pre-created Beneficiary)”{ "transfer_id": "TXN_42_1702259812", "transfer_amount": 1000.5, "beneficiary_details": { "beneficiary_id": "BEN_123_ABC" }, "transfer_currency": "INR", "transfer_mode": "banktransfer", "transfer_remarks": "Payment for services rendered", "fundsource_id": "FUND_001"}Outbound Request (Inline Beneficiary Details)
Section titled “Outbound Request (Inline Beneficiary Details)”{ "transfer_id": "TXN_42_1702259812", "transfer_amount": 1000.5, "beneficiary_details": { "beneficiary_name": "John Doe", "beneficiary_instrument_details": { "bank_account_number": "1223334444", "bank_ifsc": "HDFC0000001" }, "beneficiary_contact_details": { "beneficiary_email": "john@example.com", "beneficiary_phone": "9876543210", "beneficiary_country_code": "+91", "beneficiary_address": "177A Bleecker Street", "beneficiary_city": "Mumbai", "beneficiary_state": "Maharashtra", "beneficiary_postal_code": "400001" } }, "transfer_currency": "INR", "transfer_mode": "banktransfer", "transfer_remarks": "Payment for services rendered", "fundsource_id": "FUND_001"}Outbound Request (UPI Transfer)
Section titled “Outbound Request (UPI Transfer)”{ "transfer_id": "TXN_42_1702259813", "transfer_amount": 500.0, "beneficiary_details": { "beneficiary_id": "BEN_123_ABC" }, "transfer_currency": "INR", "transfer_mode": "upi", "transfer_remarks": "Quick payment", "fundsource_id": "FUND_001"}Outbound Request (Card Transfer)
Section titled “Outbound Request (Card Transfer)”{ "transfer_id": "TXN_42_1702259814", "transfer_amount": 2000.0, "beneficiary_details": { "beneficiary_name": "Jane Smith", "beneficiary_instrument_details": { "card_details": { "card_token": "token_abc123", "card_network_type": "VISA", "card_cryptogram": "cryptogram_data", "card_token_expiry": "2025-12", "card_type": "DEBIT", "card_token_PAN_sequence_number": "001" } }, "beneficiary_contact_details": { "beneficiary_email": "jane@example.com", "beneficiary_phone": "9876543211", "beneficiary_country_code": "+91" } }, "transfer_currency": "INR", "transfer_mode": "card", "transfer_remarks": "Card payment", "fundsource_id": "FUND_001"}Inbound Response (Success)
Section titled “Inbound Response (Success)”{ "transfer_id": "TXN_42_1702259812", "cf_transfer_id": "CF123456789", "status": "PENDING", "beneficiary_details": { "beneficiary_id": "BEN_123_ABC", "beneficiary_instrument_details": { "bank_account_number": "1223334444", "ifsc": "HDFC0000001" } }, "transfer_amount": 1000.5, "transfer_service_charge": 2.5, "transfer_service_tax": 0.45, "transfer_mode": "banktransfer", "transfer_utr": "UTR123456789012", "fundsource_id": "FUND_001", "added_on": "2023-12-04T15:50:00Z", "updated_on": "2023-12-04T15:50:00Z"}Inbound Response (Approval Pending)
Section titled “Inbound Response (Approval Pending)”{ "transfer_id": "TXN_42_1702259812", "cf_transfer_id": "CF123456789", "status": "APPROVAL_PENDING", "status_code": "VELOCITY_CHECK_FAILED", "status_description": "The transfer requires an approval as the count of transfers to a particular beneficiary etc have breached the limit.", "beneficiary_details": { "beneficiary_id": "BEN_123_ABC" }, "transfer_amount": 1000.5, "transfer_mode": "banktransfer", "fundsource_id": "FUND_001", "added_on": "2023-12-04T15:50:00Z", "updated_on": "2023-12-04T15:50:00Z"}14. Important Notes
Section titled “14. Important Notes”14.1 Async Behavior
Section titled “14.1 Async Behavior”- The API is async by default.
- Initial response may show
PENDINGstatus. - Use Get Transfer Status V2 API or webhooks to track final status.
14.2 Approval Workflow
Section titled “14.2 Approval Workflow”If status is APPROVAL_PENDING:
- Approve or reject via Cashfree Merchant Dashboard.
- Navigate to Transfers > Approve.
- After approval, transfer proceeds to partner bank.
14.3 Error Handling for 5XX
Section titled “14.3 Error Handling for 5XX”- Do NOT initiate another transaction on 5XX response.
- Check status using Get Transfer Status V2 API first.
- Proceed based on actual status.
14.4 Transfer Status Tracking
Section titled “14.4 Transfer Status Tracking”- Recommended: Use webhooks for real-time updates.
- Alternative: Poll Get Transfer Status V2 API periodically.
- Update local database with status changes.
14.5 Fund Source
Section titled “14.5 Fund Source”fundsource_idis required and identifies the account/wallet from which funds are debited.- Ensure fund source has sufficient balance before initiating transfer.
14.6 UTR (Unique Transaction Reference)
Section titled “14.6 UTR (Unique Transaction Reference)”transfer_utris generated by the bank/Cashfree.- Available only after transfer is processed.
- Use for reconciliation and tracking.
15. API Endpoints Reference
Section titled “15. API Endpoints Reference”Standard Transfer V2
Section titled “Standard Transfer V2”Endpoint: POST /payout/transfers
Base URLs:
- Sandbox:
https://sandbox.cashfree.com/payout - Production:
https://api.cashfree.com/payout
Required Headers:
x-api-version: 2024-01-01(or latest)x-client-id: <api-key>x-client-secret: <api-key>Content-Type: application/json
Optional Headers:
x-request-id: <unique-request-id>(for tech support)x-cf-signature: <signature>(if IP not whitelisted)
Get Transfer Status V2
Section titled “Get Transfer Status V2”Endpoint: GET /payout/transfers/{transfer_id}
Use this to check the current status of a transfer after initiation.
16. Response Codes Reference
Section titled “16. Response Codes Reference”| HTTP Status | Status | Status Code | Description | Next Action |
|---|---|---|---|---|
| 200 | APPROVAL_PENDING | VELOCITY_CHECK_FAILED | Transfer requires approval due to beneficiary transfer count limit breach | Approve/reject via Merchant Dashboard → Transfers > Approve |
| 200 | APPROVAL_PENDING | TRANSFER_LIMIT_BREACH | Transfer requires approval due to amount limit breach | Approve/reject via Merchant Dashboard → Transfers > Approve |
| 200 | PENDING | - | Transfer initiated, processing | Poll Get Transfer Status V2 or wait for webhook |
| 200 | SUCCESS | - | Transfer completed successfully | Transfer complete, UTR available |
| 200 | FAILED | Various | Transfer failed | Check status_code and status_description for details |
| 400 | - | - | Bad request (validation error) | Check request payload and fix validation errors |
| 403 | - | - | Forbidden (authentication/authorization error) | Verify API credentials and permissions |
| 404 | - | - | Resource not found | Verify beneficiary_id, fundsource_id, or transfer_id |
| 500 | - | - | Internal server error | Do NOT retry immediately. Check status via Get Transfer Status V2 first |