Reference — errors, HTTP status, limits
Use this page when debugging integrations. Responses are JSON unless noted.
Error response format
Failed API calls return a JSON body like:
{
"success": false,
"error": {
"message": "Human-readable reason (safe for logs; no internal stack traces)",
"statusCode": 400
}
}
successisfalsefor application-level failures.error.messageexplains what went wrong; do not assume a stable machine-readable code unless documented on the specific route.error.statusCodemirrors the HTTP status when applicable.- Never log full request bodies in production if they may contain sensitive data; follow your PCI/security policy.
HTTP status codes
Typical meanings for merchant payment/payout APIs:
| Code | Meaning | Typical causes |
|---|---|---|
| 200 | OK | Request succeeded; body may still indicate business status (e.g. transaction PENDING). |
| 400 | Bad Request | Invalid JSON, missing required fields, validation (Zod/schema), wrong pipe for endpoint, business rule (e.g. onboarding incomplete). |
| 401 | Unauthorized | Missing/wrong V1 keys; V2 wrong/missing HMAC, stale timestamp, bad signature, replayed nonce. For V2 clock skew, the JSON may include serverTime / serverTimeISO / skewSeconds and responses expose X-Server-Time; sync with GET /api/v2/time (see V2 HMAC). |
| 403 | Forbidden | V2: caller IP not on pipe whitelist; empty whitelist; nonce replay. |
| 404 | Not Found | Transaction or resource not found for the given merchant (e.g. status enquiry). |
| 429 | Too Many Requests | Rate limit exceeded for your merchant tier; back off and retry with exponential delay. |
| 500 | Internal Server Error | Unexpected server fault; retry later; if persistent, contact support with time and route (no secrets). |
| 503 | Service Unavailable | Health check / dependency degradation; retry. |
2xx means the HTTP layer accepted the call. Always read the JSON for success, status, or gateway raw fields for payment state.
Rate limiting
Requests are subject to per-merchant rate limits (tier-based). When limited, you receive 429. Reduce concurrency, cache idempotent reads, and exponential backoff on retries.
IP whitelisting (API V2)
V2 requires at least one active IP/CIDR on your pipe. Requests from non-listed IPs get 403. Configure ranges for your NAT egress IPs. V1 rules depend on pipe/channel.
Server operators may set environment variable TSP_TRUSTED_IPS (comma-separated IPv4 addresses) so those IPs bypass the per-pipe whitelist for trusted infrastructure (e.g. merchant portal BFF). HMAC and nonce checks still apply.
Idempotency (API V2)
The header X-Idempotency-Key is optional but strongly recommended on mutating routes that support it (e.g. collect, refund, transfer). The first successful response may be cached (e.g. 24h); duplicate keys return the same body without duplicating side effects.
Outbound webhooks (to your callback URL)
When a signing secret is set on the pipe, callbacks include X-TSP-Timestamp and X-TSP-Signature. Verify: HMAC_SHA256(secret, timestamp + "." + JSON.stringify(body)) as lowercase hex. Use constant-time comparison.
Payload shape depends on pipe (gateway passthrough, escrow normalized, JPSL raw, payout rail, Native V2 settlement event). See the V2 routes page outbound section for examples.
Glossary
- Pipe
- Integration channel (credentials + limits + optional callback). One merchant can have multiple pipes.
- Native V1
- V1 routes under
/api/payments/nineteenpay-native/using a gatewaypayloadobject. - Native V2
- V2 routes under
/api/v2/payments/np-native/only — collect returnscheckoutUrl(hosted payer page at/pay/:transactionId), optionalshare_intentURL(/pay/share/:transactionId, Web Share QR),upiDeeplink, and status; not the same as Native V1. - checkoutUrl
- HTTPS URL returned by Native V2 collect — TSP-hosted page where the payer completes UPI (no HMAC on that page). Not the same as optional
pgUrl. - V1 collect
- HMAC V2 routes with a gateway-style
payload(same field style as Native V1; e.g./api/v2/payments/collect); notnp-native.