💸 PayRails Merchant Payout Integration Guide

Live API console — authenticate, test, and explore the PayRails Payout API in real time.

EnvironmentLive Demo
Base URLhttps://api.payrails.in/api/v1
Authenticationx-api-key
Demo Amount₹100 (Fixed — server-side constant)
Payment ModeIMPS
BeneficiaryFixed test beneficiary (hardcoded on server)
🔐 Authentication
Every request must include your merchant API key in the x-api-key header. No OAuth, no login session required.
Base URLhttps://api.payrails.in/api/v1
Auth methodx-api-key request header
Content typeapplication/json
ProtocolHTTPS only
Headers on every request
Content-Type: application/json
Accept: application/json
x-api-key: YOUR_API_KEY
X-Idempotency-Key: <uuid>  ← recommended
Idempotency: Include a unique X-Idempotency-Key per payout request. If you submit the same key within 48 hours and a payout was already created, the original response is returned immediately — no duplicate payout is created. Use a UUID or timestamp-based key generated server-side.
🔄 Integration Flow

Follow this sequence for every payout.

💰 Step 1 — Check Wallet Balance
GET /payouts/wallet  •  verify available_balance ≥ payout amount
📤 Step 2 — Create Payout
POST /payouts  •  receive platform_payout_id in response
📡 Step 3 — Poll Status
GET /payouts/{platform_payout_id}  •  repeat every few seconds
✅ Step 4 — Terminal State
SUCCESS  •  FAILED  •  CANCELLED  •  EXPIRED
⚡ Quick Start

Everything you need to send your first payout in under 5 minutes.

🔐
Step 1 — Get API Key
Obtain your x-api-key from PayRails. Include it on every request.
💰
Step 2 — Check Wallet
GET /payouts/wallet
Verify available_balance ≥ payout amount.
📤
Step 3 — Create Payout
POST /payouts
Supply beneficiary details, amount, and mode.
📥
Step 4 — Save Payout ID
Store the platform_payout_id returned in the response. You will need it for status polling.
📡
Step 5 — Poll Status
GET /payouts/{platform_payout_id}
Repeat every 3–5 s until terminal state.
Step 6 — Handle Outcome
SUCCESS — funds transferred.
FAILED — log and retry if eligible.
EXPIRED — contact support.
💰 Wallet Balance API

Check your available balance before creating a payout. Attempting a payout with insufficient funds returns an error without creating any record.

Endpoint
GET /payouts/wallet
Auth
x-api-key
Response
HTTP 200 OK
Response Schema
{
  "currency":         "INR",
  "total_balance":    50000,
  "reserved_balance": 3000,
  "available_balance":47000,
  "payouts_enabled":  true,
  "is_frozen":        false
}
FieldTypeDescription
available_balancenumberImmediately usable funds. Formula: total_balance − reserved_balance.
reserved_balancenumberFunds locked for in-flight payouts not yet settled.
total_balancenumberFull balance including reserved funds.
payouts_enabledbooleanFalse when payouts are administratively disabled.
is_frozenbooleanTrue when wallet is frozen — all payout attempts will be rejected.

The live card below calls this exact endpoint and displays your real-time balance.

Wallet balance is checked automatically before each payout creation.

📤 Create Payout API

Initiates a real-money bank transfer. The payout begins processing immediately after successful creation.

Endpoint
POST /payouts
Auth
x-api-key
Success response
HTTP 201 Created
Idempotency
X-Idempotency-Key (optional, 1–255 chars)
Rate limit
10 requests / 60 seconds
Prerequisite
payout_mode = API_ENABLED
Request Body
FieldRequiredTypeValidation / Notes
amountRequirednumberPositive number. Must not exceed the merchant single-payout limit.
modeRequiredstringIMPS · NEFT · RTGS · UPI
beneficiary.nameRequiredstringNon-empty string.
beneficiary.account_numberRequiredstring6–18 digits. Encrypted before storage — never stored in plaintext.
beneficiary.ifscRequiredstring11-char IFSC code. Pattern: ABCD0123456
beneficiary.account_typeOptionalstringDefault SAVINGS. Allowed: SAVINGS CURRENT SALARY NRE NRO
beneficiary.bank_nameOptionalstringStored for reference. No validation.
beneficiary.mobileOptionalstringStored as-is. No format validation.
beneficiary.emailOptionalstringStored as-is. No format validation.
merchant_refOptionalstringYour reference ID. Not required to be unique.
This demo sends a fixed test beneficiary for safety. Your production integration supplies real beneficiary details in the same JSON structure above.
👤 Fixed Test Beneficiary

All payouts from this console go to the beneficiary below. These values are hardcoded constants on the server and cannot be changed from the browser.

Name
PayRails Test Payee
Bank
HDFC Bank
Account Number
XXXXXX4321
IFSC Code
HDFC0001234
Account Type
SAVINGS
Email
support@payrails.in
Mobile
98XXXXXX21
Demo Amount
₹100
📡 Status Poll API

After creating a payout, use this endpoint to check its current status. Poll until the status reaches a terminal state.

