Skip to main content

Create Refund

Create a refund for a completed INR transaction. Supports full and partial refunds. Refunds are processed as payouts to the customer's bank account via IMPS.

A refund is created and funds are immediately held. It is either auto-approved when auto-refund is enabled, or waits for ZenPays to approve it. Once approved it is sent to the provider, and on completion the held funds are debited. A rejected refund, or one that fails at the provider, releases the hold back to your balance.
How a refund is approved, sent and settled
POSThttps://api.zenpayz.com/merchant/api/v1/refund-intents
Bearer · API key

Request

Headers

HeaderDescription
Authorization
REQUIRED
Bearer {api_key}
X-Signature
REQUIRED
HMAC-SHA256 signature
X-Timestamp
REQUIRED
ISO 8601 timestamp
X-Secret-Salt
REQUIRED
Secret salt for HMAC validation
Content-Type
REQUIRED
application/json
X-Idempotency-Key
OPTIONAL
Unique key to prevent duplicate refunds

Body Parameters

ParameterTypeDescription
transactionId
OPTIONAL
stringID of the original transaction to refund
reason
OPTIONAL
stringReason for the refund
amount
OPTIONAL
numberRefund amount. Omit for a full refund. Must be > 0 and ≤ the remaining refundable amount.
customerId
OPTIONAL
stringCustomer ID. Resolved from the transaction if omitted.
beneficiaryEmail
OPTIONAL
stringBeneficiary email address
beneficiaryAccount
OPTIONAL
stringBank account number
beneficiaryIfsc
OPTIONAL
stringIFSC code (e.g. HDFC0001234)
beneficiaryName
OPTIONAL
stringFull name of the beneficiary
beneficiaryMobile
OPTIONAL
stringBeneficiary mobile number with country code
beneficiaryCity
OPTIONAL
stringBeneficiary city

Beneficiary Fields

INR refunds are processed as IMPS payouts to the customer's bank account. You must provide:

FieldRequiredExample
beneficiaryEmailYes"rahul@example.com"
beneficiaryAccountYes"50100012345678"
beneficiaryIfscYes"HDFC0001234"

Optional fields

FieldDescriptionExample
beneficiaryNameAccount holder name"Rahul Sharma"
beneficiaryMobileMobile with country code"+919876543210"
beneficiaryCityCity"Mumbai"
warning

If beneficiaryAccount or beneficiaryIfsc is missing, the API will return an error.

Try it out

Test refund creation interactively using the API Simulator.

Response

Success (201 Created)

{
"success": true,
"data": {
"refundId": "refund_1774683026458_oann5ibjf",
"merchantId": "ZP_FIN_1774592804_0781001264",
"customerId": "cust_mn8yfewm_37ntht",
"transactionId": "txn_1774619159530_1_mn8yfmph_5iwb9b",
"paymentIntentId": "pi_1774619159530_66d8s8v25",
"amount": 100,
"originalAmount": 100,
"currency": "INR",
"refundType": "full",
"status": "pending_approval",
"tspProvider": "sulifu_pay",
"externalRefundId": null,
"reason": "Customer requested refund",
"createdAt": "2026-04-10T14:22:01.000Z",
"completedAt": null,
"failureReason": null,
"processingTimeMs": null
}
}

Error Responses

CodeHTTPMessage
REFUND_NOT_ALLOWED400Transaction cannot be refunded (must be success or partial_refund status)
REFUND_AMOUNT_EXCEEDED400Requested amount exceeds the remaining refundable amount
MISSING_BENEFICIARY_FIELDS400beneficiaryEmail, beneficiaryAccount, or beneficiaryIfsc is missing
UNAUTHORIZED401Invalid or missing API key
TRANSACTION_NOT_FOUND404Transaction does not exist or does not belong to this merchant
DUPLICATE_REQUEST409A refund with this idempotency key already exists
ALREADY_FULLY_REFUNDED422Transaction has already been fully refunded

Request Examples

Full refund

Refund the entire transaction amount to the customer's bank account:

{
"transactionId": "txn_1774619159530_1_mn8yfmph_5iwb9b",
"reason": "Customer requested full refund",
"beneficiaryEmail": "rahul@example.com",
"beneficiaryAccount": "50100012345678",
"beneficiaryIfsc": "HDFC0001234"
}

Response:

{
"success": true,
"data": {
"refundId": "refund_1774683026458_oann5ibjf",
"amount": 100,
"originalAmount": 100,
"currency": "INR",
"refundType": "full",
"status": "pending_approval",
"tspProvider": "sulifu_pay",
"reason": "Customer requested full refund",
"createdAt": "2026-04-10T14:22:01.000Z"
}
}

