Production hosts
API base URL: https://nineteenapis.online — use this for all /api/, /pay/, and /webhooks/ calls.
Documentation only: https://public.nineteenapis.online — this host serves these HTML pages and Swagger; it does not proxy API traffic.
API V2 — HMAC integration
Paths include /api/v2/. You must sign the raw JSON body and whitelist caller IPs.
V2 — HMAC authentication
Required headers (exactly these four — no others are recognized)
X-API-KEYX-TimestampX-NonceX-Signature
Common mistakes
- Do not send
X-NP-KEY— it is not recognized. - Do not send
X-Method— it is not recognized. - Header names are case-insensitive in HTTP; the canonical names above match our examples.
- Signature =
HMAC-SHA256( pipeSecret, apiKey + timestamp + nonce + JSON.stringify(body) )→ lowercase hex.
Concatenate and sign with your pipe secret (same value as the salt for your API key in the dashboard):
stringToSign = apiKey + timestampSeconds + nonce + JSON.stringify(requestBody)
signature = HMAC_SHA256( secret, stringToSign ) → lowercase hex
X-API-KEY— must match the key you sign with (first segment ofstringToSign).X-Timestamp— Unix time in seconds (string); default allowed skew is ±300s from server time (operations may configure a different window server-side).X-Nonce— unique per request (replay rejected).X-Signature— hex digest; body bytes must be exactly what you put inJSON.stringify.- Optional
X-Idempotency-Keyon mutating routes (collect, refund, transfer, …). - Responses under
/api/v2/*includeX-Server-Time(Unix seconds) on every reply for clock reference. - If the timestamp is outside the allowed window you receive 401 with the usual error envelope; the JSON may also include
serverTime,serverTimeISO, andskewSeconds— see clock skew below.
V2 requires at least one whitelisted IP for the pipe or requests return 403.
Clock skew (HMAC timestamps)
For drifting device clocks, call GET /api/v2/time (no auth), compare to local Unix time, store an offset, and sign with X-Timestamp adjusted by that offset. You can also read X-Server-Time from any prior V2 response.
Example 401 JSON when the timestamp is outside the window (message string unchanged for existing SDKs):
{"success":false,"error":{"message":"Request timestamp outside allowed window","statusCode":401,"serverTime":1715123456,"serverTimeISO":"2024-05-08T06:30:56.000Z","skewSeconds":-362}}
cURL + OpenSSL (bash)
Set NP_KEY and NP_SALT, then build the same JSON string for -d and for signing.
export NP_KEY="your_api_key"
export NP_SALT="your_salt"
BODY='{"payload":{"PAY_ID":"PAY123","ORDER_ID":"ORD456","AMOUNT":"10000","CURRENCY_CODE":"356","TXNTYPE":"SALE","MOP_TYPE":"UPI","PAYMENT_TYPE":"UPI","CUST_EMAIL":"a@b.com","CUST_PHONE":"9999999999"},"environment":"prod"}'
TS=$(date +%s)
NONCE=$(openssl rand -hex 16)
SIG=$(printf '%s' "${NP_KEY}${TS}${NONCE}${BODY}" | openssl dgst -sha256 -hmac "${NP_SALT}" | awk '{print $2}')
curl -sS -X POST 'https://nineteenapis.online/api/v2/payments/collect' \
-H "Content-Type: application/json" \
-H "X-API-KEY: ${NP_KEY}" \
-H "X-Timestamp: ${TS}" \
-H "X-Nonce: ${NONCE}" \
-H "X-Signature: ${SIG}" \
-H "X-Idempotency-Key: my-idempotency-key-1" \
-d "${BODY}"
Node.js
const crypto = require('crypto');
function v2SignAndHeaders(bodyObject, apiKey, salt) {
const bodyStr = JSON.stringify(bodyObject);
const ts = String(Math.floor(Date.now() / 1000));
const nonce = crypto.randomBytes(16).toString('hex');
const payload = apiKey + ts + nonce + bodyStr;
const signature = crypto.createHmac('sha256', salt).update(payload).digest('hex');
return {
headers: {
'Content-Type': 'application/json',
'X-API-KEY': apiKey,
'X-Timestamp': ts,
'X-Nonce': nonce,
'X-Signature': signature,
},
bodyStr,
};
}
// Example (Node 18+; run inside async or use .mjs)
(async () => {
const { headers, bodyStr } = v2SignAndHeaders(
{ payload: { PAY_ID: 'PAY123', ORDER_ID: 'ORD456', AMOUNT: '10000', CURRENCY_CODE: '356',
TXNTYPE: 'SALE', MOP_TYPE: 'UPI', PAYMENT_TYPE: 'UPI', CUST_EMAIL: 'a@b.com', CUST_PHONE: '9999999999' },
environment: 'prod' },
process.env.NP_KEY,
process.env.NP_SALT
);
const res = await fetch('https://nineteenapis.online/api/v2/payments/collect', {
method: 'POST',
headers: { ...headers, 'X-Idempotency-Key': 'unique-key-123' },
body: bodyStr,
});
console.log(await res.json());
})();
Python
Use the same JSON serialization as the wire body (e.g. json.dumps(..., separators=(',', ':'))) so the signature matches.
import hmac, hashlib, json, os, time, secrets, urllib.request
def v2_headers(body: dict, api_key: str, salt: str):
body_str = json.dumps(body, separators=(",", ":"))
ts = str(int(time.time()))
nonce = secrets.token_hex(16)
payload = (api_key + ts + nonce + body_str).encode()
sig = hmac.new(salt.encode(), payload, hashlib.sha256).hexdigest()
return {
"Content-Type": "application/json",
"X-API-KEY": api_key,
"X-Timestamp": ts,
"X-Nonce": nonce,
"X-Signature": sig,
}, body_str
body = {"payload": {"PAY_ID": "PAY123", "ORDER_ID": "ORD456", "AMOUNT": "10000", "CURRENCY_CODE": "356",
"TXNTYPE": "SALE", "MOP_TYPE": "UPI", "PAYMENT_TYPE": "UPI", "CUST_EMAIL": "a@b.com", "CUST_PHONE": "9999999999"},
"environment": "prod"}
h, body_str = v2_headers(body, os.environ["NP_KEY"], os.environ["NP_SALT"])
h["X-Idempotency-Key"] = "unique-key-123"
req = urllib.request.Request(
"https://nineteenapis.online/api/v2/payments/collect",
data=body_str.encode(),
headers=h,
method="POST",
)
with urllib.request.urlopen(req) as r:
print(r.read().decode())
/api/v2/time
Server time (public)
No HMAC or API key. Use for a one-time clock sync before signing V2 requests. The response header X-Server-Time matches serverTime in the body.
cURL
curl -sS 'https://nineteenapis.online/api/v2/time'
Node.js
(async () => {
const res = await fetch('https://nineteenapis.online/api/v2/time');
console.log('X-Server-Time', res.headers.get('x-server-time'));
console.log(await res.json());
})();
Python
import json, urllib.request
req = urllib.request.Request('https://nineteenapis.online/api/v2/time', method='GET')
with urllib.request.urlopen(req) as r:
print('X-Server-Time', r.headers.get('X-Server-Time'))
print(json.loads(r.read().decode()))
Typical success (200)
{"success":true,"serverTime":1715123456,"serverTimeISO":"2024-05-08T06:30:56.000Z"}
V1 collect — gateway payload (API V2 HMAC)
Routes such as /api/v2/payments/collect use a payload object (field names similar to Native V1). This is not Native V2 — Native V2 is only /api/v2/payments/np-native/*. HMAC headers; idempotency on collect/refund where the route supports it.
/api/v2/payments/collect
Collect
X-Idempotency-Key (optional): include on mutating requests for safe retries; recommended for collect/refund/transfer where supported.
curl -sS -X POST 'https://nineteenapis.online/api/v2/payments/collect' \
-H "Content-Type: application/json" \
-H "X-API-KEY: YOUR_NP_KEY" \
-H "X-Timestamp: $(date +%s)" \
-H "X-Nonce: $(openssl rand -hex 16)" \
-H "X-Signature: <compute HMAC — see V2 auth>" \
-H "X-Idempotency-Key: unique-key-123" \
-d '{"payload":{"PAY_ID":"PAY123","ORDER_ID":"ORD456","AMOUNT":"10000","CURRENCY_CODE":"356","TXNTYPE":"SALE","MOP_TYPE":"UPI","PAYMENT_TYPE":"UPI","CUST_EMAIL":"a@b.com","CUST_PHONE":"9999999999","UPI_INTENT":1},"environment":"prod"}'
(async () => {
const crypto = require('crypto');
const url = 'https://nineteenapis.online/api/v2/payments/collect';
const body = {"payload":{"PAY_ID":"PAY123","ORDER_ID":"ORD456","AMOUNT":"10000","CURRENCY_CODE":"356","TXNTYPE":"SALE","MOP_TYPE":"UPI","PAYMENT_TYPE":"UPI","CUST_EMAIL":"a@b.com","CUST_PHONE":"9999999999","UPI_INTENT":1},"environment":"prod"};
const bodyStr = JSON.stringify(body);
const apiKey = process.env.NP_KEY || 'YOUR_NP_KEY';
const salt = process.env.NP_SALT || 'YOUR_NP_SALT';
const ts = String(Math.floor(Date.now()/1000));
const nonce = crypto.randomBytes(16).toString('hex');
const sig = crypto.createHmac('sha256', salt).update(apiKey + ts + nonce + bodyStr).digest('hex');
const headers = { 'Content-Type':'application/json', 'X-API-KEY':apiKey, 'X-Timestamp':ts, 'X-Nonce':nonce, 'X-Signature':sig, 'X-Idempotency-Key':'unique-key-123' };
const res = await fetch(url, { method:'POST', headers, body: bodyStr });
console.log(await res.json());
})();
import json, hmac, hashlib, os, time, secrets, urllib.request
url = "https://nineteenapis.online/api/v2/payments/collect"
body = {"payload":{"PAY_ID":"PAY123","ORDER_ID":"ORD456","AMOUNT":"10000","CURRENCY_CODE":"356","TXNTYPE":"SALE","MOP_TYPE":"UPI","PAYMENT_TYPE":"UPI","CUST_EMAIL":"a@b.com","CUST_PHONE":"9999999999","UPI_INTENT":1},"environment":"prod"}
body_str = json.dumps(body, separators=(",", ":"))
api_key, salt = os.environ["NP_KEY"], os.environ["NP_SALT"].encode()
ts, nonce = str(int(time.time())), secrets.token_hex(16)
sig = hmac.new(salt, (api_key + ts + nonce + body_str).encode(), hashlib.sha256).hexdigest()
h = {"Content-Type":"application/json","X-API-KEY":api_key,"X-Timestamp":ts,"X-Nonce":nonce,"X-Signature":sig,"X-Idempotency-Key":"unique-key-123"}
req = urllib.request.Request(url, data=body_str.encode(), headers=h, method="POST")
with urllib.request.urlopen(req) as r: print(r.read().decode())
Typical success (200)
{"success":true,"transactionId":"...","status":"PENDING","intentUrl":"upi://...","raw":{},"decrypted":{}}
/api/v2/payments/validate-vpa
Validate VPA
curl -sS -X POST 'https://nineteenapis.online/api/v2/payments/validate-vpa' \
-H "Content-Type: application/json" \
-H "X-API-KEY: YOUR_NP_KEY" \
-H "X-Timestamp: $(date +%s)" \
-H "X-Nonce: $(openssl rand -hex 16)" \
-H "X-Signature: <compute HMAC — see V2 auth>" \
-d '{"payload":{"PAY_ID":"PAY123","ORDER_ID":"ORD456","AMOUNT":"100","CURRENCY_CODE":"356","TXNTYPE":"VALIDATE","MOP_TYPE":"UPI","PAYMENT_TYPE":"UPI","CUST_EMAIL":"a@b.com","CUST_PHONE":"9999999999","PAYER_ADDRESS":"test@upi"},"environment":"prod"}'
(async () => {
const crypto = require('crypto');
const url = 'https://nineteenapis.online/api/v2/payments/validate-vpa';
const body = {"payload":{"PAY_ID":"PAY123","ORDER_ID":"ORD456","AMOUNT":"100","CURRENCY_CODE":"356","TXNTYPE":"VALIDATE","MOP_TYPE":"UPI","PAYMENT_TYPE":"UPI","CUST_EMAIL":"a@b.com","CUST_PHONE":"9999999999","PAYER_ADDRESS":"test@upi"},"environment":"prod"};
const bodyStr = JSON.stringify(body);
const apiKey = process.env.NP_KEY || 'YOUR_NP_KEY';
const salt = process.env.NP_SALT || 'YOUR_NP_SALT';
const ts = String(Math.floor(Date.now()/1000));
const nonce = crypto.randomBytes(16).toString('hex');
const sig = crypto.createHmac('sha256', salt).update(apiKey + ts + nonce + bodyStr).digest('hex');
const headers = { 'Content-Type':'application/json', 'X-API-KEY':apiKey, 'X-Timestamp':ts, 'X-Nonce':nonce, 'X-Signature':sig };
const res = await fetch(url, { method:'POST', headers, body: bodyStr });
console.log(await res.json());
})();
import json, hmac, hashlib, os, time, secrets, urllib.request
url = "https://nineteenapis.online/api/v2/payments/validate-vpa"
body = {"payload":{"PAY_ID":"PAY123","ORDER_ID":"ORD456","AMOUNT":"100","CURRENCY_CODE":"356","TXNTYPE":"VALIDATE","MOP_TYPE":"UPI","PAYMENT_TYPE":"UPI","CUST_EMAIL":"a@b.com","CUST_PHONE":"9999999999","PAYER_ADDRESS":"test@upi"},"environment":"prod"}
body_str = json.dumps(body, separators=(",", ":"))
api_key, salt = os.environ["NP_KEY"], os.environ["NP_SALT"].encode()
ts, nonce = str(int(time.time())), secrets.token_hex(16)
sig = hmac.new(salt, (api_key + ts + nonce + body_str).encode(), hashlib.sha256).hexdigest()
h = {"Content-Type":"application/json","X-API-KEY":api_key,"X-Timestamp":ts,"X-Nonce":nonce,"X-Signature":sig}
req = urllib.request.Request(url, data=body_str.encode(), headers=h, method="POST")
with urllib.request.urlopen(req) as r: print(r.read().decode())
Typical success (200)
{"success":true,"raw":{},"decrypted":{}}
/api/v2/payments/status
Status
curl -sS -X POST 'https://nineteenapis.online/api/v2/payments/status' \
-H "Content-Type: application/json" \
-H "X-API-KEY: YOUR_NP_KEY" \
-H "X-Timestamp: $(date +%s)" \
-H "X-Nonce: $(openssl rand -hex 16)" \
-H "X-Signature: <compute HMAC — see V2 auth>" \
-d '{"payload":{"PAY_ID":"PAY123","ORDER_ID":"ORD456","AMOUNT":"10000","CURRENCY_CODE":"356","TXNTYPE":"STATUS","PG_REF_NUM":"PGREF"},"environment":"prod"}'
(async () => {
const crypto = require('crypto');
const url = 'https://nineteenapis.online/api/v2/payments/status';
const body = {"payload":{"PAY_ID":"PAY123","ORDER_ID":"ORD456","AMOUNT":"10000","CURRENCY_CODE":"356","TXNTYPE":"STATUS","PG_REF_NUM":"PGREF"},"environment":"prod"};
const bodyStr = JSON.stringify(body);
const apiKey = process.env.NP_KEY || 'YOUR_NP_KEY';
const salt = process.env.NP_SALT || 'YOUR_NP_SALT';
const ts = String(Math.floor(Date.now()/1000));
const nonce = crypto.randomBytes(16).toString('hex');
const sig = crypto.createHmac('sha256', salt).update(apiKey + ts + nonce + bodyStr).digest('hex');
const headers = { 'Content-Type':'application/json', 'X-API-KEY':apiKey, 'X-Timestamp':ts, 'X-Nonce':nonce, 'X-Signature':sig };
const res = await fetch(url, { method:'POST', headers, body: bodyStr });
console.log(await res.json());
})();
import json, hmac, hashlib, os, time, secrets, urllib.request
url = "https://nineteenapis.online/api/v2/payments/status"
body = {"payload":{"PAY_ID":"PAY123","ORDER_ID":"ORD456","AMOUNT":"10000","CURRENCY_CODE":"356","TXNTYPE":"STATUS","PG_REF_NUM":"PGREF"},"environment":"prod"}
body_str = json.dumps(body, separators=(",", ":"))
api_key, salt = os.environ["NP_KEY"], os.environ["NP_SALT"].encode()
ts, nonce = str(int(time.time())), secrets.token_hex(16)
sig = hmac.new(salt, (api_key + ts + nonce + body_str).encode(), hashlib.sha256).hexdigest()
h = {"Content-Type":"application/json","X-API-KEY":api_key,"X-Timestamp":ts,"X-Nonce":nonce,"X-Signature":sig}
req = urllib.request.Request(url, data=body_str.encode(), headers=h, method="POST")
with urllib.request.urlopen(req) as r: print(r.read().decode())
Typical success (200)
{"success":true,"status":"SUCCESS","raw":{},"decrypted":{}}
/api/v2/payments/refund
Refund
X-Idempotency-Key (optional).
curl -sS -X POST 'https://nineteenapis.online/api/v2/payments/refund' \
-H "Content-Type: application/json" \
-H "X-API-KEY: YOUR_NP_KEY" \
-H "X-Timestamp: $(date +%s)" \
-H "X-Nonce: $(openssl rand -hex 16)" \
-H "X-Signature: <compute HMAC — see V2 auth>" \
-H "X-Idempotency-Key: unique-key-123" \
-d '{"payload":{"PAY_ID":"PAY123","ORDER_ID":"ORD456","AMOUNT":"10000","PG_REF_NUM":"PGREF"},"environment":"prod"}'
(async () => {
const crypto = require('crypto');
const url = 'https://nineteenapis.online/api/v2/payments/refund';
const body = {"payload":{"PAY_ID":"PAY123","ORDER_ID":"ORD456","AMOUNT":"10000","PG_REF_NUM":"PGREF"},"environment":"prod"};
const bodyStr = JSON.stringify(body);
const apiKey = process.env.NP_KEY || 'YOUR_NP_KEY';
const salt = process.env.NP_SALT || 'YOUR_NP_SALT';
const ts = String(Math.floor(Date.now()/1000));
const nonce = crypto.randomBytes(16).toString('hex');
const sig = crypto.createHmac('sha256', salt).update(apiKey + ts + nonce + bodyStr).digest('hex');
const headers = { 'Content-Type':'application/json', 'X-API-KEY':apiKey, 'X-Timestamp':ts, 'X-Nonce':nonce, 'X-Signature':sig, 'X-Idempotency-Key':'unique-key-123' };
const res = await fetch(url, { method:'POST', headers, body: bodyStr });
console.log(await res.json());
})();
import json, hmac, hashlib, os, time, secrets, urllib.request
url = "https://nineteenapis.online/api/v2/payments/refund"
body = {"payload":{"PAY_ID":"PAY123","ORDER_ID":"ORD456","AMOUNT":"10000","PG_REF_NUM":"PGREF"},"environment":"prod"}
body_str = json.dumps(body, separators=(",", ":"))
api_key, salt = os.environ["NP_KEY"], os.environ["NP_SALT"].encode()
ts, nonce = str(int(time.time())), secrets.token_hex(16)
sig = hmac.new(salt, (api_key + ts + nonce + body_str).encode(), hashlib.sha256).hexdigest()
h = {"Content-Type":"application/json","X-API-KEY":api_key,"X-Timestamp":ts,"X-Nonce":nonce,"X-Signature":sig,"X-Idempotency-Key":"unique-key-123"}
req = urllib.request.Request(url, data=body_str.encode(), headers=h, method="POST")
with urllib.request.urlopen(req) as r: print(r.read().decode())
Typical success (200)
{"success":true,"status":"PENDING","raw":{},"decrypted":{}}
/api/v2/payments/static-qr
Static QR
curl -sS -X POST 'https://nineteenapis.online/api/v2/payments/static-qr' \
-H "Content-Type: application/json" \
-H "X-API-KEY: YOUR_NP_KEY" \
-H "X-Timestamp: $(date +%s)" \
-H "X-Nonce: $(openssl rand -hex 16)" \
-H "X-Signature: <compute HMAC — see V2 auth>" \
-d '{"payload":{"PAY_ID":"PAY123","IDENTIFIER":"STORE1","RETURN_URL":"https://merchant.example/cb"},"environment":"prod"}'
(async () => {
const crypto = require('crypto');
const url = 'https://nineteenapis.online/api/v2/payments/static-qr';
const body = {"payload":{"PAY_ID":"PAY123","IDENTIFIER":"STORE1","RETURN_URL":"https://merchant.example/cb"},"environment":"prod"};
const bodyStr = JSON.stringify(body);
const apiKey = process.env.NP_KEY || 'YOUR_NP_KEY';
const salt = process.env.NP_SALT || 'YOUR_NP_SALT';
const ts = String(Math.floor(Date.now()/1000));
const nonce = crypto.randomBytes(16).toString('hex');
const sig = crypto.createHmac('sha256', salt).update(apiKey + ts + nonce + bodyStr).digest('hex');
const headers = { 'Content-Type':'application/json', 'X-API-KEY':apiKey, 'X-Timestamp':ts, 'X-Nonce':nonce, 'X-Signature':sig };
const res = await fetch(url, { method:'POST', headers, body: bodyStr });
console.log(await res.json());
})();
import json, hmac, hashlib, os, time, secrets, urllib.request
url = "https://nineteenapis.online/api/v2/payments/static-qr"
body = {"payload":{"PAY_ID":"PAY123","IDENTIFIER":"STORE1","RETURN_URL":"https://merchant.example/cb"},"environment":"prod"}
body_str = json.dumps(body, separators=(",", ":"))
api_key, salt = os.environ["NP_KEY"], os.environ["NP_SALT"].encode()
ts, nonce = str(int(time.time())), secrets.token_hex(16)
sig = hmac.new(salt, (api_key + ts + nonce + body_str).encode(), hashlib.sha256).hexdigest()
h = {"Content-Type":"application/json","X-API-KEY":api_key,"X-Timestamp":ts,"X-Nonce":nonce,"X-Signature":sig}
req = urllib.request.Request(url, data=body_str.encode(), headers=h, method="POST")
with urllib.request.urlopen(req) as r: print(r.read().decode())
Typical success (200)
{"success":true,"raw":{},"decrypted":{}}
API V2 — Native V2
Paths: /api/v2/payments/np-native/collect and /api/v2/payments/np-native/status only. This is Native V2 — separate from Native V1 and separate from the V1 collect API above. Requires the Native V2 pipe, onboarding, and VPA. Returns checkoutUrl, scanAndPayUrl (minimal QR + download page for gallery scan), share_intentURL (Web Share page: share QR image to UPI apps), upiDeeplink, optional collectIntent, pgUrl (always requested server-side), and collectVpaUrl (reserved; currently null).
/api/v2/payments/np-native/collect
Native V2 — collect (deeplink + checkout)
X-Idempotency-Key (optional): recommended for safe retries.
Request body (JSON)
| Field | Required | Description |
|---|---|---|
amount | Yes | Amount in INR (positive number). |
orderId | Yes | Your order reference (unique per payment attempt). |
customerName | No | Optional display. |
note | No | Shown as UPI note (tn) when supported. |
includePgFallback | No | Deprecated — ignored. Hosted PG URL is always requested server-side; you do not need to send this field. |
Response (200) — key fields
| Field | Description |
|---|---|
checkoutUrl | HTTPS URL of the TSP-hosted checkout page for the payer. Redirect or link the customer here; on mobile they pick a UPI app; on desktop they scan the QR. Same payment and webhooks as other flows. |
upiDeeplink | Standard upi://pay?… string for the primary merchant VPA — for embedding in your own QR. |
collectIntent | Optional upi://pay?… with the same tr/tn as upiDeeplink, but payee is the collect UPI ID from virtual account data (if present). For diagnostics only — your payment handler may still treat app-opened flows as restricted. |
scanAndPayUrl | HTTPS URL of a minimal page that renders the payment QR, auto-downloads a PNG, and includes a save button. Customer opens their UPI app, uses scan from gallery — typically classified as QR mode by the network. |
share_intentURL | HTTPS URL of a page that builds the payment QR in memory and uses the Web Share API to share the QR image to a UPI app (e.g. Google Pay, PhonePe). Useful when deeplink upi:// is blocked by the handler but QR mode is allowed. |
pgUrl | Hosted PG URL from the provider when available (always requested; may be null if generation fails). |
collectVpaUrl | Reserved for UPI Collect (pull to payer VPA). Currently always null — not available from this handler. |
expiresAt | ISO time; checkout session aligns with this window. |
curl -sS -X POST 'https://nineteenapis.online/api/v2/payments/np-native/collect' \
-H "Content-Type: application/json" \
-H "X-API-KEY: YOUR_NP_KEY" \
-H "X-Timestamp: $(date +%s)" \
-H "X-Nonce: $(openssl rand -hex 16)" \
-H "X-Signature: <compute HMAC — see V2 auth>" \
-H "X-Idempotency-Key: unique-key-123" \
-d '{"amount":99.5,"orderId":"order-abc-001","note":"Test","includePgFallback":false}'
(async () => {
const crypto = require('crypto');
const url = 'https://nineteenapis.online/api/v2/payments/np-native/collect';
const body = {"amount":99.5,"orderId":"order-abc-001","note":"Test","includePgFallback":false};
const bodyStr = JSON.stringify(body);
const apiKey = process.env.NP_KEY || 'YOUR_NP_KEY';
const salt = process.env.NP_SALT || 'YOUR_NP_SALT';
const ts = String(Math.floor(Date.now()/1000));
const nonce = crypto.randomBytes(16).toString('hex');
const sig = crypto.createHmac('sha256', salt).update(apiKey + ts + nonce + bodyStr).digest('hex');
const headers = { 'Content-Type':'application/json', 'X-API-KEY':apiKey, 'X-Timestamp':ts, 'X-Nonce':nonce, 'X-Signature':sig, 'X-Idempotency-Key':'unique-key-123' };
const res = await fetch(url, { method:'POST', headers, body: bodyStr });
console.log(await res.json());
})();
import json, hmac, hashlib, os, time, secrets, urllib.request
url = "https://nineteenapis.online/api/v2/payments/np-native/collect"
body = {"amount":99.5,"orderId":"order-abc-001","note":"Test","includePgFallback":False}
body_str = json.dumps(body, separators=(",", ":"))
api_key, salt = os.environ["NP_KEY"], os.environ["NP_SALT"].encode()
ts, nonce = str(int(time.time())), secrets.token_hex(16)
sig = hmac.new(salt, (api_key + ts + nonce + body_str).encode(), hashlib.sha256).hexdigest()
h = {"Content-Type":"application/json","X-API-KEY":api_key,"X-Timestamp":ts,"X-Nonce":nonce,"X-Signature":sig,"X-Idempotency-Key":"unique-key-123"}
req = urllib.request.Request(url, data=body_str.encode(), headers=h, method="POST")
with urllib.request.urlopen(req) as r: print(r.read().decode())
Typical success (200)
{"success":true,"transactionId":"...","orderId":"order-abc-001","upiDeeplink":"upi://pay?...","collectIntent":null,"checkoutUrl":"https://nineteenapis.online/pay/TXN...","scanAndPayUrl":"https://nineteenapis.online/pay/scan/TXN...","share_intentURL":"https://nineteenapis.online/pay/share/TXN...","pgUrl":null,"collectVpaUrl":null,"expiresAt":"..."}
Hosted checkout (public payer pages)
No HMAC — these URLs are for end customers after you receive checkoutUrl from collect. Base host matches your deployment (e.g. production API host).
GET /pay/:transactionId— HTML checkout (UPI app options on mobile, QR on desktop).GET /pay/scan/:transactionId— HTML scan-and-pay (large QR, auto-download PNG, save button; gallery scan flow).GET /pay/share/:transactionId— HTML share-to-UPI (Web Share API: share QR image to UPI app).GET /pay/data/:transactionId— JSON for the page (amount, merchant name,upiDeeplink,scanAndPayUrl,share_intentURL, optionalcollectUpiId/collectIntent, expiry).POST /pay/pg-url/:transactionId— JSON{"success":true,"pgUrl":"…"|null}to fetch hosted PG URL on demand for the checkout page.GET /pay/status/:transactionId— JSON{"success":true,"status":"PENDING"|"SUCCESS"|…}for polling.POST /pay/event— optional anonymous analytics from the checkout page (body:transactionId,eventType, optionaldata). No secrets.
Merchant outbound webhooks after payment success are unchanged — see outbound webhooks (HMAC X-TSP-Signature).
/api/v2/payments/np-native/status
Native V2 — status
Look up one payment by merchant orderId and/or TSP transactionId, or batch up to 50 combined references via orderIds / transactionIds. Do not mix single fields (orderId/transactionId) with batch arrays in the same request.
| Field | Required | Notes |
|---|---|---|
| orderId | optional | Single lookup only (with single mode). |
| transactionId | optional | Single lookup only (with single mode). |
| orderIds | optional | Batch: array of merchant order references; trimmed, de-duplicated; max 50 combined with transactionIds. |
| transactionIds | optional | Batch: array of TSP transaction IDs; same limits as orderIds. |
Single ID — examples
curl -sS -X POST 'https://nineteenapis.online/api/v2/payments/np-native/status' \
-H "Content-Type: application/json" \
-H "X-API-KEY: YOUR_NP_KEY" \
-H "X-Timestamp: $(date +%s)" \
-H "X-Nonce: $(openssl rand -hex 16)" \
-H "X-Signature: <compute HMAC — see V2 auth>" \
-d '{"orderId":"order-abc-001"}'
(async () => {
const crypto = require('crypto');
const url = 'https://nineteenapis.online/api/v2/payments/np-native/status';
const body = {"orderId":"order-abc-001"};
const bodyStr = JSON.stringify(body);
const apiKey = process.env.NP_KEY || 'YOUR_NP_KEY';
const salt = process.env.NP_SALT || 'YOUR_NP_SALT';
const ts = String(Math.floor(Date.now()/1000));
const nonce = crypto.randomBytes(16).toString('hex');
const sig = crypto.createHmac('sha256', salt).update(apiKey + ts + nonce + bodyStr).digest('hex');
const headers = { 'Content-Type':'application/json', 'X-API-KEY':apiKey, 'X-Timestamp':ts, 'X-Nonce':nonce, 'X-Signature':sig };
const res = await fetch(url, { method:'POST', headers, body: bodyStr });
console.log(await res.json());
})();
import json, hmac, hashlib, os, time, secrets, urllib.request
url = "https://nineteenapis.online/api/v2/payments/np-native/status"
body = {"orderId":"order-abc-001"}
body_str = json.dumps(body, separators=(",", ":"))
api_key, salt = os.environ["NP_KEY"], os.environ["NP_SALT"].encode()
ts, nonce = str(int(time.time())), secrets.token_hex(16)
sig = hmac.new(salt, (api_key + ts + nonce + body_str).encode(), hashlib.sha256).hexdigest()
h = {"Content-Type":"application/json","X-API-KEY":api_key,"X-Timestamp":ts,"X-Nonce":nonce,"X-Signature":sig}
req = urllib.request.Request(url, data=body_str.encode(), headers=h, method="POST")
with urllib.request.urlopen(req) as r: print(r.read().decode())
Typical success (200) — single
{"success":true,"transactionId":"...","orderId":"...","status":"PENDING","amount":"99.50","bankReference":null,"paymentMethod":null,"createdAt":"...","updatedAt":"..."}
Batch IDs — examples (same HMAC rules; body uses arrays)
curl -sS -X POST 'https://nineteenapis.online/api/v2/payments/np-native/status' \
-H "Content-Type: application/json" \
-H "X-API-KEY: YOUR_NP_KEY" \
-H "X-Timestamp: $(date +%s)" \
-H "X-Nonce: $(openssl rand -hex 16)" \
-H "X-Signature: <compute HMAC — see V2 auth>" \
-d '{"orderIds":["order-abc-001","order-abc-002","missing-order"]}'
(async () => {
const crypto = require('crypto');
const url = 'https://nineteenapis.online/api/v2/payments/np-native/status';
const body = { orderIds: ['order-abc-001', 'order-abc-002', 'missing-order'] };
const bodyStr = JSON.stringify(body);
const apiKey = process.env.NP_KEY || 'YOUR_NP_KEY';
const salt = process.env.NP_SALT || 'YOUR_NP_SALT';
const ts = String(Math.floor(Date.now() / 1000));
const nonce = crypto.randomBytes(16).toString('hex');
const sig = crypto.createHmac('sha256', salt).update(apiKey + ts + nonce + bodyStr).digest('hex');
const headers = { 'Content-Type': 'application/json', 'X-API-KEY': apiKey, 'X-Timestamp': ts, 'X-Nonce': nonce, 'X-Signature': sig };
const res = await fetch(url, { method: 'POST', headers, body: bodyStr });
console.log(await res.json());
})();
import json, hmac, hashlib, os, time, secrets, urllib.request
url = "https://nineteenapis.online/api/v2/payments/np-native/status"
body = {"orderIds": ["order-abc-001", "order-abc-002", "missing-order"]}
body_str = json.dumps(body, separators=(",", ":"))
api_key, salt = os.environ["NP_KEY"], os.environ["NP_SALT"].encode()
ts, nonce = str(int(time.time())), secrets.token_hex(16)
sig = hmac.new(salt, (api_key + ts + nonce + body_str).encode(), hashlib.sha256).hexdigest()
h = {"Content-Type": "application/json", "X-API-KEY": api_key, "X-Timestamp": ts, "X-Nonce": nonce, "X-Signature": sig}
req = urllib.request.Request(url, data=body_str.encode(), headers=h, method="POST")
with urllib.request.urlopen(req) as r:
print(r.read().decode())
Typical success (200) — batch
{"success":true,"data":[{"requestedId":"order-abc-001","kind":"orderId","status":"SUCCESS","transactionId":"TXN...","orderId":"order-abc-001","amount":"99.50","bankReference":null,"paymentMethod":null,"createdAt":"...","updatedAt":"..."},{"requestedId":"order-abc-002","kind":"orderId","status":"PENDING","transactionId":"TXN...","orderId":"order-abc-002","amount":"50.00","bankReference":null,"paymentMethod":null,"createdAt":"...","updatedAt":"..."},{"requestedId":"missing-order","kind":"orderId","status":"NOT_FOUND"}]}
V2 — JPSL
/api/v2/payments/jpsl/initiate-sale
Initiate sale
curl -sS -X POST 'https://nineteenapis.online/api/v2/payments/jpsl/initiate-sale' \
-H "Content-Type: application/json" \
-H "X-API-KEY: YOUR_NP_KEY" \
-H "X-Timestamp: $(date +%s)" \
-H "X-Nonce: $(openssl rand -hex 16)" \
-H "X-Signature: <compute HMAC — see V2 auth>" \
-d '{"amount":"100.00","returnURL":"https://merchant.example/jpsl-return","environment":"prod"}'
(async () => {
const crypto = require('crypto');
const url = 'https://nineteenapis.online/api/v2/payments/jpsl/initiate-sale';
const body = {"amount":"100.00","returnURL":"https://merchant.example/jpsl-return","environment":"prod"};
const bodyStr = JSON.stringify(body);
const apiKey = process.env.NP_KEY || 'YOUR_NP_KEY';
const salt = process.env.NP_SALT || 'YOUR_NP_SALT';
const ts = String(Math.floor(Date.now()/1000));
const nonce = crypto.randomBytes(16).toString('hex');
const sig = crypto.createHmac('sha256', salt).update(apiKey + ts + nonce + bodyStr).digest('hex');
const headers = { 'Content-Type':'application/json', 'X-API-KEY':apiKey, 'X-Timestamp':ts, 'X-Nonce':nonce, 'X-Signature':sig };
const res = await fetch(url, { method:'POST', headers, body: bodyStr });
console.log(await res.json());
})();
import json, hmac, hashlib, os, time, secrets, urllib.request
url = "https://nineteenapis.online/api/v2/payments/jpsl/initiate-sale"
body = {"amount":"100.00","returnURL":"https://merchant.example/jpsl-return","environment":"prod"}
body_str = json.dumps(body, separators=(",", ":"))
api_key, salt = os.environ["NP_KEY"], os.environ["NP_SALT"].encode()
ts, nonce = str(int(time.time())), secrets.token_hex(16)
sig = hmac.new(salt, (api_key + ts + nonce + body_str).encode(), hashlib.sha256).hexdigest()
h = {"Content-Type":"application/json","X-API-KEY":api_key,"X-Timestamp":ts,"X-Nonce":nonce,"X-Signature":sig}
req = urllib.request.Request(url, data=body_str.encode(), headers=h, method="POST")
with urllib.request.urlopen(req) as r: print(r.read().decode())
Typical success (200)
{"success":true,"transactionId":"...","redirectURI":"https://...","tranCtx":"...","raw":{}}
/api/v2/payments/jpsl/generate-qr
Generate QR
curl -sS -X POST 'https://nineteenapis.online/api/v2/payments/jpsl/generate-qr' \
-H "Content-Type: application/json" \
-H "X-API-KEY: YOUR_NP_KEY" \
-H "X-Timestamp: $(date +%s)" \
-H "X-Nonce: $(openssl rand -hex 16)" \
-H "X-Signature: <compute HMAC — see V2 auth>" \
-d '{"amount":"500","environment":"prod"}'
(async () => {
const crypto = require('crypto');
const url = 'https://nineteenapis.online/api/v2/payments/jpsl/generate-qr';
const body = {"amount":"500","environment":"prod"};
const bodyStr = JSON.stringify(body);
const apiKey = process.env.NP_KEY || 'YOUR_NP_KEY';
const salt = process.env.NP_SALT || 'YOUR_NP_SALT';
const ts = String(Math.floor(Date.now()/1000));
const nonce = crypto.randomBytes(16).toString('hex');
const sig = crypto.createHmac('sha256', salt).update(apiKey + ts + nonce + bodyStr).digest('hex');
const headers = { 'Content-Type':'application/json', 'X-API-KEY':apiKey, 'X-Timestamp':ts, 'X-Nonce':nonce, 'X-Signature':sig };
const res = await fetch(url, { method:'POST', headers, body: bodyStr });
console.log(await res.json());
})();
import json, hmac, hashlib, os, time, secrets, urllib.request
url = "https://nineteenapis.online/api/v2/payments/jpsl/generate-qr"
body = {"amount":"500","environment":"prod"}
body_str = json.dumps(body, separators=(",", ":"))
api_key, salt = os.environ["NP_KEY"], os.environ["NP_SALT"].encode()
ts, nonce = str(int(time.time())), secrets.token_hex(16)
sig = hmac.new(salt, (api_key + ts + nonce + body_str).encode(), hashlib.sha256).hexdigest()
h = {"Content-Type":"application/json","X-API-KEY":api_key,"X-Timestamp":ts,"X-Nonce":nonce,"X-Signature":sig}
req = urllib.request.Request(url, data=body_str.encode(), headers=h, method="POST")
with urllib.request.urlopen(req) as r: print(r.read().decode())
Typical success (200)
{"success":true,"qrString":"upi://...","raw":{}}
/api/v2/payments/jpsl/status
Status
curl -sS -X POST 'https://nineteenapis.online/api/v2/payments/jpsl/status' \
-H "Content-Type: application/json" \
-H "X-API-KEY: YOUR_NP_KEY" \
-H "X-Timestamp: $(date +%s)" \
-H "X-Nonce: $(openssl rand -hex 16)" \
-H "X-Signature: <compute HMAC — see V2 auth>" \
-d '{"merchantTxnNo":"MTX1","originalTxnNo":"OTX1","amount":"100.00","environment":"prod"}'
(async () => {
const crypto = require('crypto');
const url = 'https://nineteenapis.online/api/v2/payments/jpsl/status';
const body = {"merchantTxnNo":"MTX1","originalTxnNo":"OTX1","amount":"100.00","environment":"prod"};
const bodyStr = JSON.stringify(body);
const apiKey = process.env.NP_KEY || 'YOUR_NP_KEY';
const salt = process.env.NP_SALT || 'YOUR_NP_SALT';
const ts = String(Math.floor(Date.now()/1000));
const nonce = crypto.randomBytes(16).toString('hex');
const sig = crypto.createHmac('sha256', salt).update(apiKey + ts + nonce + bodyStr).digest('hex');
const headers = { 'Content-Type':'application/json', 'X-API-KEY':apiKey, 'X-Timestamp':ts, 'X-Nonce':nonce, 'X-Signature':sig };
const res = await fetch(url, { method:'POST', headers, body: bodyStr });
console.log(await res.json());
})();
import json, hmac, hashlib, os, time, secrets, urllib.request
url = "https://nineteenapis.online/api/v2/payments/jpsl/status"
body = {"merchantTxnNo":"MTX1","originalTxnNo":"OTX1","amount":"100.00","environment":"prod"}
body_str = json.dumps(body, separators=(",", ":"))
api_key, salt = os.environ["NP_KEY"], os.environ["NP_SALT"].encode()
ts, nonce = str(int(time.time())), secrets.token_hex(16)
sig = hmac.new(salt, (api_key + ts + nonce + body_str).encode(), hashlib.sha256).hexdigest()
h = {"Content-Type":"application/json","X-API-KEY":api_key,"X-Timestamp":ts,"X-Nonce":nonce,"X-Signature":sig}
req = urllib.request.Request(url, data=body_str.encode(), headers=h, method="POST")
with urllib.request.urlopen(req) as r: print(r.read().decode())
Typical success (200)
{"success":true,"status":"SUCCESS","raw":{}}
/api/v2/payments/jpsl/refund
Refund
X-Idempotency-Key (optional).
curl -sS -X POST 'https://nineteenapis.online/api/v2/payments/jpsl/refund' \
-H "Content-Type: application/json" \
-H "X-API-KEY: YOUR_NP_KEY" \
-H "X-Timestamp: $(date +%s)" \
-H "X-Nonce: $(openssl rand -hex 16)" \
-H "X-Signature: <compute HMAC — see V2 auth>" \
-H "X-Idempotency-Key: unique-key-123" \
-d '{"merchantTxnNo":"MTXRF1","originalTxnNo":"OTX1","amount":"100.00","environment":"prod"}'
(async () => {
const crypto = require('crypto');
const url = 'https://nineteenapis.online/api/v2/payments/jpsl/refund';
const body = {"merchantTxnNo":"MTXRF1","originalTxnNo":"OTX1","amount":"100.00","environment":"prod"};
const bodyStr = JSON.stringify(body);
const apiKey = process.env.NP_KEY || 'YOUR_NP_KEY';
const salt = process.env.NP_SALT || 'YOUR_NP_SALT';
const ts = String(Math.floor(Date.now()/1000));
const nonce = crypto.randomBytes(16).toString('hex');
const sig = crypto.createHmac('sha256', salt).update(apiKey + ts + nonce + bodyStr).digest('hex');
const headers = { 'Content-Type':'application/json', 'X-API-KEY':apiKey, 'X-Timestamp':ts, 'X-Nonce':nonce, 'X-Signature':sig, 'X-Idempotency-Key':'unique-key-123' };
const res = await fetch(url, { method:'POST', headers, body: bodyStr });
console.log(await res.json());
})();
import json, hmac, hashlib, os, time, secrets, urllib.request
url = "https://nineteenapis.online/api/v2/payments/jpsl/refund"
body = {"merchantTxnNo":"MTXRF1","originalTxnNo":"OTX1","amount":"100.00","environment":"prod"}
body_str = json.dumps(body, separators=(",", ":"))
api_key, salt = os.environ["NP_KEY"], os.environ["NP_SALT"].encode()
ts, nonce = str(int(time.time())), secrets.token_hex(16)
sig = hmac.new(salt, (api_key + ts + nonce + body_str).encode(), hashlib.sha256).hexdigest()
h = {"Content-Type":"application/json","X-API-KEY":api_key,"X-Timestamp":ts,"X-Nonce":nonce,"X-Signature":sig,"X-Idempotency-Key":"unique-key-123"}
req = urllib.request.Request(url, data=body_str.encode(), headers=h, method="POST")
with urllib.request.urlopen(req) as r: print(r.read().decode())
Typical success (200)
{"success":true,"status":"PENDING","raw":{}}
V2 — Paytm Escrow
/api/v2/payments/paytm/collect
Collect
curl -sS -X POST 'https://nineteenapis.online/api/v2/payments/paytm/collect' \
-H "Content-Type: application/json" \
-H "X-API-KEY: YOUR_NP_KEY" \
-H "X-Timestamp: $(date +%s)" \
-H "X-Nonce: $(openssl rand -hex 16)" \
-H "X-Signature: <compute HMAC — see V2 auth>" \
-H "X-Idempotency-Key: unique-key-123" \
-d '{"amount":100.5,"transaction_note":"Order 1"}'
(async () => {
const crypto = require('crypto');
const url = 'https://nineteenapis.online/api/v2/payments/paytm/collect';
const body = {"amount":100.5,"transaction_note":"Order 1"};
const bodyStr = JSON.stringify(body);
const apiKey = process.env.NP_KEY || 'YOUR_NP_KEY';
const salt = process.env.NP_SALT || 'YOUR_NP_SALT';
const ts = String(Math.floor(Date.now()/1000));
const nonce = crypto.randomBytes(16).toString('hex');
const sig = crypto.createHmac('sha256', salt).update(apiKey + ts + nonce + bodyStr).digest('hex');
const headers = { 'Content-Type':'application/json', 'X-API-KEY':apiKey, 'X-Timestamp':ts, 'X-Nonce':nonce, 'X-Signature':sig, 'X-Idempotency-Key':'unique-key-123' };
const res = await fetch(url, { method:'POST', headers, body: bodyStr });
console.log(await res.json());
})();
import json, hmac, hashlib, os, time, secrets, urllib.request
url = "https://nineteenapis.online/api/v2/payments/paytm/collect"
body = {"amount":100.5,"transaction_note":"Order 1"}
body_str = json.dumps(body, separators=(",", ":"))
api_key, salt = os.environ["NP_KEY"], os.environ["NP_SALT"].encode()
ts, nonce = str(int(time.time())), secrets.token_hex(16)
sig = hmac.new(salt, (api_key + ts + nonce + body_str).encode(), hashlib.sha256).hexdigest()
h = {"Content-Type":"application/json","X-API-KEY":api_key,"X-Timestamp":ts,"X-Nonce":nonce,"X-Signature":sig,"X-Idempotency-Key":"unique-key-123"}
req = urllib.request.Request(url, data=body_str.encode(), headers=h, method="POST")
with urllib.request.urlopen(req) as r: print(r.read().decode())
Typical success (200)
{"success":true,"collectRef":"...","link":"https://...","raw":{}}
/api/v2/payments/paytm/status
Status
Batch status from stored transaction rows. Returns one item in data for every collect_ref in the request, in request order. Refs that don't match a stored transaction come back with status: "NOT_FOUND" and paid: false.
Response item shape (each entry in data[])
| Field | Type | Notes |
|---|---|---|
collect_ref | string | snake_case. Echoes the requested ref. |
transactionId | string | Internal NineteenPay txn id. Empty when NOT_FOUND. |
status | string | One of SUCCESS, PENDING, FAILED, NOT_FOUND. |
paid | boolean | Pre-computed: status === 'SUCCESS'. Read this directly. |
amount | number | In INR. 0 when NOT_FOUND. |
bankref | string|null | UTR once paid; null otherwise. |
curl -sS -X POST 'https://nineteenapis.online/api/v2/payments/paytm/status' \
-H "Content-Type: application/json" \
-H "X-API-KEY: YOUR_NP_KEY" \
-H "X-Timestamp: $(date +%s)" \
-H "X-Nonce: $(openssl rand -hex 16)" \
-H "X-Signature: <compute HMAC — see V2 auth>" \
-d '{"collect_ref_arr":["CRN123"]}'
(async () => {
const crypto = require('crypto');
const url = 'https://nineteenapis.online/api/v2/payments/paytm/status';
const body = {"collect_ref_arr":["CRN123"]};
const bodyStr = JSON.stringify(body);
const apiKey = process.env.NP_KEY || 'YOUR_NP_KEY';
const salt = process.env.NP_SALT || 'YOUR_NP_SALT';
const ts = String(Math.floor(Date.now()/1000));
const nonce = crypto.randomBytes(16).toString('hex');
const sig = crypto.createHmac('sha256', salt).update(apiKey + ts + nonce + bodyStr).digest('hex');
const headers = { 'Content-Type':'application/json', 'X-API-KEY':apiKey, 'X-Timestamp':ts, 'X-Nonce':nonce, 'X-Signature':sig };
const res = await fetch(url, { method:'POST', headers, body: bodyStr });
console.log(await res.json());
})();
import json, hmac, hashlib, os, time, secrets, urllib.request
url = "https://nineteenapis.online/api/v2/payments/paytm/status"
body = {"collect_ref_arr":["CRN123"]}
body_str = json.dumps(body, separators=(",", ":"))
api_key, salt = os.environ["NP_KEY"], os.environ["NP_SALT"].encode()
ts, nonce = str(int(time.time())), secrets.token_hex(16)
sig = hmac.new(salt, (api_key + ts + nonce + body_str).encode(), hashlib.sha256).hexdigest()
h = {"Content-Type":"application/json","X-API-KEY":api_key,"X-Timestamp":ts,"X-Nonce":nonce,"X-Signature":sig}
req = urllib.request.Request(url, data=body_str.encode(), headers=h, method="POST")
with urllib.request.urlopen(req) as r: print(r.read().decode())
Typical success (200)
{
"success": true,
"data": [
{
"collect_ref": "20260430174031TESTREF001",
"transactionId": "TXN9F4A2B...",
"status": "SUCCESS",
"paid": true,
"amount": 115,
"bankref": "ICIC1234567890"
}
],
"raw": { "data": [ /* same array */ ] }
}
Integrator note: read data[i].paid directly. Refs you sent that don't match any stored transaction will come back with status: "NOT_FOUND" rather than being dropped silently.
/api/v2/payments/paytm/link-details
Link details
curl -sS -X POST 'https://nineteenapis.online/api/v2/payments/paytm/link-details' \
-H "Content-Type: application/json" \
-H "X-API-KEY: YOUR_NP_KEY" \
-H "X-Timestamp: $(date +%s)" \
-H "X-Nonce: $(openssl rand -hex 16)" \
-H "X-Signature: <compute HMAC — see V2 auth>" \
-d '{"crn_arr":["CRN123"]}'
(async () => {
const crypto = require('crypto');
const url = 'https://nineteenapis.online/api/v2/payments/paytm/link-details';
const body = {"crn_arr":["CRN123"]};
const bodyStr = JSON.stringify(body);
const apiKey = process.env.NP_KEY || 'YOUR_NP_KEY';
const salt = process.env.NP_SALT || 'YOUR_NP_SALT';
const ts = String(Math.floor(Date.now()/1000));
const nonce = crypto.randomBytes(16).toString('hex');
const sig = crypto.createHmac('sha256', salt).update(apiKey + ts + nonce + bodyStr).digest('hex');
const headers = { 'Content-Type':'application/json', 'X-API-KEY':apiKey, 'X-Timestamp':ts, 'X-Nonce':nonce, 'X-Signature':sig };
const res = await fetch(url, { method:'POST', headers, body: bodyStr });
console.log(await res.json());
})();
import json, hmac, hashlib, os, time, secrets, urllib.request
url = "https://nineteenapis.online/api/v2/payments/paytm/link-details"
body = {"crn_arr":["CRN123"]}
body_str = json.dumps(body, separators=(",", ":"))
api_key, salt = os.environ["NP_KEY"], os.environ["NP_SALT"].encode()
ts, nonce = str(int(time.time())), secrets.token_hex(16)
sig = hmac.new(salt, (api_key + ts + nonce + body_str).encode(), hashlib.sha256).hexdigest()
h = {"Content-Type":"application/json","X-API-KEY":api_key,"X-Timestamp":ts,"X-Nonce":nonce,"X-Signature":sig}
req = urllib.request.Request(url, data=body_str.encode(), headers=h, method="POST")
with urllib.request.urlopen(req) as r: print(r.read().decode())
Typical success (200)
{"success":true,"details":[...]}
V2 — NSDL UPI Pay-In
UPI intent-link collect via the same escrow-style flow as the row above. Requires HMAC V2 auth, IP whitelist, and your account enabled for pipe NSDL_PAYIN. Response may include gateway fields under raw.
/api/v2/payments/nsdl/collect
Collect
Create a collect / intent link for the configured payee.
| Header | Required | Description |
|---|---|---|
X-API-KEY | Yes | Your NineteenPay API key for this pipe |
X-Timestamp | Yes | Unix epoch seconds (string) |
X-Nonce | Yes | Unique nonce per request |
X-Signature | Yes | HMAC-SHA256 per V2 auth |
| JSON body field | Required | Type / notes |
|---|---|---|
amount | Yes | number |
collect_ref | No | string; alphanumeric only (non-alphanumeric characters are stripped server-side). Max 30 chars after sanitization. |
user_ref | No | string; min 5 chars, max 50 chars. Defaults to Customer if omitted or shorter than 5. |
display_name | No | string |
transaction_note | No | string |
curl -sS -X POST 'https://nineteenapis.online/api/v2/payments/nsdl/collect' \
-H "Content-Type: application/json" \
-H "X-API-KEY: YOUR_NP_KEY" \
-H "X-Timestamp: $(date +%s)" \
-H "X-Nonce: $(openssl rand -hex 16)" \
-H "X-Signature: <compute HMAC — see V2 auth>" \
-d '{"amount":100.5,"transaction_note":"Order 1"}'
(async () => {
const crypto = require('crypto');
const url = 'https://nineteenapis.online/api/v2/payments/nsdl/collect';
const body = {"amount":100.5,"transaction_note":"Order 1"};
const bodyStr = JSON.stringify(body);
const apiKey = process.env.NP_KEY || 'YOUR_NP_KEY';
const salt = process.env.NP_SALT || 'YOUR_NP_SALT';
const ts = String(Math.floor(Date.now()/1000));
const nonce = crypto.randomBytes(16).toString('hex');
const sig = crypto.createHmac('sha256', salt).update(apiKey + ts + nonce + bodyStr).digest('hex');
const headers = { 'Content-Type':'application/json', 'X-API-KEY':apiKey, 'X-Timestamp':ts, 'X-Nonce':nonce, 'X-Signature':sig };
const res = await fetch(url, { method:'POST', headers, body: bodyStr });
console.log(await res.json());
})();
import json, hmac, hashlib, os, time, secrets, urllib.request
url = "https://nineteenapis.online/api/v2/payments/nsdl/collect"
body = {"amount":100.5,"transaction_note":"Order 1"}
body_str = json.dumps(body, separators=(",", ":"))
api_key, salt = os.environ["NP_KEY"], os.environ["NP_SALT"].encode()
ts, nonce = str(int(time.time())), secrets.token_hex(16)
sig = hmac.new(salt, (api_key + ts + nonce + body_str).encode(), hashlib.sha256).hexdigest()
h = {"Content-Type":"application/json","X-API-KEY":api_key,"X-Timestamp":ts,"X-Nonce":nonce,"X-Signature":sig}
req = urllib.request.Request(url, data=body_str.encode(), headers=h, method="POST")
with urllib.request.urlopen(req) as r: print(r.read().decode())
Typical success (200)
{"success":true,"transactionId":"...","collectRef":"...","status":"...","crn":null,"link":"https://...","feeAccountBalance":null,"raw":{}}
/api/v2/payments/nsdl/status
Status (database)
Batch status from stored transaction rows (same headers as collect). Returns one item in data for every collect_ref in the request, in request order.
| JSON body field | Required | Type / notes |
|---|---|---|
collect_ref_arr | Yes | array of strings (collect references), at least one entry, each non-empty |
Response item shape (each entry in data[])
| Field | Type | Notes |
|---|---|---|
collect_ref | string | snake_case. Echoes the requested ref. |
transactionId | string | Internal NineteenPay txn id. Empty string when status is NOT_FOUND. |
status | string | One of SUCCESS, PENDING, FAILED, NOT_FOUND. |
paid | boolean | Pre-computed: status === 'SUCCESS'. Read this directly instead of comparing strings. |
amount | number | In INR. 0 when status is NOT_FOUND. |
bankref | string|null | Bank reference (UTR) once paid; null otherwise. |
curl -sS -X POST 'https://nineteenapis.online/api/v2/payments/nsdl/status' \
-H "Content-Type: application/json" \
-H "X-API-KEY: YOUR_NP_KEY" \
-H "X-Timestamp: $(date +%s)" \
-H "X-Nonce: $(openssl rand -hex 16)" \
-H "X-Signature: <compute HMAC — see V2 auth>" \
-d '{"collect_ref_arr":["CRN123"]}'
(async () => {
const crypto = require('crypto');
const url = 'https://nineteenapis.online/api/v2/payments/nsdl/status';
const body = {"collect_ref_arr":["CRN123"]};
const bodyStr = JSON.stringify(body);
const apiKey = process.env.NP_KEY || 'YOUR_NP_KEY';
const salt = process.env.NP_SALT || 'YOUR_NP_SALT';
const ts = String(Math.floor(Date.now()/1000));
const nonce = crypto.randomBytes(16).toString('hex');
const sig = crypto.createHmac('sha256', salt).update(apiKey + ts + nonce + bodyStr).digest('hex');
const headers = { 'Content-Type':'application/json', 'X-API-KEY':apiKey, 'X-Timestamp':ts, 'X-Nonce':nonce, 'X-Signature':sig };
const res = await fetch(url, { method:'POST', headers, body: bodyStr });
console.log(await res.json());
})();
import json, hmac, hashlib, os, time, secrets, urllib.request
url = "https://nineteenapis.online/api/v2/payments/nsdl/status"
body = {"collect_ref_arr":["CRN123"]}
body_str = json.dumps(body, separators=(",", ":"))
api_key, salt = os.environ["NP_KEY"], os.environ["NP_SALT"].encode()
ts, nonce = str(int(time.time())), secrets.token_hex(16)
sig = hmac.new(salt, (api_key + ts + nonce + body_str).encode(), hashlib.sha256).hexdigest()
h = {"Content-Type":"application/json","X-API-KEY":api_key,"X-Timestamp":ts,"X-Nonce":nonce,"X-Signature":sig}
req = urllib.request.Request(url, data=body_str.encode(), headers=h, method="POST")
with urllib.request.urlopen(req) as r: print(r.read().decode())
Typical success (200)
{
"success": true,
"data": [
{
"collect_ref": "20260430174031TESTREF001",
"transactionId": "TXN9F4A2B...",
"status": "SUCCESS",
"paid": true,
"amount": 115,
"bankref": "ICIC1234567890"
},
{
"collect_ref": "REF_THAT_DOES_NOT_EXIST",
"transactionId": "",
"status": "NOT_FOUND",
"paid": false,
"amount": 0,
"bankref": null
}
],
"raw": { "data": [ /* same array */ ] }
}
Integrator note: read data[i].paid directly. Avoid deriving "paid" from any other field — status values may grow over time. Refs you sent that don't match any stored transaction will come back with status: "NOT_FOUND" rather than being dropped silently.
/api/v2/payments/nsdl/link-details
Link details
Fetch link details by CRN list (same headers as collect).
| JSON body field | Required | Type / notes |
|---|---|---|
crn_arr | Yes | array of strings |
curl -sS -X POST 'https://nineteenapis.online/api/v2/payments/nsdl/link-details' \
-H "Content-Type: application/json" \
-H "X-API-KEY: YOUR_NP_KEY" \
-H "X-Timestamp: $(date +%s)" \
-H "X-Nonce: $(openssl rand -hex 16)" \
-H "X-Signature: <compute HMAC — see V2 auth>" \
-d '{"crn_arr":["CRN123"]}'
(async () => {
const crypto = require('crypto');
const url = 'https://nineteenapis.online/api/v2/payments/nsdl/link-details';
const body = {"crn_arr":["CRN123"]};
const bodyStr = JSON.stringify(body);
const apiKey = process.env.NP_KEY || 'YOUR_NP_KEY';
const salt = process.env.NP_SALT || 'YOUR_NP_SALT';
const ts = String(Math.floor(Date.now()/1000));
const nonce = crypto.randomBytes(16).toString('hex');
const sig = crypto.createHmac('sha256', salt).update(apiKey + ts + nonce + bodyStr).digest('hex');
const headers = { 'Content-Type':'application/json', 'X-API-KEY':apiKey, 'X-Timestamp':ts, 'X-Nonce':nonce, 'X-Signature':sig };
const res = await fetch(url, { method:'POST', headers, body: bodyStr });
console.log(await res.json());
})();
import json, hmac, hashlib, os, time, secrets, urllib.request
url = "https://nineteenapis.online/api/v2/payments/nsdl/link-details"
body = {"crn_arr":["CRN123"]}
body_str = json.dumps(body, separators=(",", ":"))
api_key, salt = os.environ["NP_KEY"], os.environ["NP_SALT"].encode()
ts, nonce = str(int(time.time())), secrets.token_hex(16)
sig = hmac.new(salt, (api_key + ts + nonce + body_str).encode(), hashlib.sha256).hexdigest()
h = {"Content-Type":"application/json","X-API-KEY":api_key,"X-Timestamp":ts,"X-Nonce":nonce,"X-Signature":sig}
req = urllib.request.Request(url, data=body_str.encode(), headers=h, method="POST")
with urllib.request.urlopen(req) as r: print(r.read().decode())
Typical success (200)
{"success":true,"raw":{}}
V2 — Payouts
/api/v2/payouts/balance
Balance
curl -sS -X POST 'https://nineteenapis.online/api/v2/payouts/balance' \
-H "Content-Type: application/json" \
-H "X-API-KEY: YOUR_NP_KEY" \
-H "X-Timestamp: $(date +%s)" \
-H "X-Nonce: $(openssl rand -hex 16)" \
-H "X-Signature: <compute HMAC — see V2 auth>" \
-d '{"environment":"prod"}'
(async () => {
const crypto = require('crypto');
const url = 'https://nineteenapis.online/api/v2/payouts/balance';
const body = {"environment":"prod"};
const bodyStr = JSON.stringify(body);
const apiKey = process.env.NP_KEY || 'YOUR_NP_KEY';
const salt = process.env.NP_SALT || 'YOUR_NP_SALT';
const ts = String(Math.floor(Date.now()/1000));
const nonce = crypto.randomBytes(16).toString('hex');
const sig = crypto.createHmac('sha256', salt).update(apiKey + ts + nonce + bodyStr).digest('hex');
const headers = { 'Content-Type':'application/json', 'X-API-KEY':apiKey, 'X-Timestamp':ts, 'X-Nonce':nonce, 'X-Signature':sig };
const res = await fetch(url, { method:'POST', headers, body: bodyStr });
console.log(await res.json());
})();
import json, hmac, hashlib, os, time, secrets, urllib.request
url = "https://nineteenapis.online/api/v2/payouts/balance"
body = {"environment":"prod"}
body_str = json.dumps(body, separators=(",", ":"))
api_key, salt = os.environ["NP_KEY"], os.environ["NP_SALT"].encode()
ts, nonce = str(int(time.time())), secrets.token_hex(16)
sig = hmac.new(salt, (api_key + ts + nonce + body_str).encode(), hashlib.sha256).hexdigest()
h = {"Content-Type":"application/json","X-API-KEY":api_key,"X-Timestamp":ts,"X-Nonce":nonce,"X-Signature":sig}
req = urllib.request.Request(url, data=body_str.encode(), headers=h, method="POST")
with urllib.request.urlopen(req) as r: print(r.read().decode())
Typical success (200)
{"success":true,"balance":123.45,"raw":{}}
/api/v2/payouts/verify-account
Verify account
curl -sS -X POST 'https://nineteenapis.online/api/v2/payouts/verify-account' \
-H "Content-Type: application/json" \
-H "X-API-KEY: YOUR_NP_KEY" \
-H "X-Timestamp: $(date +%s)" \
-H "X-Nonce: $(openssl rand -hex 16)" \
-H "X-Signature: <compute HMAC — see V2 auth>" \
-d '{"number":"9999999999","accountNo":"123456789012","ifscCode":"SBIN0001234","clientOrderId":"CO-1","environment":"prod"}'
(async () => {
const crypto = require('crypto');
const url = 'https://nineteenapis.online/api/v2/payouts/verify-account';
const body = {"number":"9999999999","accountNo":"123456789012","ifscCode":"SBIN0001234","clientOrderId":"CO-1","environment":"prod"};
const bodyStr = JSON.stringify(body);
const apiKey = process.env.NP_KEY || 'YOUR_NP_KEY';
const salt = process.env.NP_SALT || 'YOUR_NP_SALT';
const ts = String(Math.floor(Date.now()/1000));
const nonce = crypto.randomBytes(16).toString('hex');
const sig = crypto.createHmac('sha256', salt).update(apiKey + ts + nonce + bodyStr).digest('hex');
const headers = { 'Content-Type':'application/json', 'X-API-KEY':apiKey, 'X-Timestamp':ts, 'X-Nonce':nonce, 'X-Signature':sig };
const res = await fetch(url, { method:'POST', headers, body: bodyStr });
console.log(await res.json());
})();
import json, hmac, hashlib, os, time, secrets, urllib.request
url = "https://nineteenapis.online/api/v2/payouts/verify-account"
body = {"number":"9999999999","accountNo":"123456789012","ifscCode":"SBIN0001234","clientOrderId":"CO-1","environment":"prod"}
body_str = json.dumps(body, separators=(",", ":"))
api_key, salt = os.environ["NP_KEY"], os.environ["NP_SALT"].encode()
ts, nonce = str(int(time.time())), secrets.token_hex(16)
sig = hmac.new(salt, (api_key + ts + nonce + body_str).encode(), hashlib.sha256).hexdigest()
h = {"Content-Type":"application/json","X-API-KEY":api_key,"X-Timestamp":ts,"X-Nonce":nonce,"X-Signature":sig}
req = urllib.request.Request(url, data=body_str.encode(), headers=h, method="POST")
with urllib.request.urlopen(req) as r: print(r.read().decode())
Typical success (200)
{"success":true,"status":"SUCCESS","beneficiaryName":"...","raw":{}}
/api/v2/payouts/transfer
Transfer
X-Idempotency-Key (optional).
curl -sS -X POST 'https://nineteenapis.online/api/v2/payouts/transfer' \
-H "Content-Type: application/json" \
-H "X-API-KEY: YOUR_NP_KEY" \
-H "X-Timestamp: $(date +%s)" \
-H "X-Nonce: $(openssl rand -hex 16)" \
-H "X-Signature: <compute HMAC — see V2 auth>" \
-H "X-Idempotency-Key: unique-key-123" \
-d '{"number":"9999999999","amount":"100","transferMode":"IMPS","accountNo":"123456789012","ifscCode":"SBIN0001234","beneficiaryName":"Test User","clientOrderId":"PO-1","environment":"prod"}'
(async () => {
const crypto = require('crypto');
const url = 'https://nineteenapis.online/api/v2/payouts/transfer';
const body = {"number":"9999999999","amount":"100","transferMode":"IMPS","accountNo":"123456789012","ifscCode":"SBIN0001234","beneficiaryName":"Test User","clientOrderId":"PO-1","environment":"prod"};
const bodyStr = JSON.stringify(body);
const apiKey = process.env.NP_KEY || 'YOUR_NP_KEY';
const salt = process.env.NP_SALT || 'YOUR_NP_SALT';
const ts = String(Math.floor(Date.now()/1000));
const nonce = crypto.randomBytes(16).toString('hex');
const sig = crypto.createHmac('sha256', salt).update(apiKey + ts + nonce + bodyStr).digest('hex');
const headers = { 'Content-Type':'application/json', 'X-API-KEY':apiKey, 'X-Timestamp':ts, 'X-Nonce':nonce, 'X-Signature':sig, 'X-Idempotency-Key':'unique-key-123' };
const res = await fetch(url, { method:'POST', headers, body: bodyStr });
console.log(await res.json());
})();
import json, hmac, hashlib, os, time, secrets, urllib.request
url = "https://nineteenapis.online/api/v2/payouts/transfer"
body = {"number":"9999999999","amount":"100","transferMode":"IMPS","accountNo":"123456789012","ifscCode":"SBIN0001234","beneficiaryName":"Test User","clientOrderId":"PO-1","environment":"prod"}
body_str = json.dumps(body, separators=(",", ":"))
api_key, salt = os.environ["NP_KEY"], os.environ["NP_SALT"].encode()
ts, nonce = str(int(time.time())), secrets.token_hex(16)
sig = hmac.new(salt, (api_key + ts + nonce + body_str).encode(), hashlib.sha256).hexdigest()
h = {"Content-Type":"application/json","X-API-KEY":api_key,"X-Timestamp":ts,"X-Nonce":nonce,"X-Signature":sig,"X-Idempotency-Key":"unique-key-123"}
req = urllib.request.Request(url, data=body_str.encode(), headers=h, method="POST")
with urllib.request.urlopen(req) as r: print(r.read().decode())
Typical success (200)
{"success":true,"transactionId":"...","status":"PENDING","raw":{}}
/api/v2/payouts/status
Status
curl -sS -X POST 'https://nineteenapis.online/api/v2/payouts/status' \
-H "Content-Type: application/json" \
-H "X-API-KEY: YOUR_NP_KEY" \
-H "X-Timestamp: $(date +%s)" \
-H "X-Nonce: $(openssl rand -hex 16)" \
-H "X-Signature: <compute HMAC — see V2 auth>" \
-d '{"orderId":"NP_ORDER_ID","environment":"prod"}'
(async () => {
const crypto = require('crypto');
const url = 'https://nineteenapis.online/api/v2/payouts/status';
const body = {"orderId":"NP_ORDER_ID","environment":"prod"};
const bodyStr = JSON.stringify(body);
const apiKey = process.env.NP_KEY || 'YOUR_NP_KEY';
const salt = process.env.NP_SALT || 'YOUR_NP_SALT';
const ts = String(Math.floor(Date.now()/1000));
const nonce = crypto.randomBytes(16).toString('hex');
const sig = crypto.createHmac('sha256', salt).update(apiKey + ts + nonce + bodyStr).digest('hex');
const headers = { 'Content-Type':'application/json', 'X-API-KEY':apiKey, 'X-Timestamp':ts, 'X-Nonce':nonce, 'X-Signature':sig };
const res = await fetch(url, { method:'POST', headers, body: bodyStr });
console.log(await res.json());
})();
import json, hmac, hashlib, os, time, secrets, urllib.request
url = "https://nineteenapis.online/api/v2/payouts/status"
body = {"orderId":"NP_ORDER_ID","environment":"prod"}
body_str = json.dumps(body, separators=(",", ":"))
api_key, salt = os.environ["NP_KEY"], os.environ["NP_SALT"].encode()
ts, nonce = str(int(time.time())), secrets.token_hex(16)
sig = hmac.new(salt, (api_key + ts + nonce + body_str).encode(), hashlib.sha256).hexdigest()
h = {"Content-Type":"application/json","X-API-KEY":api_key,"X-Timestamp":ts,"X-Nonce":nonce,"X-Signature":sig}
req = urllib.request.Request(url, data=body_str.encode(), headers=h, method="POST")
with urllib.request.urlopen(req) as r: print(r.read().decode())
Typical success (200)
{"success":true,"status":"SUCCESS","raw":{}}
V2 — Outbound webhooks (NineteenPay → your callback URL)
When a signing secret is configured on your pipe, we send:
X-TSP-Timestamp— milliseconds since epoch (string)X-TSP-Signature—HMAC_SHA256(secret, timestamp + "." + JSON.stringify(body))hex
Verify (Node.js)
const crypto = require('crypto');
function verifyTspWebhook(body, tsHeader, sigHeader, signingSecret) {
const base = tsHeader + '.' + JSON.stringify(body);
const expected = crypto.createHmac('sha256', signingSecret).update(base).digest('hex');
return crypto.timingSafeEqual(Buffer.from(expected, 'utf8'), Buffer.from(sigHeader, 'utf8'));
}
Verify (Python)
import hmac, hashlib, json
def verify_tsp(body: dict, ts: str, sig: str, secret: str) -> bool:
base = ts + "." + json.dumps(body, separators=(",", ":"))
exp = hmac.new(secret.encode(), base.encode(), hashlib.sha256).hexdigest()
return hmac.compare_digest(exp, sig)
Payload shapes (examples)
NSDL_PAYIN).