Skip to main content

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

EndpointWajib kirim Idempotency-Key?
POST /api/v1/transactions/qrisYa
POST /api/v1/transactions/disbursementsYa

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

KondisiYang terjadi
Key baru (belum pernah dipakai di endpoint ini)Diproses normal, transaksi baru dibuat.
Key sama, body sama persis, percobaan sebelumnya sudah selesaiResponse 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 diproses409 Conflict, code IDEMPOTENCY_REQUEST_IN_PROGRESS -- coba lagi sebentar.
Key sama, body berbeda dari percobaan sebelumnya409 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 dikirim400 Bad Request, code IDEMPOTENCY_KEY_REQUIRED.
Contoh -- 409 IDEMPOTENCY_KEY_CONFLICT
{
"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"
}
Contoh -- 409 IDEMPOTENCY_REQUEST_IN_PROGRESS
{
"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.