Overview
NRPS is a reconciliation and provisioning system for collection requests. Your system creates a payment request, redirects the customer to a hosted payment page, and waits for verification or provider confirmation. Manual methods collect UTR/proof from the customer. Automated UPI requests show a QR code and update automatically after provider confirmation.
Once the transaction is approved or rejected, Nirmaata sends a webhook to your configured endpoint. Your system can also poll the status APIs if needed.
Payment links are single-use. After a customer submits UTR/details, the payment page is locked and cannot be opened or shared again.
- Merchant checks active payment methods.
- Merchant creates a payment request.
- Merchant redirects customer to returned payment URL.
- Customer pays using the selected method.
- Manual payments are verified by staff; automated UPI is confirmed by provider update.
- Nirmaata sends webhook to merchant.
- Merchant marks order as paid/rejected.
Authentication
Every API request must include both the API key and API secret issued to the merchant. These credentials identify the merchant and protect the API from unauthorized order creation or status access.
X-Api-Key: YOUR_API_KEY
X-Api-Secret: YOUR_API_SECRET
cURL Example
curl -X POST "{BASE_URL}/api/v1/payments" \
-H "Content-Type: application/json" \
-H "X-Api-Key: YOUR_API_KEY" \
-H "X-Api-Secret: YOUR_API_SECRET" \
-d '{"order_id":"ORDER-1001","amount":1250.00,"customer_name":"Customer Name"}'
| X-Api-Key | Merchant public API key. |
| X-Api-Secret | Merchant private API secret. Do not expose this in frontend code. |
Fetch Active Payment Methods
Use this endpoint before creating a payment request if your checkout needs to show only currently available methods. A method is returned only when it is active and mapped to an active collection bank account.
GET /api/v1/payment-methods
{
"success": true,
"data": {
"payment_methods": [
{ "code": "UPI", "name": "UPI", "available": true },
{ "code": "IMPS", "name": "IMPS", "available": true },
{ "code": "RTGS", "name": "RTGS", "available": true }
]
}
}
Create Payment Request
This endpoint creates a hosted payment page. Store the returned payment_id and request_ref in your order table. The returned payment_url should be shown to or redirected for the customer.
If the same merchant sends the same order_id again, the existing payment request is returned instead of creating a duplicate.
If payment_expires_at is omitted, the link expires 24 hours after creation. Once UTR is submitted, the link is considered used even if staff review is still pending.
POST /api/v1/payments
Content-Type: application/json
Request Body
| order_id | Required. Unique merchant order ID. |
| amount | Required. Amount to be collected. |
| customer_id | Optional merchant customer ID. |
| customer_name | Customer name shown on payment page. |
| customer_email | Customer email shown on payment page. |
| customer_mobile | Customer mobile shown on payment page. |
| return_url | URL where customer is redirected after UTR submission. |
| failure_url | Reserved for failure/cancel flows. |
| payment_method | Optional preferred method: UPI, IMPS, or RTGS. |
| payment_expires_at | Optional expiry date/time in YYYY-MM-DD HH:MM:SS format. Defaults to 24 hours from creation. |
{
"order_id": "ORDER-1001",
"amount": 1250.00,
"customer_id": "CUST-1001",
"customer_name": "Customer Name",
"customer_email": "customer@merchantdomain.com",
"customer_mobile": "9999999999",
"return_url": "https://merchant.example.com/success",
"failure_url": "https://merchant.example.com/failed",
"payment_method": "UPI",
"payment_expires_at": "2026-06-11 18:30:00"
}
Response
{
"success": true,
"payment_id": "PAY202606100101019999",
"request_ref": "R202606100101019999",
"order_id": "ORDER-1001",
"amount": 1250,
"fee_amount": 25,
"net_amount": 1225,
"payment_expires_at": "2026-06-11 18:30:00",
"status": "Received",
"payment_origin": "checkout",
"payment_url": "{BASE_URL}/pay/{token}",
"email_sent": false
}
Create And Send Link
Use POST /api/v1/payment-links when you want NRPS to optionally send the payment link email using platform SMTP. Send send_email: true to email the customer from NRPS, or send_email: false when your own system will share the returned payment_url.
{
"order_id": "ORDER-1002",
"amount": 2500.00,
"customer_name": "Customer Name",
"customer_email": "customer@merchantdomain.com",
"payment_method": "UPI",
"payment_expires_at": "2026-06-11 18:30:00",
"send_email": true
}
{
"success": true,
"payment_id": "PAY202606100101029999",
"request_ref": "R202606100101029999",
"order_id": "ORDER-1002",
"amount": 2500,
"fee_amount": 50,
"net_amount": 2450,
"payment_expires_at": "2026-06-11 18:30:00",
"status": "Received",
"payment_origin": "payment_link",
"payment_url": "{BASE_URL}/pay/{token}",
"email_sent": true
}
Automated UPI Flow
Automated UPI is used when UPI is mapped to an automated provider route for the merchant. Your system creates the payment request in the same way as other methods and redirects the customer to the returned payment_url.
The hosted page generates a provider-backed QR code. The customer does not enter UTR or upload proof. NRPS updates the request after provider confirmation and sends your configured merchant webhook.
Create Request
POST /api/v1/payments
Content-Type: application/json
{
"order_id": "ORDER-1001",
"amount": 1250.00,
"customer_name": "Customer Name",
"customer_mobile": "9999999999",
"payment_method": "UPI",
"return_url": "https://merchant.example.com/success",
"failure_url": "https://merchant.example.com/failed"
}
Customer Handling
- Redirect the customer to
payment_url. - Customer scans the QR and completes payment.
- The payment page checks status automatically while open.
- Your backend should wait for the merchant webhook, or poll status as a backup.
Status Check
Use status APIs when the customer returns to your site or when your system needs to reconcile an open request. For automated UPI, checking status can trigger a provider status refresh if the request is still open.
GET /api/v1/payments/{payment_id}
GET /api/v1/payment-requests/{request_ref}
Cancel And Recreate
If the customer abandons checkout, wants to change order details, or needs a fresh QR, cancel the open automated UPI request and create a new one. Do not reuse the old payment URL after cancellation.
POST /api/v1/payments/{payment_id}/cancel
POST /api/v1/payment-requests/{request_ref}/cancel
Cancellation is allowed only before the request reaches a final state. If payment has already been confirmed, the cancel API returns an error and your system should use the latest status/webhook result.
Source Of Truth
The final merchant-facing source of truth is the NRPS webhook sent to your configured webhook URL. Status APIs are useful for polling and recovery, but your order should be finalized only after verified API status or webhook confirmation from NRPS.
Payment Origins
Every transaction carries payment_origin so merchants and operators can identify how the payment request was created.
| checkout | Payment request created from merchant checkout/API flow. |
| payment_link | Payment request created as a direct payment link. |
More origins can be added later through the normalized payment_origins table.
Customer Redirect
Redirect the customer to payment_url. The hosted page displays the amount and the available payment instructions.
For automated UPI, the page displays a provider-backed QR code and the request updates automatically after payment confirmation. The customer does not submit UTR/proof for automated UPI.
For manual UPI, IMPS, and RTGS, the page displays collection details and asks the customer to submit UTR/reference proof. UTR validation is method-specific:
| UPI / IMPS | 12-16 digits only. |
| RTGS | 22-character alphanumeric UTR starting with 4-letter bank code. |
Duplicate UTR values are rejected for manual methods. After successful manual submission or final automated confirmation, the same payment page URL becomes unavailable.
Status APIs
Use status APIs to poll payment state if your system does not rely only on webhook callbacks. You can check by payment_id or request_ref.
For automated UPI, status checks may trigger a provider status refresh when the transaction is still open. Use this as a backup to webhook delivery, not as the primary customer confirmation mechanism.
GET /api/v1/payments/{payment_id}
GET /api/v1/payment-requests/{request_ref}
{
"success": true,
"request": {
"status": "Approved",
"request_ref": "R202606100101019999",
"payment_id": "PAY202606100101019999",
"order_id": "ORDER-1001",
"payment_method": "UPI",
"amount": "1250.00",
"fee_amount": "25.00",
"net_amount": "1225.00",
"payment_expires_at": "2026-06-11 18:30:00"
},
"payment": {
"paid_amount": "1250.00",
"utr": "123456789012",
"payment_date": "2026-06-10 01:30:00",
"verification_status": "Verified",
"verified_at": "2026-06-10 01:40:00",
"remarks": "Payment approved"
}
}
Cancel Payment Request
Use this endpoint when the customer cancels checkout, wants to change the order, or needs a fresh payment request. Cancellation is supported for open automated UPI requests only. Final requests such as approved, settled, rejected, or failed cannot be cancelled.
POST /api/v1/payments/{payment_id}/cancel
POST /api/v1/payment-requests/{request_ref}/cancel
Headers
X-Api-Key: YOUR_API_KEY
X-Api-Secret: YOUR_API_SECRET
Response
{
"success": true,
"payment_id": "PAY202606100101019999",
"request_ref": "R202606100101019999",
"order_id": "ORDER-1001",
"status": "Failed",
"provider_status": "In Process",
"message": "Payment request cancelled."
}
After cancellation, create a new payment request if the customer needs to pay again. Do not reuse the cancelled payment URL.
Balance Summary
This endpoint returns approved/settled collection summaries for the merchant. Use it for merchant dashboards, reconciliation, and settlement planning.
POST /api/v1/balance-summary
| start_date | Optional. Filter start datetime. |
| end_date | Optional. Filter end datetime. |
| type | consolidated or daily. |
{
"start_date": "2026-05-01 00:00:00",
"end_date": "2026-05-03 23:59:59",
"type": "daily"
}
Service Status & Support
Use the service status endpoint to check NRPS availability before initiating checkout.
GET /api/v1/service-status
{
"success": true,
"service": "Nirmaata Reconciliation and Provisioning System (NRPS)",
"status": "live",
"database": "ok",
"timestamp": "2026-06-27T10:30:00+05:30"
}
Merchants can raise support tickets through API. Failed transaction tickets require both request_id and utr.
POST /api/v1/support/tickets
{
"category": "failed_transaction",
"priority": "high",
"request_id": "R202606100101019999",
"utr": "180127144274",
"subject": "Customer debited but payment not approved",
"message": "Customer has shared bank confirmation, but the payment is still pending."
}
Supported categories are failed_transaction, refund, technical, settlement, payout, and other.
Webhook
Nirmaata sends a webhook when a submitted payment is approved, rejected, or failed by an authorized reviewer. Your system should verify the signature before updating the order.
Headers
X-Nirmaata-Webhook-Id: evt_xxx
X-Nirmaata-Webhook-Timestamp: 1780000000
X-Nirmaata-Webhook-Signature: sha256={hmac}
Payload
{
"event": "payment.approved",
"event_id": "evt_9f4b6e2d7c8a1b2c3d4e5f60",
"payment_id": "PAY202606100101019999",
"request_ref": "R202606100101019999",
"order_id": "ORDER-1001",
"amount": "1250.00",
"utr": "123456789012",
"status": "approved",
"timestamp": "2026-06-10T01:40:00+00:00"
}
Verification
- Read the raw JSON body exactly as received.
- Read
X-Nirmaata-Webhook-Timestamp. - Build the string:
timestamp + "." + raw_json_payload. - Generate HMAC SHA-256 using your webhook secret.
- Prefix with
sha256=. - Compare with
X-Nirmaata-Webhook-Signature.
sha256=<hmac_sha256(timestamp + "." + raw_json_payload, webhook_secret)>
Webhook retries reuse the same event ID, timestamp, payload, and signature. Retry actions are stored in the audit trail.
Error Codes
API failures return a stable error_code along with the HTTP status and readable message. Integrations should use error_code for program logic and show message only where suitable.
{
"success": false,
"error_code": "DUPLICATE_UTR",
"message": "This UTR has already been submitted"
}
| HTTP | Error Code | Meaning |
|---|---|---|
| 400 | BAD_REQUEST | Request body or request format is invalid. |
| 401 | INVALID_API_CREDENTIALS | API key or API secret is missing or incorrect. |
| 401 | UNAUTHORIZED | Request is not authorized. |
| 403 | IP_NOT_ALLOWED | Merchant API key is not allowed from the request IP. |
| 403 | DOMAIN_NOT_ALLOWED | Merchant API key is not allowed from the request domain. |
| 403 | FORBIDDEN | Authenticated user or API client cannot perform this action. |
| 404 | PAYMENT_NOT_FOUND | Payment page, payment request, or status record was not found. |
| 404 | NOT_FOUND | Requested resource was not found. |
| 410 | PAYMENT_EXPIRED | Payment link has expired. |
| 419 | INVALID_SECURITY_TOKEN | Security token is invalid or expired. |
| 422 | VALIDATION_FAILED | Required fields or values failed validation. |
| 422 | INVALID_AMOUNT | Amount is missing, non-numeric, zero, or negative. |
| 422 | AMOUNT_LIMIT_EXCEEDED | Amount exceeds the platform allowed limit. |
| 422 | AMOUNT_NOT_SUPPORTED | Amount is outside the configured route/provider limit. |
| 422 | METHOD_NOT_AVAILABLE | No active route is available for the requested payment method. |
| 422 | INVALID_PAYMENT_METHOD | Payment method or mapped collection account is invalid. |
| 422 | INVALID_UTR | UTR/reference format is invalid for the selected payment method. |
| 422 | DUPLICATE_UTR | UTR/reference has already been submitted or used. |
| 422 | INVALID_EXPIRY | Payment expiry value is invalid or not in the future. |
| 422 | SUPPORT_REFERENCE_REQUIRED | Failed transaction support requests require request ID and UTR. |
| 422 | SUPPORT_DETAILS_REQUIRED | Support subject or message is missing. |
| 422 | INVALID_SUPPORT_CATEGORY | Support category is not supported. |
| 500 | SERVER_ERROR | Temporary internal error. |
| 502 | UPSTREAM_ERROR | External dependency failed. |
| 503 | SERVICE_UNAVAILABLE | Service is temporarily unavailable. |
Settlements & Payouts
Settlements and payouts are managed in the NRPS portal for reconciliation. These are operational records and do not change the merchant payment API identifiers.
| Settlement Reference | Unique internal reference such as SET202606101030001234. |
| Payout Reference | Unique payout/bank reference entered by the platform team or generated by the system. |
| Mapping | One payout can clear multiple locked settlements. The portal shows which settlement was cleared in which payout. |
When payout status is paid, Nirmaata sends the merchant a payout email with settlement references covered. |
Security Notes
- Never expose API secret or webhook secret in frontend code.
- Verify every webhook signature before provisioning an order.
- Reject old webhook timestamps to reduce replay risk.
- Use merchant IP/domain whitelisting where possible.
- Treat duplicate UTR as suspicious and do not provision twice.
- All API attempts are logged, including invalid credentials and blocked IP/domain attempts.
- API errors stay JSON for integrations. Browser/payment-page errors are shown as branded HTML pages.
Status Values
| Received | Payment request has been created and customer action is pending. |
| Pending Verification | Customer submitted UTR/proof and review is pending. |
| Approved | Payment has been verified and accepted. |
| Rejected | Payment was reviewed and rejected. |
| Failed | Payment failed or was manually failed. |
| Settled | Payment has been included in a locked settlement. |