MPMatrix Pay
REST v2.0
Console is readyLive Azure ProductionKeys Stay Server-Side

Request runs against production Azure account. Your keys stay server-side. Keys supplied from your authenticated session.

Developer Keys & IP Whitelist
UPI Integration• Server-side HMAC-SHA256 authenticated

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 Verified

Follow these 4 sequential steps to activate your reseller account and obtain live credentials.

01

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.

02

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.

03

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.

04

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.

Go to Developer Hub & API KeysKeys are tied to your authenticated session.

Build with an AI assistant

Latest AI Trend
BUILD WITH AN ASSISTANT
132 lines

This 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).

matrixpay-upi-specification.mdMarkdown System Brief
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 Supported

Choose your preferred backend language. All samples use standard HTTP and native cryptographic HMAC-SHA256 libraries.

Node.js / TSnpm / pnpm / yarn

Works seamlessly with Node 18+, Bun, Deno, Next.js, and Express.

npm install axios crypto
Pythonpip

Standard library hmac + hashlib used for canonical signing. Works with FastAPI & Django.

pip install requests
PHPcomposer

Native hash_hmac('sha256') & ksort() used for strict key canonicalization.

composer require guzzlehttp/guzzle
Gogo get

Zero external dependencies — uses crypto/hmac, crypto/sha256, and net/http standard library.

go get github.com/matrixpay/go-gateway
JavaMaven / Gradle

Compatible with Java 11+ HttpClient and Spring Boot Microservices.

implementation 'org.apache.httpcomponents.client5:httpclient5'
C# / .NETNuGet

Built for .NET 6, 7, 8 & ASP.NET Core web APIs using HMACSHA256.

dotnet add package System.Net.Http.Json
Looking for complete request code? View full HMAC signing and order creation snippets in the sections below.Jump to Code Tabs

1. 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.

Requirements: To generate the signature, you need the request payload (either with content or empty) and your correct API key. Note that even if you provide a wrong key, a signature will still generate, but it will be invalid and rejected by our servers.
HMAC-SHA256 Request Signing (7 Languages)
# 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 + Nonce
Request Payload (JSON)Edit JSON to recalculate
X-Timestamp
1790186715
X-Nonce
req_ab12cd34ef56
Canonical String-to-Sign
Calculated X-Signature (HMAC-SHA256)
Computing...

2. 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.

Important: You must calculate the signature using the raw request body (as a string or buffer) before parsing it into JSON.

Webhook Headers

Header NameTypeRequiredDescription
X-Webhook-SignaturestringRequiredThe HMAC SHA256 signature generated using your API key to verify the payload integrity.
X-Webhook-EventstringRequiredThe name of the event that triggered the webhook (e.g., payment.success).
X-Webhook-IdstringRequiredA unique identifier for this specific webhook delivery attempt.
Webhook Receiver Implementation (7 Languages)
# 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 NameTypeRequiredDescription
eventstringRequiredThe type of event that triggered the webhook. You will receive either payment.success or payment.failed.
event_idstringRequiredA 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_idstringRequiredThe unique Matrix Pay internal identifier for the processed UPI order (e.g. MSPGPL260101010203AB04).
utr_numberstringRequiredThe official Bank Unique Transaction Reference (UTR) number confirming the transfer.
amountstringRequiredThe exact transaction amount that was processed, returned to you as a string.
statusstringRequiredThe final state of the transaction. You will receive the updated status, such as Success or Failed.
date_timestringOptionalThe ISO 8601 timestamp representing when the transaction was completed on our system.
commentstringOptionalThe optional comment or note you provided during the initial order creation.
sent_atstringRequiredThe ISO 8601 timestamp recording exactly when our server dispatched this webhook payload to your endpoint.

Example Webhook JSON Payload

