Overview

NRPS is a reconciliation and provisioning system for offline bank transfers. Your system creates a payment request, redirects the customer to a hosted payment page, and waits for verification. The customer pays using UPI, IMPS, or RTGS, submits the UTR/reference number, and the transaction is reviewed by authorized staff.

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.

  1. Merchant checks active payment methods.
  2. Merchant creates a payment request.
  3. Merchant redirects customer to returned payment URL.
  4. Customer pays and submits UTR.
  5. Staff verifies the transaction.
  6. Nirmaata sends webhook to merchant.
  7. 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-KeyMerchant public API key.
X-Api-SecretMerchant 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_idRequired. Unique merchant order ID.
amountRequired. Amount to be collected.
customer_idOptional merchant customer ID.
customer_nameCustomer name shown on payment page.
customer_emailCustomer email shown on payment page.
customer_mobileCustomer mobile shown on payment page.
return_urlURL where customer is redirected after UTR submission.
failure_urlReserved for failure/cancel flows.
payment_methodOptional preferred method: UPI, IMPS, or RTGS.
payment_expires_atOptional 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
}

Payment Origins

Every transaction carries payment_origin so merchants and operators can identify how the payment request was created.

checkoutPayment request created from merchant checkout/API flow.
payment_linkPayment 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, merchant, customer/order details, and payment instructions.

For UPI, the page displays a self-hosted QR code using the NPCI UPI URI format and UPI ID. For IMPS/RTGS, it displays account name, bank name, account number, and IFSC.

After payment, the customer submits the UTR. UTR validation is method-specific:

UPI / IMPS12-16 digits only.
RTGS22-character alphanumeric UTR starting with 4-letter bank code.

Duplicate UTR values are rejected. After successful UTR submission, 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.

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"
  }
}

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_dateOptional. Filter start datetime.
end_dateOptional. Filter end datetime.
typeconsolidated 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

  1. Read the raw JSON body exactly as received.
  2. Read X-Nirmaata-Webhook-Timestamp.
  3. Build the string: timestamp + "." + raw_json_payload.
  4. Generate HMAC SHA-256 using your webhook secret.
  5. Prefix with sha256=.
  6. 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"
}
HTTPError CodeMeaning
400BAD_REQUESTRequest body or request format is invalid.
401INVALID_API_CREDENTIALSAPI key or API secret is missing or incorrect.
401UNAUTHORIZEDRequest is not authorized.
403IP_NOT_ALLOWEDMerchant API key is not allowed from the request IP.
403DOMAIN_NOT_ALLOWEDMerchant API key is not allowed from the request domain.
403FORBIDDENAuthenticated user or API client cannot perform this action.
404PAYMENT_NOT_FOUNDPayment page, payment request, or status record was not found.
404NOT_FOUNDRequested resource was not found.
410PAYMENT_EXPIREDPayment link has expired.
419INVALID_SECURITY_TOKENSecurity token is invalid or expired.
422VALIDATION_FAILEDRequired fields or values failed validation.
422INVALID_AMOUNTAmount is missing, non-numeric, zero, or negative.
422AMOUNT_LIMIT_EXCEEDEDAmount exceeds the platform allowed limit.
422AMOUNT_NOT_SUPPORTEDAmount is outside the configured route/provider limit.
422METHOD_NOT_AVAILABLENo active route is available for the requested payment method.
422INVALID_PAYMENT_METHODPayment method or mapped collection account is invalid.
422INVALID_UTRUTR/reference format is invalid for the selected payment method.
422DUPLICATE_UTRUTR/reference has already been submitted or used.
422INVALID_EXPIRYPayment expiry value is invalid or not in the future.
422SUPPORT_REFERENCE_REQUIREDFailed transaction support requests require request ID and UTR.
422SUPPORT_DETAILS_REQUIREDSupport subject or message is missing.
422INVALID_SUPPORT_CATEGORYSupport category is not supported.
500SERVER_ERRORTemporary internal error.
502UPSTREAM_ERRORExternal dependency failed.
503SERVICE_UNAVAILABLEService 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 ReferenceUnique internal reference such as SET202606101030001234.
Payout ReferenceUnique payout/bank reference entered by the platform team or generated by the system.
MappingOne payout can clear multiple locked settlements. The portal shows which settlement was cleared in which payout.
EmailWhen 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

ReceivedPayment request has been created and customer action is pending.
Pending VerificationCustomer submitted UTR/proof and review is pending.
ApprovedPayment has been verified and accepted.
RejectedPayment was reviewed and rejected.
FailedPayment failed or was manually failed.
SettledPayment has been included in a locked settlement.