# SGPayNowQR API — Full Reference > Generate EMVCo-compliant Singapore PayNow QR codes via REST API. Base URL: https://developers.sgpaynowqr.com/api/v1 --- ## Authentication All requests (except /health) require an API key in the X-API-Key header. Header: X-API-Key: sgpn_<32 hex characters> Get a free key at https://developers.sgpaynowqr.com/register --- ## POST /generate Generate a PayNow QR code. Content-Type: application/json ### Request Parameters | Field | Type | Required | Description | |-----------------|---------|----------------------------------|--------------------------------------------------| | payment_type | string | Yes | "uen", "mobile", or "vpa" | | uen | string | Required if payment_type="uen" | UEN number, max 25 characters | | merchant_name | string | Required if payment_type="uen" | Merchant name, max 25 characters | | mobile_number | string | Required if payment_type="mobile"| SG mobile: (+65)?[89]XXXXXXX | | vpa | string | Required if payment_type="vpa" | Virtual Payment Address | | amount | number | Yes | 0.01 to 999999.99 | | reference | string | No | Alphanumeric only, max 25 characters | | expiry | string | No | "1h", "2h", "6h", "12h", "24h", "none" (default: "24h") | | qr_color | string | No | Hex color, 6 chars (default: "7d1979") | | qr_size | number | No | 200, 300, or 400 pixels (default: 300) | | include_image | boolean | No | Return PNG image as base64 (default: true) | ### Conditional Requirements - payment_type="uen": uen and merchant_name are required - payment_type="mobile": mobile_number is required - payment_type="vpa": vpa is required ### Success Response (200) { "success": true, "data": { "qr_string": "000201010212...", "qr_image_base64": "iVBORw0KGgo...", "image_mime_type": "image/png", "payment_type": "uen", "amount": "10.50", "currency": "SGD", "reference": "INV001", "expiry": "24h" }, "meta": { "api_version": "v1", "request_id": "req_abc123def456", "usage": { "used": 42, "limit": 200, "period": "2026-03" } } } Notes: - qr_image_base64 and image_mime_type are only present when include_image=true - amount is returned as a string with 2 decimal places - reference is null if not provided --- ## Example: UEN Payment Request: curl -X POST https://developers.sgpaynowqr.com/api/v1/generate \ -H "Content-Type: application/json" \ -H "X-API-Key: sgpn_your_api_key_here" \ -d '{ "payment_type": "uen", "uen": "201234567A", "merchant_name": "My Company", "amount": 25.00, "reference": "INV001" }' ## Example: Mobile Payment Request: curl -X POST https://developers.sgpaynowqr.com/api/v1/generate \ -H "Content-Type: application/json" \ -H "X-API-Key: sgpn_your_api_key_here" \ -d '{ "payment_type": "mobile", "mobile_number": "+6591234567", "amount": 10.50 }' ## Example: VPA Payment Request: curl -X POST https://developers.sgpaynowqr.com/api/v1/generate \ -H "Content-Type: application/json" \ -H "X-API-Key: sgpn_your_api_key_here" \ -d '{ "payment_type": "vpa", "vpa": "+6591234567#OCBC", "amount": 5.00, "reference": "DONATION" }' --- ## Error Responses All errors follow this format: { "success": false, "error": { "code": "ERROR_CODE", "message": "Human-readable description" }, "meta": { "api_version": "v1", "request_id": "req_abc123def456" } } ### Error Codes | HTTP | Code | Description | |------|-----------------------|--------------------------------------------| | 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 | --- ## Rate Limits Limits are per API key, per calendar month (Singapore timezone). | Tier | Monthly Limit | |-------------|---------------| | Free | 50 | | Starter | 200 | | Pro | 2,000 | | Enterprise | 10,000 | ### Rate Limit Headers All responses include: X-RateLimit-Limit: 200 X-RateLimit-Remaining: 158 X-RateLimit-Reset: 2026-04-01T00:00:00+08:00 X-Request-Id: req_abc123def456 Only successful (2xx) responses count toward the quota. Limits reset on the 1st of each month at 00:00:00+08:00 (Singapore time). --- ## GET /health Health check endpoint. No authentication required. Response (200): { "success": true, "data": { "status": "ok", "version": "v1", "timestamp": "2026-03-22T14:30:00.000Z" }, "meta": { "api_version": "v1", "request_id": "req_abc123def456" } } status is "ok" when all systems are operational, "degraded" when the database is unavailable. --- ## CORS All endpoints return CORS headers allowing cross-origin requests: Access-Control-Allow-Origin: * Access-Control-Allow-Methods: POST, GET, OPTIONS Access-Control-Allow-Headers: Content-Type, X-API-Key, Accept Access-Control-Max-Age: 86400 Preflight OPTIONS requests return 204 No Content.