JSON
{
  "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.

POSThttps://matrixpay.vercel.app/api/v2/payment_gateway/create_upi_order

Generates 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

HeaderTypeRequiredDescription
X-Client-IdstringRequiredYour unique Client ID provided by Matrix Pay.
X-SignaturestringRequiredThe HMAC-SHA256 signature generated using your API key and the request payload. Required for authentication.
Content-TypestringRequiredMust be set to application/json.

Body Parameters

Global Security Firewall: The entire JSON payload is scanned before processing. Your request will be rejected if it contains brackets [ ] { } ( ), dollar signs $, or angled brackets < > in any of the values.
FieldTypeRequiredRules & Description
amountstringRequiredThe exact transaction amount to be charged. Min 1.00, max of 2 decimal places allowed (e.g. "100.96").
redirect_urlstringRequiredThe destination URL where customer will be redirected automatically after completing payment. Localhost restricted.
customer_namestringRequiredMin 3 chars. Only letters, spaces, and dots allowed (e.g. "John Doe").
customer_emailstringRequiredMust be a valid email address format (e.g. "john@gmail.com").
customer_mobilestringRequiredMust be exactly 10 digits (e.g. "9876543210").
Create UPI Order Request (7 Languages)
# 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

FieldTypeDescription
successbooleanReturns true for success and false for failures.
data.order_idstringUnique Matrix Pay internal identifier generated for this order.
data.statusstringInitial state of order (e.g., Pending).
data.amountstringRequested transaction amount.
data.currencystringCurrency code, fixed to INR.
data.payment_urlstringDestination URL for customer payment completion.

Response Example (201 OK)

JSON
{
  "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
Ready
Request Payload (JSON)
Server Response
Click "Send Request" to test live against Matrix Pay...
Auth headers calculated via client-side HMAC-SHA256.● Matrix Sols v2 Compliant
Ready-to-Use Code Snippet
# 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}"
POSThttps://matrixpay.vercel.app/api/v2/payment_gateway/check_upi_order_status

Retrieve the details of an existing payment link or transaction status programmatically.

Check UPI Status Request (7 Languages)
# 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 EnumDescription
SuccessPayment received from the user and verified against banking UTR.
RefundedPayment was received and subsequently refunded to the user.
PendingAwaiting payment from the user.
QueuePayment is being processed by banking rails.
FailedTransaction attempted but not completed.
CancelledUser exited the session before paying.
ExpiredPayment session timed out before user paid.

Selectable Status Response Examples

JSON
// 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
Ready
Request Payload (JSON)
Server Response
Click "Send Request" to test live against Matrix Pay...
Auth headers calculated via client-side HMAC-SHA256.● Matrix Sols v2 Compliant
Ready-to-Use Code Snippet
# 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 StatusError Code(s)Description & Remediation
400 Bad RequestINVALID_JSON / INVALID_PAYLOAD / INVALID_AMOUNT / INVALID_CUSTOMER_NAMEPayload is invalid JSON, violates firewall (forbidden symbols), or individual fields failed validation. Amount must have max 2 decimal places.
401 UnauthorizedAUTH_HEADERS_MISSING / UNAUTHORIZED / STALE_REQUESTMissing headers (X-Client-Id, X-Signature, X-Timestamp, X-Nonce), invalid credentials, or timestamp outside allowed time window.
403 ForbiddenIP_WHITELIST_EMPTY / IP_RESTRICTED / INVALID_SIGNATURE / SUBSCRIPTION_REQUIREDAccess control violation: IP not whitelisted, invalid HMAC signature, or no active subscription plan on merchant account.
409 ConflictSERVICE_NOT_AUTHORIZEDCredentials are valid but not authorized for the Payment Gateway service.
429 Too Many RequestsQUOTA_EXCEEDED / VOLUME_LIMIT_EXCEEDEDPlan 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 GatewayPAYMENT_LINK_FAILEDUpstream payment gateway (Razorpay, Zoho, HDFC, Paytm) failed to generate payment link. Retry request.
503 Service UnavailableINACTIVE_MERCHANT / BUSY_MERCHANTINACTIVE_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 ErrorSERVER_ERRORUnexpected server-side error. Contact support with your order_id.

Security Best Practices

Mandatory security guidelines every merchant integration must follow.

Never expose API key in frontend JavaScript

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.

Store API keys as environment variables

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.

Use HTTPS for all API requests

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 API keys periodically

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.

IP Whitelisting configuration

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.

CORS & Origin headers

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 TypeDetailsError CodeAction
Monthly Order QuotaMaximum number of orders per calendar month as defined by your plan tierQUOTA_EXCEEDED (429)Upgrade your plan or wait for monthly reset
Monthly Volume LimitMaximum 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 WindowTimestamp in X-Timestamp header must be within ±300 seconds of server timeSTALE_REQUEST (401)Sync your server clock with NTP
Nonce ReuseEach X-Nonce value must be globally unique — replay attacks are blockedUNAUTHORIZED (401)Generate a fresh cryptographic nonce per request
Concurrent RequestsExcessive parallel requests from the same account may be throttled temporarily429 / 503Implement exponential backoff retry logic
Important: Rate limit counters reset at 00:00 UTC on the 1st of each calendar month. Use the 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.

Safe to Retry
  • 502 PAYMENT_LINK_FAILED — Upstream gateway timeout; retry after 2–5 seconds
  • 503 BUSY_MERCHANT — Merchant slot unavailable; retry after 3–10 seconds
  • 500 SERVER_ERROR — Transient server error; retry up to 3 times with backoff
  • Network timeout / connection reset — Retry with a fresh nonce and timestamp
Do Not Retry
  • 400 INVALID_PAYLOAD — Fix the request body before retrying
  • 401 UNAUTHORIZED — Credentials invalid; check keys & signature logic
  • 403 IP_RESTRICTED — Add server IP to whitelist first
  • 403 SUBSCRIPTION_REQUIRED — Activate a plan before retrying
  • 429 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 attempt

Testing & 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

1

Get your API keys from Developer Hub and configure IP whitelisting

2

Test HMAC-SHA256 signature generation using the Signature Playground above

3

Create a UPI order for ₹1 via the Interactive Console or Floating Console

4

Validate the payment link opens correctly and complete a real test payment

5

Poll the status endpoint and verify it returns `status: "success"`

6

Configure your webhook endpoint and verify you receive the `payment.success` event

7

Review error codes and implement retry logic for 502/503 responses

8

Go live — scale up to full production volume with the same integration

No sandbox needed: Matrix Pay's production API is designed for confidence from day one. Every response is real, every latency measurement is accurate, and every workflow you test maps exactly to your production integration — zero surprises at launch.