Idempotency
Panggilan API dapat gagal di tengah proses bukan karena request ditolak, tetapi karena koneksi terputus sebelum response diterima. Dalam kondisi ini, Anda tidak dapat mengetahui apakah transaksi sudah berhasil dibuat di sisi TuplePay atau belum.
Melakukan retry tanpa mekanisme idempotency berisiko membuat transaksi duplikat, seperti QRIS
yang dibuat dua kali atau, yang lebih berisiko, transfer dana yang diproses lebih dari sekali.
Header Idempotency-Key mencegah kondisi tersebut: retry dengan Idempotency-Key yang sama aman
dilakukan dan tidak akan membuat transaksi baru.
Endpoint yang mewajibkan
| Endpoint | Wajib kirim Idempotency-Key? |
|---|---|
POST /api/v1/transactions/qris | Ya |
POST /api/v1/transactions/disbursements | Ya |
Cara pakai
Generate satu UUID v4 untuk setiap transaksi, bukan untuk setiap HTTP request. Gunakan nilai
yang sama untuk setiap retry dari transaksi yang sama.
Rekomendasi praktis: simpan Idempotency-Key bersama ID transaksi internal kamu (misalnya
externalReference), sehingga setiap retry akibat timeout, koneksi terputus, atau kegagalan
jaringan dapat menggunakan key yang sama tanpa perlu membuat key baru.
Jangan generate Idempotency-Key baru setiap kali melakukan retry, karena hal tersebut akan
dianggap sebagai transaksi baru dan menghilangkan perlindungan terhadap duplikasi.
Idempotency-Key memiliki scope per endpoint. Artinya, key yang sama dapat digunakan pada
endpoint yang berbeda tanpa menimbulkan konflik, misalnya satu kali pada create-qris dan satu
kali pada create-disbursement.
Yang dianggap "request yang sama"
Kombinasi Idempotency-Key + endpoint + isi body request harus identik. Jika body-nya berbeda
sedikit pun (nominal, deskripsi, dsb.) sementara key-nya sama, itu akan dianggap sebagai konflik
— bukan permintaan baru dan bukan juga retry yang sah.
Perilaku Idempotency-Key
| Kondisi | Yang terjadi |
|---|---|
| Key baru (belum pernah dipakai di endpoint ini) | Diproses normal, transaksi baru dibuat. |
| Key sama, body sama persis, percobaan sebelumnya sudah selesai | Response yang identik (status HTTP dan body yang sama) dikembalikan lagi. Tidak diproses ulang, tidak ada transaksi kedua yang dibuat. |
| Key sama, body sama persis, percobaan sebelumnya masih diproses | 409 Conflict, code IDEMPOTENCY_REQUEST_IN_PROGRESS -- coba lagi sebentar. |
| Key sama, body berbeda dari percobaan sebelumnya | 409 Conflict, code IDEMPOTENCY_KEY_CONFLICT. |
| Key sama, percobaan sebelumnya gagal (mis. error internal) | Diproses ulang dari awal -- retry dengan key yang sama aman dilakukan, tidak dianggap konflik. |
Header Idempotency-Key tidak dikirim | 400 Bad Request, code IDEMPOTENCY_KEY_REQUIRED. |
{
"code": "IDEMPOTENCY_KEY_CONFLICT",
"message": "Idempotency-Key 'a1b2c3d4-...' sudah pernah dipakai dengan request body yang berbeda.",
"correlationId": "9f8e7d6c-5b4a-3210-fedc-ba9876543210",
"requestId": "1a2b3c4d-5e6f-7890-abcd-ef1234567890",
"timestamp": "2026-08-13T09:15:30.123Z"
}
{
"code": "IDEMPOTENCY_REQUEST_IN_PROGRESS",
"message": "Request dengan Idempotency-Key 'a1b2c3d4-...' masih diproses, coba lagi sebentar.",
"correlationId": "9f8e7d6c-5b4a-3210-fedc-ba9876543210",
"requestId": "1a2b3c4d-5e6f-7890-abcd-ef1234567890",
"timestamp": "2026-08-13T09:15:30.123Z"
}
Masa Berlaku Idempotency-Key
Idempotency-Key berlaku selama 24 jam sejak pertama kali digunakan. Setelah 24 jam berlalu,
penggunaan key yang sama akan diperlakukan sebagai request baru, bukan sebagai replay atau retry
dari request sebelumnya.