Authentication
All API requests require an API key in the request header.
Required Headers
X-Api-Key: your_api_key
Content-Type: application/json
⚠️ IP Whitelist Required
Your server IP must be whitelisted before making API calls. Submit your IP and callback URL via the dashboard. Admin approval required.
Authentication Flow
Request → Check API Key → Check IP Whitelist → Check Rate Limit → Process
PayIn
Collect UPI payments from your customers. Supports GPay, PhonePe, Paytm, BHIM and all UPI apps.
Create PayIn → Get intent_url → Show QR / Redirect customer → Customer pays → Webhook → Wallet credited
Wallet Credit: Customer pays ₹1,000 → Commission ₹10 → Your wallet receives ₹990
Expiry: Payment link expires in 10 minutes. Unpaid transactions are auto-marked as expired.
1. Create PayIn
POST /api/v1/payin/create
Request Body
{
"order_id": "YOUR-ORDER-001",
"amount": 1000,
"customer_phone": "9876543210",
"customer_name": "Rahul Sharma"
}
| Field | Type | Required | Description |
order_id | string | Optional | Your unique order ID (max 100 chars). Auto-generated if not provided. |
amount | number | Required | Collection amount in ₹ — minimum ₹300 |
customer_phone | string | Required | Customer's 10-digit mobile number |
customer_name | string | Optional | Customer name (max 100 chars) |
Response — 201
{
"success": true,
"data": {
"transaction_id": "txn_xxxxxxxxxxxxxxxx",
"order_id": "YOUR-ORDER-001",
"txn_ref": "PAYIN-REF-XXXXX",
"amount": 1000.00,
"commission": 10.00,
"intent_url": "upi://pay?pa=xxxxx&am=1000.00&cu=INR",
"expires_in": 600,
"status": "pending"
}
}
| Field | Description |
transaction_id | Save this — used for status checks |
intent_url | UPI payment link — generate QR or redirect mobile users |
expires_in | Seconds until expiry (600 = 10 minutes) |
commission | Your service charge — deducted from credited amount |
Showing the Payment to Customer
QR Code (Desktop)
<script src="https://cdnjs.cloudflare.com/ajax/libs/
qrcodejs/1.0.0/qrcode.min.js"></script>
<div id="qrcode"></div>
<input type="hidden" id="upi-url"
value="{{ $intentUrl }}">
<script>
new QRCode(document.getElementById('qrcode'), {
text: document.getElementById('upi-url').value,
width: 220, height: 220
});
</script>
UPI Button (Mobile)
<!-- Pass via hidden input to avoid
HTML encoding issues -->
<input type="hidden" id="upi-url"
value="{{ $intentUrl }}">
<button onclick="
window.location.href =
document.getElementById('upi-url').value
">
Pay with UPI App
</button>
2. Check Payment Status
GET /api/v1/payin/status/{txn_ref}
{
"success": true,
"data": {
"transaction_id": "txn_xxxxxxxxxxxxxxxx",
"order_id": "YOUR-ORDER-001",
"txn_ref": "PAYIN-REF-XXXXX",
"amount": 1000.00,
"commission": 10.00,
"utr": "407241812279",
"status": "success",
"created_at": "2024-04-30T10:00:00.000000Z"
}
}
| Status | Meaning |
pending | Awaiting customer payment |
success | Payment received — wallet credited |
failed | Payment failed |
expired | 10 minutes passed without payment |
3. Transaction History
GET /api/v1/payin/transactions
| Param | Description | Default |
page | Page number | 1 |
limit | Records per page (max 100) | 15 |
Payout
Transfer money directly to any bank account via IMPS.
Create Payout → Wallet debited (amount + commission) → Bank transfer → Webhook on final status
Wallet Debit: Transfer ₹5,000 + Commission ₹10 = ₹5,010 debited from wallet
Refund: If transfer fails, full amount is automatically refunded to wallet.
1. Initiate Payout
POST /api/v1/services/payout/process
Request Body
{
"mobile_no": "9876543210",
"beneficiary_name": "Rahul Sharma",
"account_no": "1234567890",
"ifsc": "SBIN0001234",
"bank_name": "State Bank of India",
"amount": 5000,
"transfer_type": "5",
"partner_request_id": "YOUR-UNIQUE-ORDER-ID"
}
| Field | Type | Required | Description |
mobile_no | string | Required | 10-digit mobile number |
beneficiary_name | string | Required | Account holder name (max 100 chars) |
account_no | string | Required | Bank account number (8–20 digits) |
ifsc | string | Required | IFSC code — format: ABCD0123456 |
bank_name | string | Required | Bank name (max 100 chars) |
amount | number | Required | Transfer amount in ₹ (min ₹1,000 — max ₹2,00,000) |
transfer_type | string | Required | Always "5" (IMPS) |
partner_request_id | string | Optional | Your unique order ID. Auto-generated if not sent. Used for duplicate prevention. |
Response — Success
{
"success": true,
"message": "Payout transferred successfully.",
"data": {
"transaction": {
"transaction_id": "txn_xxxxxxxxxxxxxxxx",
"reference_id": "bank_reference_number",
"partner_request_id": "YOUR-UNIQUE-ORDER-ID",
"status": "success",
"amount": 5000.00,
"charge": 10.00,
"net_amount": 5010.00
}
}
}
Response — Pending
{
"success": true,
"message": "Payout is being processed. You will be notified once settled.",
"data": {
"transaction": {
"status": "pending",
"amount": 5000.00,
"charge": 10.00,
"net_amount": 5010.00
}
}
}
| Status | Meaning |
success | Money credited to beneficiary |
pending | Bank processing — callback will follow |
failed | Transfer failed |
refunded | Transfer failed — amount refunded to wallet |
2. Transaction History
GET /api/v1/transactions/service/payout
| Param | Description | Default |
status | Filter: success / pending / failed / refunded | All |
from_date | Start date — YYYY-MM-DD | — |
to_date | End date — YYYY-MM-DD | — |
page | Page number | 1 |
limit | Records per page (max 100) | 15 |
3. Single Transaction
GET /api/v1/transactions/service/payout/{transaction_id}
Wallet
Check your wallet balance and transaction history.
Balance
GET /api/v1/wallet/balance
{
"success": true,
"data": {
"balance": 45000.00,
"locked_balance": 0.00
}
}
| Field | Description |
balance | Available balance — usable for payouts |
locked_balance | On-hold amount — not available for use |
Callback (Webhook)
KlyroPay sends a POST request to your registered callback URL when a transaction reaches a final status.
Important: Callbacks are sent only on success, failed, refunded, and expired — not on pending.
Retry: 5 attempts with 5-minute gaps if your server doesn't return HTTP 200.
Callback Request
POST https://yourserver.com/your-callback-endpoint
Content-Type: application/json
X-KlyroPay-Event: transaction.updated
X-KlyroPay-Signature: hmac_sha256_signature
PayIn Callback Payload
{
"event": "transaction.updated",
"transaction_id": "txn_xxxxxxxxxxxxxxxx",
"service": "payin",
"status": "success",
"amount": 1000.00,
"commission": 10.00,
"net_amount": 990.00,
"order_id": "YOUR-ORDER-001",
"txn_ref": "PAYIN-REF-XXXXX",
"utr": "407241812279",
"timestamp": "2024-04-30T10:05:00.000000Z"
}
Payout Callback Payload
{
"event": "transaction.updated",
"transaction_id": "txn_xxxxxxxxxxxxxxxx",
"service": "payout",
"status": "success",
"amount": 5000.00,
"commission": 10.00,
"net_amount": 5010.00,
"reference_id": "bank_ref_number",
"partner_request_id": "YOUR-ORDER-ID",
"timestamp": "2024-04-16T10:30:00.000000Z"
}
Verify Signature
Always verify the signature to ensure the callback is from KlyroPay.
PHP
$sig = $_SERVER['HTTP_X_KLYROPAY_SIGNATURE'];
$payload = json_decode(
file_get_contents('php://input'), true
);
$expected = hash_hmac(
'sha256',
json_encode($payload),
'YOUR_API_KEY'
);
if (!hash_equals($expected, $sig)) {
http_response_code(401);
exit;
}
// Valid — process the callback
http_response_code(200);
echo json_encode(['status' => 'ok']);
Node.js
const crypto = require('crypto');
const sig = req.headers[
'x-klyropay-signature'
];
const expected = crypto
.createHmac('sha256', 'YOUR_API_KEY')
.update(JSON.stringify(req.body))
.digest('hex');
if (!crypto.timingSafeEqual(
Buffer.from(expected),
Buffer.from(sig)
)) {
return res.status(401).send('Unauthorized');
}
res.status(200).json({ status: 'ok' });
Error Reference
All error responses follow this format:
{ "success": false, "message": "Error description.", "data": null }
| HTTP Code | Message | Reason |
| 401 | API key is missing | X-Api-Key header not sent |
| 401 | Invalid API key | Key is incorrect |
| 401 | API key is inactive or expired | Key revoked or expired |
| 403 | No IP whitelist configured | No IP approved yet |
| 403 | Your IP is not whitelisted | Request from non-whitelisted IP |
| 403 | You do not have access to this service | Service not assigned to your account |
| 409 | Duplicate request | partner_request_id already exists |
| 422 | Validation failed | Invalid request fields |
| 422 | Insufficient wallet balance | Not enough balance for payout |
| 429 | Rate limit exceeded | Too many requests per minute |
Quick Reference
| Method | Endpoint | Description |
| POST | /api/v1/payin/create | Create PayIn request |
| GET | /api/v1/payin/status/{txn_ref} | Check PayIn status |
| GET | /api/v1/payin/transactions | PayIn history |
| POST | /api/v1/services/payout/process | Initiate payout |
| GET | /api/v1/transactions/service/payout | Payout history |
| GET | /api/v1/transactions/service/payout/{id} | Single payout detail |
| GET | /api/v1/wallet/balance | Wallet balance |