Handling Errors and Rate Limits
Every SGPayNowQR error code, recommended retry/backoff handling, and how to read the X-RateLimit-* response headers.
Every error response uses the same envelope, so you can handle them uniformly. Inspect error.code for a stable, machine-readable identifier and log meta.request_id for support.
{
"success": false,
"error": {
"code": "RATE_LIMIT_EXCEEDED",
"message": "Monthly usage limit exceeded"
},
"meta": {
"api_version": "v1",
"request_id": "req_abc123def456"
}
}Error codes
| HTTP | Code | Meaning |
|---|---|---|
| 400 | VALIDATION_ERROR | Invalid parameters or missing required fields |
| 400 | INVALID_JSON | Request body is not valid JSON |
| 400 | INVALID_CONTENT_TYPE | Content-Type must be application/json |
| 401 | UNAUTHORIZED | Missing or invalid API key |
| 429 | RATE_LIMIT_EXCEEDED | Monthly usage limit exceeded |
| 500 | INTERNAL_ERROR | Server error during QR generation |
Retry guidance
4xx errors are caused by the request — fix the input rather than retrying. VALIDATION_ERROR, INVALID_JSON, and UNAUTHORIZED will keep failing identically. For 429 RATE_LIMIT_EXCEEDED, stop until the quota resets (see below). For 500 INTERNAL_ERROR, retry with exponential backoff (e.g. 1s, 2s, 4s) and cap the attempts.
Rate limits
Limits are per API key, per calendar month (Singapore timezone). Only successful (2xx) responses count toward the quota, and it resets on the 1st of each month at 00:00:00+08:00.
| Tier | Monthly limit |
|---|---|
| Free | 50 |
| Starter | 200 |
| Pro | 2,000 |
| Enterprise | 10,000 |
Reading the rate-limit headers
Every response carries your current quota state. Track these to avoid hitting the limit:
X-RateLimit-Limit: 200
X-RateLimit-Remaining: 158
X-RateLimit-Reset: 2026-04-01T00:00:00+08:00
X-Request-Id: req_abc123def456X-RateLimit-Remaining— requests left this month; throttle as it approaches 0.X-RateLimit-Reset— when the quota refills (ISO 8601, SGT).
Next, see TypeScript SDK Quickstart or the full API reference.