API documentation
A REST API for creating QRIS transactions, checking their status, and receiving payment notifications.
Introduction
The Tatsupay API is REST-based. Requests and responses use JSON, and every request is authenticated with an API key via the Authorization header. No SDK is required.
Base URL
All endpoints live under the base URL below. Every request must go over HTTPS.
https://api.tatsupay.comAuthentication
Pass your API key as a bearer token in the Authorization header. Test keys are prefixed sk_test_ and live keys sk_live_.
Authorization: Bearer sk_test_your_key_hereAn API key grants full access to your account's transactions. Keep it in a server-side environment variable, and never ship it in code that reaches a browser or mobile app.
Test and live mode
Every account has two separate sets of keys. Test-mode transactions involve no real funds and can be settled through the simulate endpoint, so the whole integration can be exercised first.
Create a transaction
Creates a new transaction and returns QRIS data ready to display to your customer.
Parameters
- amount — integer, amount in whole rupiah. Required.
- payment_method — payment method code, for example qris. Required.
- reference — your own order identifier. Optional, but strongly recommended for reconciliation.
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"
}'{
"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_01HQ8Z3XK2M9V4N7P1R5T8W2Y6/qris.png",
"expires_at": "2026-10-03T01:15:00Z",
"created_at": "2026-10-03T00:45:00Z"
}const res = await fetch('https://api.tatsupay.com/v1/transactions', {
method: 'POST',
headers: {
Authorization: `Bearer ${process.env.TATSUPAY_SECRET_KEY}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
amount: 150000,
payment_method: 'qris',
reference: 'ORDER-1042',
}),
});
const trx = await res.json();Check status
Retrieves the current state of a transaction. Useful as a fallback check if a webhook does not arrive.
curl "https://api.tatsupay.com/v1/transactions/trx_01HQ8Z3XK2M9V4N7P1R5T8W2Y6" \
-H "Authorization: Bearer sk_test_your_key"Webhooks
When a transaction settles, Tatsupay sends a POST request to the endpoint you register in the dashboard. Your endpoint must respond with a 2xx status; otherwise delivery is retried with increasing delays.
{
"event": "transaction.paid",
"data": {
"id": "trx_01HQ8Z3XK2M9V4N7P1R5T8W2Y6",
"status": "paid",
"amount": 150000,
"reference": "ORDER-1042",
"paid_at": "2026-10-03T00:47:12Z"
}
}Your webhook endpoint must be idempotent. Retries can deliver the same event more than once, and processing an order twice is a far more damaging outcome than re-checking an order's status before acting on it.
Transaction statuses
- pending — transaction created, awaiting payment.
- paid — payment received and the transaction has settled.
- expired — the payment window elapsed.
- failed — the transaction failed and cannot be paid.
Error handling
Failures return an appropriate HTTP status code along with a JSON body carrying an error code. Branch on the code rather than the message text: messages may be reworded over time, codes will not.
{
"error": {
"code": "VALIDATION_ERROR",
"field": "amount"
}
}Rate limits
Requests are rate limited per API key. When the limit is exceeded you receive a 429 along with a Retry-After header stating how many seconds to wait before retrying.
For machines and AI agents
An OpenAPI specification and a plain-text summary are available at the addresses below, so automated tools do not need to parse this page's HTML.