Endpoint
GET /payouts/{platform_payout_id}
Auth
x-api-key
Success response
HTTP 200 OK
Response Fields (API key path)
{
  "platform_payout_id":    "PPX...",
  "platform_request_id":   "PRQ...",
  "merchant_reference":    "DEMO_...",
  "status":                "SUCCESS",
  "amount":                100,
  "currency":              "INR",
  "mode":                  "IMPS",
  "provider_reference":    "COLT12345",
  "bank_reference_number": "HDFC9876",
  "failure_reason":        null,
  "created_at":            "...",
  "updated_at":            "..."
}
Poll every 3–5 seconds. Stop immediately when status is a terminal value. The live polling card above uses this exact API automatically.
♻️ Payout Status Lifecycle

A payout transitions through these states. Poll the Status API until a terminal state is reached.

Standard flow (auto-approved)
PENDING
PROCESSING
SUCCESS  ✔
Approval required flow
PENDING
APPROVAL_PENDING
PROCESSING
SUCCESS  ✔
Failure paths
PROCESSING → FAILED
PROCESSING → EXPIRED (timeout)
APPROVAL_PENDING → CANCELLED
FAILED → RETRY_PENDING (retry issued)

All statuses
PENDING APPROVAL_PENDING PROCESSING SUCCESS FAILED CANCELLED EXPIRED RETRY_PENDING REVERSED
Terminal states: CANCELLED EXPIRED RETRY_PENDING REVERSED have no further transitions. FAILED is not terminal — an admin may issue a retry. SUCCESS may transition to REVERSED if the bank reverses the transfer. EXPIRED means the polling window exceeded 24 h without a definitive outcome; wallet reservation is not automatically released.
👤 Beneficiary Handling
This integration guide uses inline beneficiary details supplied directly inside the POST /payouts request body. No separate beneficiary management step is required.

In your production integration, include the beneficiary's bank details in every payout request as shown in the Create Payout API section above. The fields you need are: name, account_number, ifsc, account_type, and optionally bank_name, mobile, and email. All values are encrypted before storage and the account number is never returned in plaintext.

⚠️ Error Reference

All errors from the payout backend. Every field is from the actual implementation.

HTTPError / ConditionCauseResolution
400PAYOUT_API_DISABLEDMerchant's payout_mode is not API_ENABLED.Contact PayRails support to enable API payouts.
400amount must be positiveamount is 0, negative, or not a number.Send a positive numeric amount.
400mode must be one of…Invalid mode value.Use IMPS, NEFT, RTGS, or UPI.
400beneficiary.account_number invalidNot 6–18 digits.Validate before submission.
400beneficiary.ifsc invalidDoes not match [A-Z]{4}0[A-Z0-9]{6}.Use a valid 11-char IFSC code.
400Insufficient balanceavailable_balance < amount.Check wallet before submitting.
400Wallet frozenWallet is frozen by admin.Contact PayRails support.
400Daily limit exceededMerchant daily payout limit reached.Wait for the next IST business day or request a limit increase.
400Mode not allowedRequested mode not in merchant's allowed list.Use a permitted mode or contact support.
403IP_NOT_ALLOWEDCaller IP not in the merchant IP whitelist.Add your server IP via the admin portal.
503IDEMPOTENCY_STORE_UNAVAILABLEIdempotency Redis store unavailable.Retry with backoff. Do not change your idempotency key.
503PAYOUTS_SYSTEM_DISABLEDGlobal kill-switch active.Contact PayRails support.
429Rate limit exceededMore than 10 payout creation requests in 60 seconds.Implement exponential backoff.
💻 cURL Reference Examples

Copy-paste ready examples. Replace YOUR_API_KEY with your actual key.

1. Check Wallet Balance
curl -X GET \\
  'https://api.payrails.in/api/v1/payouts/wallet' \\
  -H 'x-api-key: YOUR_API_KEY' \\
  -H 'Accept: application/json'
2. Create Payout
curl -X POST \\
  'https://api.payrails.in/api/v1/payouts' \\
  -H 'Content-Type: application/json' \\
  -H 'Accept: application/json' \\
  -H 'x-api-key: YOUR_API_KEY' \\
  -H 'X-Idempotency-Key: unique-request-id-here' \\
  -d '{
    "amount": 100,
    "beneficiary": {
      "name": "Beneficiary Name",
      "account_number": "1234567890",
      "ifsc": "HDFC0001234",
      "account_type": "SAVINGS",
      "bank_name": "HDFC Bank",
      "mobile": "9876543210",
      "email": "payee@example.com"
    },
    "mode": "IMPS",
    "merchant_ref": "YOUR_REF_001"
  }'
3. Poll Payout Status
curl -X GET \\
  'https://api.payrails.in/api/v1/payouts/PPX_REPLACE_WITH_PLATFORM_PAYOUT_ID' \\
  -H 'x-api-key: YOUR_API_KEY' \\
  -H 'Accept: application/json'
✅ Production Checklist

Verify each item before going live with PayRails Payout API.

🔒 Security Note — How This Demo Protects Real Data

This demo executes real payouts against the live API. To prevent exposing private banking information, the page enforces a strict two-model architecture.

Execution Model (server-side only)
  • Real beneficiary name
  • Real account number
  • Real IFSC
  • Real mobile & email
  • Fixed amount (¤100)
These values are PHP constants. They are used only inside $execPayload which goes directly to CURLOPT_POSTFIELDS. They are never passed to any HTML rendering function.
Display Model (browser)
  • Name: PayRails Test Payee
  • Account: XXXXXX4321
  • Mobile: 98XXXXXX21
  • Email: support@payrails.in
Only these sanitized placeholders reach the browser. The API response is recursively sanitized before rendering. The cURL verbose log is string-scrubbed before display.