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
  }
}
  • success is false for application-level failures.
  • error.message explains what went wrong; do not assume a stable machine-readable code unless documented on the specific route.
  • error.statusCode mirrors 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:

CodeMeaningTypical causes
200OKRequest succeeded; body may still indicate business status (e.g. transaction PENDING).
400Bad RequestInvalid JSON, missing required fields, validation (Zod/schema), wrong pipe for endpoint, business rule (e.g. onboarding incomplete).
401UnauthorizedMissing/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).
403ForbiddenV2: caller IP not on pipe whitelist; empty whitelist; nonce replay.
404Not FoundTransaction or resource not found for the given merchant (e.g. status enquiry).
429Too Many RequestsRate limit exceeded for your merchant tier; back off and retry with exponential delay.
500Internal Server ErrorUnexpected server fault; retry later; if persistent, contact support with time and route (no secrets).
503Service UnavailableHealth 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 gateway payload object.
Native V2
V2 routes under /api/v2/payments/np-native/ only — collect returns checkoutUrl (hosted payer page at /pay/:transactionId), optional share_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); not np-native.