PayNXT Developer Documentation
Integrate once and accept payments through PayNXT's orchestration layer. This guide covers authentication, request signing, creating a payment session, redirecting to checkout, and going live.
Overview
The integration is server-to-server. Your backend creates a payment session via the PayNXT API, then redirects the customer to the returned checkout_url. PayNXT handles the gateway (Razorpay today) and notifies you of the result.
Base URL: https://paynxt.xyz
Environments (UAT & Live)
PayNXT supports two modes, controlled by the credentials your PayNXT admin configures for your account:
| Environment | Purpose | Gateway mode |
|---|---|---|
| TEST UAT | Integration testing with test gateway keys. No real money moves. | Razorpay TEST |
| LIVE | Production traffic with live gateway keys. | Razorpay LIVE |
The same API endpoints and signing scheme apply to both. Your account starts in UAT; an admin enables LIVE once you're approved and live credentials are connected.
Credentials
Your PayNXT admin issues you two values:
- Merchant ID — your unique, public identifier (e.g.
ACME_CORP_AB12). - Sign Key — a secret used to sign every API request. Shown once at generation, stored encrypted by PayNXT. Treat it like a password; never expose it in client-side code.
If a sign key is leaked, ask your admin to regenerate it — the old key stops working immediately.
Authentication & request signing
Every request to the PayNXT API must be signed. Send these headers:
| Header | Value |
|---|---|
X-Merchant-Id | Your Merchant ID |
X-Timestamp | Current Unix time in milliseconds (must be within 5 minutes of server time) |
X-Signature | HMAC-SHA256 hex of <timestamp>.<raw JSON body>, keyed with your Sign Key |
The signature is computed over the exact request body bytes you send. Build the JSON once and sign that exact string.
Node.js example
import crypto from "node:crypto";
const MERCHANT_ID = "ACME_CORP_AB12";
const SIGN_KEY = process.env.PAYNXT_SIGN_KEY; // keep secret
const body = JSON.stringify({
merchant_order_id: "ORD-1001",
amount: 249900, // smallest currency unit (paise)
currency: "INR",
customer: { name: "Priya", email: "priya@store.in", phone: "9000000000" },
return_url: "https://yourstore.in/payment/return"
});
const timestamp = Date.now().toString();
const signature = crypto
.createHmac("sha256", SIGN_KEY)
.update(timestamp + "." + body)
.digest("hex");
const res = await fetch("https://paynxt.xyz/v1/payment-sessions", {
method: "POST",
headers: {
"Content-Type": "application/json",
"X-Merchant-Id": MERCHANT_ID,
"X-Timestamp": timestamp,
"X-Signature": signature
},
body
});
const data = await res.json();
// redirect the customer to data.checkout_url
cURL example
TS=$(date +%s000)
BODY='{"merchant_order_id":"ORD-1001","amount":249900,"currency":"INR","customer":{"name":"Priya","email":"priya@store.in","phone":"9000000000"},"return_url":"https://yourstore.in/return"}'
SIG=$(printf '%s' "$TS.$BODY" | openssl dgst -sha256 -hmac "$PAYNXT_SIGN_KEY" | awk '{print $2}')
curl -X POST https://paynxt.xyz/v1/payment-sessions \
-H "Content-Type: application/json" \
-H "X-Merchant-Id: ACME_CORP_AB12" \
-H "X-Timestamp: $TS" \
-H "X-Signature: $SIG" \
-d "$BODY"
Create a payment session
POST /v1/payment-sessions (signed). Request body:
| Field | Type | Notes |
|---|---|---|
merchant_order_id | string | Your unique order reference |
amount | integer | Smallest currency unit (e.g. paise) |
currency | string | Defaults to INR |
customer.name | string | Customer name |
customer.email | string | Customer email |
customer.phone | string | Customer phone |
description | string | Optional |
return_url | string (URL) | Where the customer returns after payment |
Response 201:
{
"payment_session_id": "ps_xxxxxxxxxxxxxxxx",
"checkout_url": "https://paynxt.xyz/checkout/ps_xxxxxxxxxxxxxxxx",
"status": "created"
}
Checkout & redirect
Redirect the customer's browser to checkout_url. PayNXT renders the hosted checkout and processes payment through the configured gateway. After payment the customer is returned to your return_url.
Callbacks & webhooks
After payment, the customer is redirected to your return_url. For reliable server-side confirmation, set your Merchant webhook URL (your PayNXT admin sets this) — PayNXT will POST a signed event to it when a payment is captured.
Payload (POST, JSON)
{
"event": "payment.captured",
"payment_session_id": "ps_xxxxxxxxxxxxxxxx",
"merchant_order_id": "ORD-1001",
"amount": 100, // smallest unit (paise)
"currency": "INR",
"status": "captured",
"gateway_payment_id": "pay_xxxxxxxxxxxx",
"timestamp": "2026-06-27T08:00:00.000Z"
}
Verifying the signature
Header X-PayNXT-Signature = HMAC_SHA256(your_sign_key, raw_request_body) as hex. Recompute it over the exact body received and compare before trusting the event.
// Node example (Express, raw body)
const expected = crypto.createHmac("sha256", SIGN_KEY).update(rawBody).digest("hex");
if (expected !== req.header("X-PayNXT-Signature")) return res.status(401).end();
// mark merchant_order_id as paid
Respond 2xx to acknowledge. Treat the webhook as the source of truth for final status.
Error reference
| HTTP | Meaning |
|---|---|
400 | Invalid request body (see details) |
401 | Missing/invalid signature, unknown merchant, or stale timestamp |
403 | Merchant not approved for transactions |
404 | Resource not found |
Go-live checklist
- Integration tested end-to-end in TEST (UAT).
- Your PayNXT account is approved by an admin.
- LIVE Razorpay credentials connected to your account.
- Sign key stored securely on your server (never in client code).
- Webhook endpoint live and signature-verified.
Questions? hello@paynxt.xyz