API Documentation (UPI) (v2)
Build seamless UPI checkout experiences. Matrix Pay v2 APIs provide cryptographically secure, high-performance endpoints for generating dynamic UPI collection links and instantly verifying order status.
Quick Start & API Access
Production VerifiedFollow these 4 sequential steps to activate your reseller account and obtain live credentials.
Get your API Keys
Visit your Developer Hub to generate your live Client ID and API Secret Key. Your API key stays strictly server-side — never expose it in frontend code, browser consoles, or git repositories.
Complete Verification (eKYC)
Complete the identity & business verification process in the eKYC tab of your merchant dashboard. API access is unlocked automatically once approved with an active plan.
Receive Client ID & API Key
Once verified, your credentials are live. Your Client ID is passed in HTTP headers as `X-Client-Id`. Your API Secret Key signs every request via HMAC-SHA256 and stays server-side permanently.
Configure IP Whitelisting
In Developer Hub → IP Whitelisting tab, add your server's static outbound IP address(es). Every API request is verified against this whitelist — unlisted IPs receive a 403 IP_RESTRICTED response.
Build with an AI assistant
Latest AI TrendThis documentation sits behind authentication, so ChatGPT, Claude, Cursor, and Copilot cannot browse it directly. Copy the brief below into your assistant instead. It carries the complete specification on its own: every endpoint, payload schema, the order lifecycle, canonical HMAC-SHA256 signature protocol, webhook verification, and common pitfalls assistants get wrong (such as server-to-server only, no browser CORS, and production-first testing).
You are helping me integrate the Matrix Pay UPI payment gateway API into my application. Use only the specification below. Do not guess at endpoints, field names, or behaviour that is not written here, and do not try to fetch the documentation online: it sits behind an authenticated merchant dashboard and is not publicly reachable.
# 1. Non-negotiable constraints
1. This is a SERVER-TO-SERVER API. It enforces strict request validation and rejects browser-origin requests with CORS errors. Never call it from frontend JavaScript, browser applications, or mobile client code. All API calls must originate from my backend server.
2. The base host is https://matrixpay.vercel.app. THIS IS THE LIVE PRODUCTION HOST. There is no sandbox environment and no mock test mode. Testing is performed directly against production using real low-cost transactions of ₹1. Every transaction interacts with real banking and UPI infrastructure.
3. Every API call is an HTTP POST request with a JSON body and Content-Type: application/json.
4. Authentication is performed via canonical HMAC-SHA256 request signing sent in custom HTTP request headers. Never put the API Secret Key in the JSON request body or URL parameters.
Required headers on every request:
- X-Client-Id: My Merchant Live Client ID
- X-Signature: Hex-encoded HMAC-SHA256 signature
- X-Timestamp: Unix timestamp in seconds (integer string, valid within ±300s window)
- X-Nonce: Cryptographically random unique nonce string (8-16 bytes hex, replay protection)
5. HMAC-SHA256 Request Signing Protocol:
- Canonicalize the JSON body: sort all keys alphabetically (A-Z) recursively, eliminate all whitespace between keys and values.
- Construct signing string: "${canonical_json_body}.${timestamp}.${nonce}"
- Compute HMAC-SHA256 using my API Secret Key as the HMAC key. Output the result as a lowercase hexadecimal string.
6. IP Whitelisting: My server's static outbound IP address must be registered in the Developer Hub -> IP Whitelist tab. Requests originating from unlisted IPs are rejected with 403 IP_RESTRICTED.
7. The API Secret Key is confidential. It must never appear in frontend code, version control commits, public repositories, or client-side network inspect tabs. Store it as a secure environment variable on the server.
# 2. Endpoints
All endpoints accept HTTP POST with JSON body and the 4 authentication headers.
## Create UPI Order
POST https://matrixpay.vercel.app/api/v2/payment_gateway/create_upi_order
Headers:
Content-Type: application/json
X-Client-Id: <client_id>
X-Signature: <hmac_sha256_signature>
X-Timestamp: <timestamp_seconds>
X-Nonce: <unique_nonce>
Request Body:
{
"customer_name": "Customer Name",
"customer_email": "customer@example.com",
"customer_mobile": "9876543210",
"amount": 100.00,
"customer_reference": "YOUR_UNIQUE_ORDER_REF",
"redirect_url": "https://yourstore.com/checkout/return",
"service_type": "UPI"
}
Response (HTTP 200 or 201):
{
"order_id": "MP_MUEC7JEV_4977",
"customer_reference": "YOUR_UNIQUE_ORDER_REF",
"amount": 100.00,
"currency": "INR",
"payment_url": "https://matrixpay.vercel.app/pay/MP_MUEC7JEV_4977",
"upi_intent_url": "upi://pay?pa=matrixpay@icici&pn=MatrixPay&am=100.00&tr=MP_MUEC7JEV_4977",
"qr_data": "upi://pay?pa=matrixpay@icici&pn=MatrixPay&am=100.00&tr=MP_MUEC7JEV_4977",
"status": "pending",
"expires_at": "2026-09-24T12:00:00Z"
}
## Check UPI Order Status
POST https://matrixpay.vercel.app/api/v2/payment_gateway/check_upi_order_status
Headers:
Content-Type: application/json
X-Client-Id: <client_id>
X-Signature: <hmac_sha256_signature>
X-Timestamp: <timestamp_seconds>
X-Nonce: <unique_nonce>
Request Body:
{
"order_id": "MP_MUEC7JEV_4977"
}
Response (HTTP 200 or 422):
{
"order_id": "MP_MUEC7JEV_4977",
"customer_reference": "YOUR_UNIQUE_ORDER_REF",
"amount": 100.00,
"status": "success",
"paid_at": "2026-09-24T10:15:30Z",
"utr": "426189912001",
"gateway_reference": "RZP_PAY_991823"
}
# 3. Order Lifecycle & Statuses
The workflow sequence is:
1. Generate unique customer_reference on your server (e.g. ORD_${Date.now()}_${randomUUID()}).
2. Call create_upi_order with canonical HMAC-SHA256 signature headers.
3. Store order_id and customer_reference in your database.
4. Redirect user to payment_url or render the upi_intent_url / qr_data for mobile checkout.
5. Listen for incoming webhook notifications OR poll check_upi_order_status at 5-10s intervals until a terminal status is reached.
There are exactly four order statuses:
pending Order created and awaiting payment by customer. Not terminal. Do NOT deliver goods.
success Payment verified and captured. Terminal. Fulfil customer order and grant access.
refunded Transaction reversed or refunded. Terminal.
failed Transaction timed out, expired, or cancelled. Terminal.
# 4. Webhook Handling
Matrix Pay delivers asynchronous HTTP POST event updates to your configured Webhook URL.
Incoming Webhook Headers:
Content-Type: application/json
X-Webhook-Signature: <hmac_sha256_hex_signature>
X-Webhook-Event: payment.success | payment.failed | payment.refunded
X-Webhook-Id: <delivery_uuid>
Webhook Payload:
{
"event": "payment.success",
"order_id": "MP_MUEC7JEV_4977",
"customer_reference": "YOUR_UNIQUE_ORDER_REF",
"amount": 100.00,
"currency": "INR",
"status": "success",
"utr": "426189912001",
"timestamp": 1735689600
}
Signature Verification:
You MUST verify the signature using the raw request body buffer/string before JSON parsing:
expected_sig = HMAC_SHA256(secret = API_KEY, message = raw_request_body_string)
Compare expected_sig with header "X-Webhook-Signature" using a constant-time comparison.
Reject with 401 Unauthorized if signatures do not match. Respond with 200 OK immediately once verified.
# 5. How I want the integration written
- Implement a single, clean backend client class or module (e.g. MatrixPayClient).
- Keep API credentials strictly in environment variables (MATRIXPAY_CLIENT_ID and MATRIXPAY_API_KEY).
- Persist the customer_reference before sending the request and treat it as the idempotency key.
- Never retry a creation request with a new reference on network timeout — look up the order with check_upi_order_status instead.
- Implement exponential backoff retry logic for transient errors (HTTP 500, 502, 503).
- Do not retry client errors (HTTP 400, 401, 403, 429).
- Never log raw API secrets or sensitive signing keys.
# 6. What I want from you
Ask me which backend language/framework I am using (e.g. Node.js/TypeScript, Python/FastAPI/Django, PHP/Laravel, Go, Java/Spring, C#/.NET) and whether I prefer webhook delivery or status polling, then write the complete, production-ready integration client and webhook handler.Client Libraries & SDKs
7 Languages SupportedChoose your preferred backend language. All samples use standard HTTP and native cryptographic HMAC-SHA256 libraries.
Works seamlessly with Node 18+, Bun, Deno, Next.js, and Express.
npm install axios cryptoStandard library hmac + hashlib used for canonical signing. Works with FastAPI & Django.
pip install requestsNative hash_hmac('sha256') & ksort() used for strict key canonicalization.
composer require guzzlehttp/guzzleZero external dependencies — uses crypto/hmac, crypto/sha256, and net/http standard library.
go get github.com/matrixpay/go-gatewayCompatible with Java 11+ HttpClient and Spring Boot Microservices.
implementation 'org.apache.httpcomponents.client5:httpclient5'Built for .NET 6, 7, 8 & ASP.NET Core web APIs using HMACSHA256.
dotnet add package System.Net.Http.Json1. Signature Generation & Authentication
Server-side request signing protocol for canonical request authentication.
To enhance security, every request must be signed on your server. The signature is created by serializing the payload into canonical JSON (sorted keys, no whitespace), joining it with a timestamp and a random nonce, and hashing the result with your API key using HMAC-SHA256. The resulting signature is sent alongside the timestamp and nonce in the request headers. This must be done server-side so your API key is never exposed.
# 1. Define API Credentials & Payload
CLIENT_ID="your_client_id"
API_KEY="your_api_secret_key"
# 2. Generate Unix Epoch Timestamp & Random 16-hex Nonce
TIMESTAMP=$(date +%s)
NONCE=$(openssl rand -hex 16)
# 3. Form Canonical JSON (alphabetically sorted keys, compact separators)
PAYLOAD='{"amount":"100.96","customer_email":"john@gmail.com","customer_mobile":"9876543210","customer_name":"John Doe","redirect_url":"https://example.com/success"}'
# 4. Create Signing String: payload.timestamp.nonce
MESSAGE="${PAYLOAD}.${TIMESTAMP}.${NONCE}"
# 5. Compute HMAC-SHA256 Hex Digest
SIGNATURE=$(echo -n "${MESSAGE}" | openssl dgst -sha256 -hmac "${API_KEY}" -hex | sed 's/^.* //')
# 6. Send Request with Required Security Headers
curl -X POST "https://matrixpay.vercel.app/api/v2/payment_gateway/create_upi_order" \
-H "Content-Type: application/json" \
-H "X-Client-Id: ${CLIENT_ID}" \
-H "X-Timestamp: ${TIMESTAMP}" \
-H "X-Nonce: ${NONCE}" \
-H "X-Signature: ${SIGNATURE}" \
-d "${PAYLOAD}"Interactive HMAC-SHA256 Signature Calculator
Canonical Body + Timestamp + Nonce2. Webhook Verification & Handling
Verify incoming webhook event payloads from Matrix Pay servers.
To ensure security, you must verify the X-Webhook-Signature header sent with the webhook request. When an event occurs on your account, such as a successful payment, Matrix Pay will send an HTTP POST request to your configured webhook URL.
Webhook Headers
| Header Name | Type | Required | Description |
|---|---|---|---|
| X-Webhook-Signature | string | Required | The HMAC SHA256 signature generated using your API key to verify the payload integrity. |
| X-Webhook-Event | string | Required | The name of the event that triggered the webhook (e.g., payment.success). |
| X-Webhook-Id | string | Required | A unique identifier for this specific webhook delivery attempt. |
# Test your webhook handler locally from the command line:
API_KEY="your_api_secret_key"
PAYLOAD='{"event":"payment.success","order_id":"MSPGPL260101","amount":"100.96","utr_number":"312345678901","currency":"INR","timestamp":"2026-06-02T21:18:00Z"}'
# 1. Compute HMAC-SHA256 hex digest of RAW request payload
SIGNATURE=$(echo -n "${PAYLOAD}" | openssl dgst -sha256 -hmac "${API_KEY}" -hex | sed 's/^.* //')
# 2. Dispatch simulated webhook event
curl -X POST "http://localhost:5000/webhooks/matrixpay" \
-H "Content-Type: application/json" \
-H "X-Webhook-Signature: ${SIGNATURE}" \
-H "X-Webhook-Event: payment.success" \
-H "X-Webhook-Id: evt_test_12345" \
-d "${PAYLOAD}"Payload Parameters
When an event is triggered, our servers will dispatch a JSON payload to your configured endpoint. Below is a detailed breakdown of the data fields you will receive in the request body.
| Field Name | Type | Required | Description |
|---|---|---|---|
| event | string | Required | The type of event that triggered the webhook. You will receive either payment.success or payment.failed. |
| event_id | string | Required | A unique identifier generated by Matrix Pay for this specific webhook delivery. You can use this to prevent processing duplicate events. It will exactly match the X-Webhook-Id header. |
| order_id | string | Required | The unique Matrix Pay internal identifier for the processed UPI order (e.g. MSPGPL260101010203AB04). |
| utr_number | string | Required | The official Bank Unique Transaction Reference (UTR) number confirming the transfer. |
| amount | string | Required | The exact transaction amount that was processed, returned to you as a string. |
| status | string | Required | The final state of the transaction. You will receive the updated status, such as Success or Failed. |
| date_time | string | Optional | The ISO 8601 timestamp representing when the transaction was completed on our system. |
| comment | string | Optional | The optional comment or note you provided during the initial order creation. |
| sent_at | string | Required | The ISO 8601 timestamp recording exactly when our server dispatched this webhook payload to your endpoint. |
Example Webhook JSON Payload
{
"event": "payment.success",
"event_id": "9b1deb4d-3b7d-4bad-9bdd-2b0d7b3dcb6d",
"order_id": "MSPGPL260101010203AB04",
"utr_number": "312345678901",
"amount": "100.96",
"status": "Success",
"date_time": "2026-06-02T21:18:00+05:30",
"comment": "Payment for services",
"sent_at": "2026-06-02T21:18:05+05:30"
}Acknowledging Webhooks
After verifying the signature and processing the payload, your server must acknowledge receipt by returning a 2xx HTTP status code (such as 200 OK) within 5 seconds.
To explicitly confirm that your system successfully handled the event, we strongly recommend responding with a JSON payload containing {"received": true}. If your server responds with a non-2xx status code, or if the request times out, our systems will automatically retry the webhook delivery up to 5 times with increasing delays.
https://matrixpay.vercel.app/api/v2/payment_gateway/create_upi_orderGenerates a dynamic UPI payment link and QR code. This endpoint returns a unique URL that you can present to your customers to collect payments via installed UPI apps or by scanning.
Headers
| Header | Type | Required | Description |
|---|---|---|---|
| X-Client-Id | string | Required | Your unique Client ID provided by Matrix Pay. |
| X-Signature | string | Required | The HMAC-SHA256 signature generated using your API key and the request payload. Required for authentication. |
| Content-Type | string | Required | Must be set to application/json. |
Body Parameters
[ ] { } ( ), dollar signs $, or angled brackets < > in any of the values.| Field | Type | Required | Rules & Description |
|---|---|---|---|
| amount | string | Required | The exact transaction amount to be charged. Min 1.00, max of 2 decimal places allowed (e.g. "100.96"). |
| redirect_url | string | Required | The destination URL where customer will be redirected automatically after completing payment. Localhost restricted. |
| customer_name | string | Required | Min 3 chars. Only letters, spaces, and dots allowed (e.g. "John Doe"). |
| customer_email | string | Required | Must be a valid email address format (e.g. "john@gmail.com"). |
| customer_mobile | string | Required | Must be exactly 10 digits (e.g. "9876543210"). |
# 1. Set Credentials & Payload
CLIENT_ID="your_client_id"
API_KEY="your_api_secret_key"
TIMESTAMP=$(date +%s)
NONCE=$(openssl rand -hex 16)
PAYLOAD='{"amount":"100.96","customer_email":"john@gmail.com","customer_mobile":"9876543210","customer_name":"John Doe","redirect_url":"https://example.com/success"}'
# 2. Compute HMAC Signature
SIGNATURE=$(echo -n "${PAYLOAD}.${TIMESTAMP}.${NONCE}" | openssl dgst -sha256 -hmac "${API_KEY}" -hex | sed 's/^.* //')
# 3. Create UPI Order
curl -X POST "https://matrixpay.vercel.app/api/v2/payment_gateway/create_upi_order" \
-H "Content-Type: application/json" \
-H "X-Client-Id: ${CLIENT_ID}" \
-H "X-Timestamp: ${TIMESTAMP}" \
-H "X-Nonce: ${NONCE}" \
-H "X-Signature: ${SIGNATURE}" \
-d "${PAYLOAD}"Response Parameters Table
| Field | Type | Description |
|---|---|---|
| success | boolean | Returns true for success and false for failures. |
| data.order_id | string | Unique Matrix Pay internal identifier generated for this order. |
| data.status | string | Initial state of order (e.g., Pending). |
| data.amount | string | Requested transaction amount. |
| data.currency | string | Currency code, fixed to INR. |
| data.payment_url | string | Destination URL for customer payment completion. |
Response Example (201 OK)
{
"success": true,
"data": {
"order_id": "MSPGPL260101010203AB04",
"status": "Pending",
"amount": "100.96",
"currency": "INR",
"payment_url": "https://matrixpay.vercel.app/pay/xyz123"
},
"error": null
}Live Interactive Console — Create UPI Order
POST /api/v2/payment_gateway/create_upi_order# 1. Calculate HMAC-SHA256 signature
TIMESTAMP=$(date +%s)
NONCE=$(openssl rand -hex 8)
PAYLOAD='{"amount":"100.00","customer_mobile":"9876543210","customer_name":"John Doe","order_id":"ORD_UPI_7891","redirect_url":"https://example.com/payment/callback"}'
SIGNATURE=$(echo -n "${PAYLOAD}.${TIMESTAMP}.${NONCE}" | openssl dgst -sha256 -hmac "${displayApiKey}" -hex | sed 's/^.* //')
curl -X POST "https://matrixpay.vercel.app/api/v2/payment_gateway/create_upi_order" \
-H "Content-Type: application/json" \
-H "X-Client-Id: ${displayClientId}" \
-H "X-Signature: ${SIGNATURE}" \
-H "X-Timestamp: ${TIMESTAMP}" \
-H "X-Nonce: ${NONCE}" \
-d "${PAYLOAD}"https://matrixpay.vercel.app/api/v2/payment_gateway/check_upi_order_statusRetrieve the details of an existing payment link or transaction status programmatically.
# 1. Set Credentials & Order ID
CLIENT_ID="your_client_id"
API_KEY="your_api_secret_key"
TIMESTAMP=$(date +%s)
NONCE=$(openssl rand -hex 16)
PAYLOAD='{"order_id":"MP_MUEC7JEV_4977"}'
# 2. Compute HMAC Signature
SIGNATURE=$(echo -n "${PAYLOAD}.${TIMESTAMP}.${NONCE}" | openssl dgst -sha256 -hmac "${API_KEY}" -hex | sed 's/^.* //')
# 3. Check Order Status
curl -X POST "https://matrixpay.vercel.app/api/v2/payment_gateway/check_upi_order_status" \
-H "Content-Type: application/json" \
-H "X-Client-Id: ${CLIENT_ID}" \
-H "X-Timestamp: ${TIMESTAMP}" \
-H "X-Nonce: ${NONCE}" \
-H "X-Signature: ${SIGNATURE}" \
-d "${PAYLOAD}"Order Status Enum Values
| Status Enum | Description |
|---|---|
| Success | Payment received from the user and verified against banking UTR. |
| Refunded | Payment was received and subsequently refunded to the user. |
| Pending | Awaiting payment from the user. |
| Queue | Payment is being processed by banking rails. |
| Failed | Transaction attempted but not completed. |
| Cancelled | User exited the session before paying. |
| Expired | Payment session timed out before user paid. |
Selectable Status Response Examples
// HTTP Status: 200 OK
{
"success": true,
"data": {
"order_id": "MSPGPL260101010203AB04",
"amount": "100.96",
"currency": "INR",
"status": "Success",
"message": "Payment amount received from the user.",
"utr_number": "312345678901",
"date_time": "2026-06-02T21:18:00+05:30",
"created_at": "2026-06-02T21:15:00+05:30"
},
"error": null
}Live Interactive Console — Check UPI Order Status
POST /api/v2/payment_gateway/check_upi_order_status# 1. Calculate HMAC-SHA256 signature
TIMESTAMP=$(date +%s)
NONCE=$(openssl rand -hex 8)
PAYLOAD='{"order_id":"MP_MUEC7JEV_4977"}'
SIGNATURE=$(echo -n "${PAYLOAD}.${TIMESTAMP}.${NONCE}" | openssl dgst -sha256 -hmac "${displayApiKey}" -hex | sed 's/^.* //')
curl -X POST "https://matrixpay.vercel.app/api/v2/payment_gateway/check_upi_order_status" \
-H "Content-Type: application/json" \
-H "X-Client-Id: ${displayClientId}" \
-H "X-Signature: ${SIGNATURE}" \
-H "X-Timestamp: ${TIMESTAMP}" \
-H "X-Nonce: ${NONCE}" \
-d "${PAYLOAD}"5. Comprehensive Error Codes Table
Full reference of HTTP status codes and programmatic error codes returned by Matrix Pay APIs.
| HTTP Status | Error Code(s) | Description & Remediation |
|---|---|---|
| 400 Bad Request | INVALID_JSON / INVALID_PAYLOAD / INVALID_AMOUNT / INVALID_CUSTOMER_NAME | Payload is invalid JSON, violates firewall (forbidden symbols), or individual fields failed validation. Amount must have max 2 decimal places. |
| 401 Unauthorized | AUTH_HEADERS_MISSING / UNAUTHORIZED / STALE_REQUEST | Missing headers (X-Client-Id, X-Signature, X-Timestamp, X-Nonce), invalid credentials, or timestamp outside allowed time window. |
| 403 Forbidden | IP_WHITELIST_EMPTY / IP_RESTRICTED / INVALID_SIGNATURE / SUBSCRIPTION_REQUIRED | Access control violation: IP not whitelisted, invalid HMAC signature, or no active subscription plan on merchant account. |
| 409 Conflict | SERVICE_NOT_AUTHORIZED | Credentials are valid but not authorized for the Payment Gateway service. |
| 429 Too Many Requests | QUOTA_EXCEEDED / VOLUME_LIMIT_EXCEEDED | Plan limit hit. QUOTA_EXCEEDED means monthly order quota is full; VOLUME_LIMIT_EXCEEDED means order amount exceeds plan volume limit. Upgrade plan to continue. |
| 502 Bad Gateway | PAYMENT_LINK_FAILED | Upstream payment gateway (Razorpay, Zoho, HDFC, Paytm) failed to generate payment link. Retry request. |
| 503 Service Unavailable | INACTIVE_MERCHANT / BUSY_MERCHANT | INACTIVE_MERCHANT indicates receiving account is misconfigured. BUSY_MERCHANT indicates automated merchant has no amount slot available for this value, retry after short delay. |
| 500 Internal Error | SERVER_ERROR | Unexpected server-side error. Contact support with your order_id. |
Security Best Practices
Mandatory security guidelines every merchant integration must follow.
Your API Secret Key must only exist in server-side code (Node.js, Python, PHP, Go, Java, C#). It must never be bundled, minified, or embedded in browser-facing code, mobile apps, or HTML.
Never hardcode credentials in source files. Use environment variables (e.g. process.env.MATRIXPAY_API_KEY) and a secrets manager for production. Rotate immediately if exposed.
All API calls must be made over HTTPS (TLS 1.2 minimum, TLS 1.3 recommended). Plain HTTP connections are rejected. Validate SSL certificates — never disable certificate verification.
Rotate your API Secret Key on a regular schedule (recommended every 90 days) or immediately upon suspected compromise. New keys take effect instantly; old keys are invalidated.
Configure your server's static outbound IP address(es) in Developer Hub → IP Whitelist tab. Only whitelisted IPs can call the API. Use dedicated NAT gateway IPs in cloud environments — dynamic IPs will be blocked.
Matrix Pay APIs are server-to-server only. Browser-origin requests via CORS are deliberately blocked. Always proxy API calls through your backend — never call the gateway directly from a browser or mobile app frontend.
Critical Security Notice
If your API Secret Key is ever committed to source control, logged in browser DevTools, or returned in a client-facing response — treat it as compromised immediately. Regenerate your keys from the Developer Hub and audit your logs.
Rate Limits & Plan Quotas
API usage limits are enforced per merchant account based on your active subscription plan.
| Limit Type | Details | Error Code | Action |
|---|---|---|---|
| Monthly Order Quota | Maximum number of orders per calendar month as defined by your plan tier | QUOTA_EXCEEDED (429) | Upgrade your plan or wait for monthly reset |
| Monthly Volume Limit | Maximum total transaction value per calendar month (e.g. ₹25,00,000 / month) | VOLUME_LIMIT_EXCEEDED (429) | Upgrade your plan or reduce order amounts |
| Request Signing Window | Timestamp in X-Timestamp header must be within ±300 seconds of server time | STALE_REQUEST (401) | Sync your server clock with NTP |
| Nonce Reuse | Each X-Nonce value must be globally unique — replay attacks are blocked | UNAUTHORIZED (401) | Generate a fresh cryptographic nonce per request |
| Concurrent Requests | Excessive parallel requests from the same account may be throttled temporarily | 429 / 503 | Implement exponential backoff retry logic |
check_upi_order_status endpoint to track order state without consuming new creation quota.Error Handling & Automatic Retry Logic
Retrying transient errors with exponential backoff resolves transaction failures safely.
502 PAYMENT_LINK_FAILED— Upstream gateway timeout; retry after 2–5 seconds503 BUSY_MERCHANT— Merchant slot unavailable; retry after 3–10 seconds500 SERVER_ERROR— Transient server error; retry up to 3 times with backoff- Network timeout / connection reset — Retry with a fresh nonce and timestamp
400 INVALID_PAYLOAD— Fix the request body before retrying401 UNAUTHORIZED— Credentials invalid; check keys & signature logic403 IP_RESTRICTED— Add server IP to whitelist first403 SUBSCRIPTION_REQUIRED— Activate a plan before retrying429 QUOTA_EXCEEDED— Upgrade plan before retrying
Recommended Retry Strategy (Backoff Pattern)
async function callWithRetry(fn, maxRetries = 3) {
const retryableStatuses = [500, 502, 503];
for (let attempt = 1; attempt <= maxRetries; attempt++) {
try {
const res = await fn();
if (!retryableStatuses.includes(res.status)) return res;
if (attempt === maxRetries) return res;
// Exponential backoff: 2s, 4s, 8s
await new Promise(r => setTimeout(r, Math.pow(2, attempt) * 1000));
} catch (err) {
if (attempt === maxRetries) throw err;
await new Promise(r => setTimeout(r, Math.pow(2, attempt) * 1000));
}
}
}
// Always generate a fresh X-Nonce + X-Timestamp on each retry attemptTesting & Production Go-Live
Production-first testing — no sandbox environment needed.
Production Environment — Real-Time Testing
Matrix Pay operates exclusively on a live production environment with no sandbox mode. Testing is done directly against production with real low-cost transactions — no environment switches, no dummy credentials, no mock endpoints required.
What Real Testing Includes
Test with real transactions of ₹1
Create a UPI order for the minimum test amount (₹1). Complete a real payment through the generated link. Verify the status endpoint returns `success`.
Get actual API responses and timing
Measure real end-to-end latency from your server to Matrix Pay and back. Validate that your signature logic, header formatting, and JSON canonicalization are correct using real responses.
Validate complete payment workflow
Create order → receive payment link → complete payment → poll status → receive webhook → update your system. Test the full flow end-to-end with real ₹1 before going live at scale.
No environment switches required
The same API endpoint, same credentials, same response format used for ₹1 testing is identical to production at scale. No staging URLs, no flag toggles, no separate test accounts.
Integration Workflow Checklist
Get your API keys from Developer Hub and configure IP whitelisting
Test HMAC-SHA256 signature generation using the Signature Playground above
Create a UPI order for ₹1 via the Interactive Console or Floating Console
Validate the payment link opens correctly and complete a real test payment
Poll the status endpoint and verify it returns `status: "success"`
Configure your webhook endpoint and verify you receive the `payment.success` event
Review error codes and implement retry logic for 502/503 responses
Go live — scale up to full production volume with the same integration