Partial refund

Refund 500 INR out of a 2000 INR transaction:

{
"transactionId": "txn_1774700012000_1_abc12345_9z8y7x",
"amount": 500,
"reason": "Partial item return",
"beneficiaryEmail": "priya@example.com",
"beneficiaryAccount": "91020034567890",
"beneficiaryIfsc": "SBIN0001234",
"beneficiaryName": "Priya Sharma"
}

Response:

{
"success": true,
"data": {
"refundId": "refund_1774700099000_kp3m7dxw2",
"amount": 500,
"originalAmount": 2000,
"currency": "INR",
"refundType": "partial",
"status": "pending_approval",
"tspProvider": "sulifu_pay",
"reason": "Partial item return",
"createdAt": "2026-04-10T14:35:00.000Z"
}
}

Amount exceeds refundable balance

If you try to refund more than the remaining balance:

{
"success": false,
"error": "Requested refund amount 1800 exceeds refundable amount 1250.00 INR"
}

Refund Lifecycle

After a refund is created, it moves through these statuses:

StatusWhat happens
pending_approvalRefund created. The refund amount is blocked (escrowed) in the merchant wallet. Waiting for admin to approve or reject.
approvedAdmin approved. The refund is being sent to the payment provider.
processingPayment provider is executing the payout to the customer.
completedPayout succeeded. Blocked funds are debited from the merchant wallet. Transaction refundedAmount is updated.
failedPayment provider failed to process. Blocked funds are released back to the merchant wallet.
rejectedAdmin rejected the refund. Blocked funds are released back.
cancelledMerchant cancelled the refund before processing. Blocked funds are released back.

Flow

                                    +---> rejected (funds released)
|
pending_approval ---> approved ---> processing ---> completed (funds debited)
| |
+---> cancelled (funds released) +---> failed (funds released)

Auto-approval

If auto_refund_enabled is true in the merchant configuration, refunds skip pending_approval and go directly to processing.

Auto-cancellation

If a refund stays in pending_approval for 2 days without admin action, it is automatically cancelled and the blocked funds are released.

Partial Refunds

You can issue multiple partial refunds against the same transaction.

  • Specify amount to refund less than the full transaction amount.
  • The system tracks cumulative refundedAmount on the transaction.
  • Each completed refund adds to the running total.
  • Validation: amount must be ≤ originalAmount - refundedAmount.
  • When cumulative refunds equal the transaction amount, the transaction becomes refunded and no more refunds are accepted.

Example: three partial refunds on a 1000 INR transaction

RefundAmountTransaction refundedAmountTransaction Status
1st300300partial_refund
2nd200500partial_refund
3rd5001000refunded
4th (rejected)1--Error: already fully refunded
info

Transactions in partial_refund status still accept new refund requests. You do not need to wait for a pending refund to complete before creating the next one -- the system validates against cumulative completed refunds only.

Code Examples

# Full refund
curl -X POST https://api.zenpayz.com/merchant/api/v1/refund-intents \
-H "Authorization: Bearer zp_live_abc123def456" \
-H "X-Timestamp: 2026-04-10T14:22:01.000Z" \
-H "X-Signature: a1b2c3d4e5f6..." \
-H "X-Secret-Salt: your_secret_salt" \
-H "Content-Type: application/json" \
-H "X-Idempotency-Key: refund-order-8842" \
-d '{
"transactionId": "txn_1774619159530_1_mn8yfmph_5iwb9b",
"reason": "Customer requested full refund",
"beneficiaryEmail": "rahul@example.com",
"beneficiaryAccount": "50100012345678",
"beneficiaryIfsc": "HDFC0001234"
}'

# Partial refund
curl -X POST https://api.zenpayz.com/merchant/api/v1/refund-intents \
-H "Authorization: Bearer zp_live_abc123def456" \
-H "X-Timestamp: 2026-04-10T14:35:00.000Z" \
-H "X-Signature: e5f6a7b8c9d0..." \
-H "X-Secret-Salt: your_secret_salt" \
-H "Content-Type: application/json" \
-d '{
"transactionId": "txn_1774700012000_1_abc12345_9z8y7x",
"amount": 500,
"reason": "Partial item return",
"beneficiaryEmail": "priya@example.com",
"beneficiaryAccount": "91020034567890",
"beneficiaryIfsc": "SBIN0001234",
"beneficiaryName": "Priya Sharma"
}'