# Tatsupay — Full Documentation Tatsupay is a QRIS payment gateway for businesses in Indonesia. This file contains the complete public documentation as plain text, intended for language models and automated tools. Canonical site: https://tatsupay.com HTML documentation: https://tatsupay.com/docs OpenAPI specification: https://tatsupay.com/openapi.json Generated: 2026-10-05T22:49:03.317Z ================================================================ OVERVIEW ================================================================ Tatsupay lets a merchant accept payments via QRIS, the Indonesian national QR payment standard. A single QR code is accepted by every e-wallet and mobile banking app that supports QRIS, so customers pay with an app they already have. What Tatsupay provides: - A REST API to create transactions and check their status - QR data and a rendered QR image for each transaction - Webhooks when a payment settles - A ledger recording balance per transaction - Payouts to verified Indonesian bank accounts - A merchant dashboard and an account centre with SSO Tatsupay is not a bank and does not offer fund storage as a standalone product. ================================================================ PRICING ================================================================ Transaction fees: - QRIS (code: qris): 0.7% (70 bps) per transaction. Min IDR 500, max IDR 10,000,000. - QRIS CUSTOM (code: qris_custom): billed via subscription, no per-transaction fee. Min IDR 500, max IDR 10,000,000. Payout fee: IDR 5,000 per payout request, regardless of amount. QRIS Custom subscription plans: - qris_custom_1m: 1 Bulan, 30 days, IDR 99,000 (about IDR 99,000 per month) - qris_custom_3m: 3 Bulan, 90 days, IDR 269,000 (about IDR 89,666 per month) - qris_custom_6m: 6 Bulan, 180 days, IDR 499,000 (about IDR 83,166 per month) - qris_custom_12m: 12 Bulan, 365 days, IDR 899,000 (about IDR 73,890 per month) QRIS Custom lets a merchant use QRIS under their own business name. Payments land directly in the merchant's own account and Tatsupay charges no per-transaction fee; the product is billed through the subscription above. There is no signup fee and no monthly fee for standard QRIS acceptance. Fees are deducted when a transaction settles and are recorded in the ledger, so each deduction can be reviewed individually. WARNING: the pricing service was unreachable when this file was generated. The figures above are fallback values and may be out of date. ================================================================ BASE URL ================================================================ https://api.tatsupay.com All requests must use HTTPS. ================================================================ AUTHENTICATION ================================================================ Every request is authenticated with an API key passed as a bearer token: Authorization: Bearer sk_test_your_key_here Key prefixes: - sk_test_ — test mode. No real funds move. Transactions can be settled through the simulate endpoint. - sk_live_ — live mode. Real payments. API keys grant full access to the account's transactions. They must be kept in server-side environment variables and must never be shipped in code that reaches a browser or mobile app. A key is shown once at creation and stored as a hash, so it cannot be retrieved again. ================================================================ CREATE A TRANSACTION ================================================================ POST /v1/transactions Request body fields: - amount (integer, required) — amount in whole rupiah. Not in cents. - payment_method (string, required) — method code, for example "qris". - reference (string, optional) — the merchant's own order identifier. Strongly recommended, because it is what makes reconciliation possible. Example request: curl -X POST "https://api.tatsupay.com/v1/transactions" \ -H "Authorization: Bearer sk_test_your_key" \ -H "Content-Type: application/json" \ -d '{ "amount": 150000, "payment_method": "qris", "reference": "ORDER-1042" }' Example response (200): { "id": "trx_01HQ8Z3XK2M9V4N7P1R5T8W2Y6", "status": "pending", "amount": 150000, "payment_method": "qris", "reference": "ORDER-1042", "qr_string": "00020101021226...", "url_image_qris": "https://api.tatsupay.com/v1/transactions/trx_01HQ.../qris.png", "expires_at": "2026-10-03T01:15:00Z", "created_at": "2026-10-03T00:45:00Z" } Response fields: - id — Tatsupay transaction identifier, prefixed trx_. - status — see TRANSACTION STATUSES below. - qr_string — raw QRIS payload. Render it as a QR code yourself if you want control over size and styling. - url_image_qris — a ready-made PNG of the same QR, for cases where rendering it yourself is not worth the effort. - expires_at — after this time the transaction can no longer be paid. ================================================================ CHECK TRANSACTION STATUS ================================================================ GET /v1/transactions/{id} Returns the current state of one transaction. Use this as a fallback when a webhook does not arrive; do not use it as the primary mechanism, because polling every transaction is wasteful compared with receiving webhooks. Example: curl "https://api.tatsupay.com/v1/transactions/trx_01HQ8Z3XK2M9V4N7P1R5T8W2Y6" \ -H "Authorization: Bearer sk_test_your_key" ================================================================ LIST TRANSACTIONS ================================================================ GET /v1/transactions Returns transactions for the authenticated merchant, most recent first. ================================================================ PAYMENT METHODS ================================================================ GET /v1/payment-methods Returns the payment methods enabled for the authenticated merchant, including the fee that applies to that merchant. ================================================================ SIMULATE A PAYMENT (TEST MODE ONLY) ================================================================ POST /v1/transactions/{id}/simulate Marks a test-mode transaction as paid, so the full flow including webhook delivery and balance crediting can be exercised without real money. This endpoint only works with test-mode keys. ================================================================ WEBHOOKS ================================================================ When a transaction settles, Tatsupay sends a POST request to the endpoint registered in the dashboard. Example payload: { "event": "transaction.paid", "data": { "id": "trx_01HQ8Z3XK2M9V4N7P1R5T8W2Y6", "status": "paid", "amount": 150000, "reference": "ORDER-1042", "paid_at": "2026-10-03T00:47:12Z" } } Requirements for the receiving endpoint: - Respond with a 2xx status. Any other status is treated as a failure and the delivery is retried with increasing delays. - Be idempotent. Retries can deliver the same event more than once. Processing an order twice is far more damaging than re-checking whether an order has already been processed. - Respond quickly. Do the slow work after acknowledging, not before. Delivery history is visible in the dashboard, so a webhook that never arrived can be distinguished from one that arrived and failed. ================================================================ TRANSACTION STATUSES ================================================================ - pending — transaction created, awaiting payment. - paid — payment received and the transaction has settled. - expired — the payment window elapsed without payment. - failed — the transaction failed and cannot be paid. Only "paid" means money has been received. Treat every other status as not yet paid. ================================================================ ERROR HANDLING ================================================================ Failures return an appropriate HTTP status code with a JSON body: { "error": { "code": "VALIDATION_ERROR", "field": "amount" } } Branch on the "code" value rather than on message text. Messages may be reworded over time; codes will not. Common status codes: - 400 — the request was malformed or failed validation. - 401 — the API key is missing or invalid. - 404 — the transaction does not exist, or does not belong to this account. - 429 — rate limit exceeded. See RATE LIMITS below. - 503 — a dependency was temporarily unavailable; retry is appropriate. ================================================================ RATE LIMITS ================================================================ Requests are rate limited per API key. When the limit is exceeded the response is 429 with a Retry-After header stating how many seconds to wait before retrying. Honour that header rather than retrying immediately. ================================================================ TEST AND LIVE MODE ================================================================ Every account has two separate sets of keys. Test mode involves no real funds, and its transactions are kept separate from live transactions in the dashboard and in the ledger. The recommended sequence is to build against test mode, exercise the webhook and settlement path with the simulate endpoint, and only then swap in the live key. ================================================================ ACCOUNTS AND SSO ================================================================ Accounts are managed at https://account.tatsupay.com. Signing in once there grants access to the merchant dashboard and other Tatsupay services, through OAuth 2.0 with PKCE and OpenID Connect. Two-step verification is enforced during sign-in, and each account has a reviewable security activity history. The merchant dashboard is at https://merchant.tatsupay.com. ================================================================ CONTACT ================================================================ Email: support@tatsupay.com