tgpay cryptoAPI
crypto-payapiinvoicesrefunds

Referensi API: faktur dan pengembalian dana

Baca 5 menitDiperbarui 22 Agu 2026

Metode faktur: createInvoice, getInvoices, deleteInvoice, refundInvoice. Konvensi umum (autentikasi, envelope, jumlah, spend_id) ada di halaman Referensi Merchant API; panduan langkah demi langkahnya ada di Menerima pembayaran lewat faktur.

createInvoice

POST /pay/api/createInvoice — scope invoices, batas 60 per menit.

ParameterTipeWajibKeterangan
currency_typestringtidakcrypto (bawaan) atau fiat
assetstringmode cryptoaset yang ditagih, misalnya USDT. Tidak boleh dipakai bersama fiat
fiatstringmode fiatmata uang fiat yang dipakai untuk harganya (baris is_fiat dari getCurrencies)
accepted_assetsstring / arraytidakkhusus mode fiat: aset yang boleh dipakai pembayar — string dipisah koma ("USDT,GRAM") atau array JSON. Dikosongkan = semua aset yang didukung
amountstringya, kecuali open_amount diisistring desimal positif: satuan aset di mode crypto, satuan fiat (maksimal 2 angka di belakang koma) di mode fiat
open_amountbooleantidakekstensi, khusus mode crypto: tanpa jumlah tetap — pembayar yang mengisinya saat membayar (donasi dan tip). Tidak bisa dipakai bersama amount
descriptionstringtidakmaksimal 1024 karakter, ditampilkan ke pembayar
hidden_messagestringtidakmaksimal 2048 karakter, baru terlihat oleh pembayar setelah pembayaran
payloadstringtidakmaksimal 4096 karakter data milikmu sendiri, dikirim balik di objek faktur dan di webhook
allow_commentsbooleantidakizinkan pembayar menyertakan komentar (bawaan true)
allow_anonymousbooleantidakizinkan pembayar menyembunyikan identitasnya (bawaan true)
paid_btn_namestringtidaktombol setelah pembayaran: viewItem, openChannel, openBot, atau callback
paid_btn_urlstringtidakURL http(s) tombol itu — wajib kalau paid_btn_name diisi
swap_tostringtidaktukar otomatis pembayaran yang masuk ke aset ini. Sifatnya best-effort: kalau penukaran tidak bisa jalan saat pembayaran, pembayarannya tetap berhasil tanpa ditukar
expires_inintegertidakdetik sampai faktur kedaluwarsa, maksimal 2678400 (31 hari); dikosongkan atau 0 = tidak pernah
rate_lock_secondsintegertidakekstensi, khusus mode fiat: kunci kurs pada saat faktur dibuat selama rentang waktu ini (lihat di bawah)

Hasilnya — sekaligus payload webhook invoice_paid — adalah objek faktur. Field pentingnya:

  • Identitas dan status: invoice_id, hash (id publik di dalam pay_url), status (active / paid / expired), pay_url — link t.me yang kamu kirim ke pembayar (bot_invoice_url, mini_app_invoice_url, web_app_invoice_url adalah aliasnya).
  • Jumlah: amount (nilai faktur — satuan fiat di faktur fiat, kripto di selainnya; null selama faktur open-amount belum dibayar), amount_minor, dan di faktur fiat yang sudah dibayar paid_asset / paid_amount / paid_fiat_rate — kripto yang benar-benar ditagih dan kurs yang dipakai.
  • Biaya: fee_asset / fee_amount, dicatat saat pembayaran — angka resmi untuk pembukuanmu (fee dan usd_rate adalah alias Crypto Bot yang sudah usang). Lihat biaya dan batas.
  • Pembayar: paid_by_user_id (null kalau pembayar memilih anonim), paid_anonymously, comment.
  • Pengembalian dana (ekstensi): refunded_amount / refunded_minor (kumulatif) dan refunded_at, dicatat begitu faktur dikembalikan sepenuhnya.
  • Penguncian kurs (ekstensi): rate_lock_until dan rate_lock_rates — kurs per aset yang disimpan, null kalau tidak ada penguncian yang diminta.
  • Sesuai saat dibuat: description, hidden_message, payload, paid_btn_name / paid_btn_url, expiration_date (expires_at adalah alias), dan field penukaran (swap_to, is_swapped, swapped_to, swapped_rate, swapped_output, …).

Error: 400 invalid_currency (aset dan fiat tertukar), 400 invalid_amount, 404 unknown_asset, 400 unsupported_fiat, 400 paid_btn_url_required, dan untuk permintaan penguncian kurs 400 rate_lock_fiat_only, 409 ratelock_disabled, 409 rate_unavailable (tidak ada kurs terbaru untuk salah satu aset yang diterima — coba lagi).

Cara faktur dibayar

Pembayar membayar dari saldo dompetnya di Mini App — langsung, tanpa biaya jaringan. Pembayar juga bisa membayar faktur itu pakai dana dari dompet luar: aplikasi menampilkan alamat deposit untuknya, dananya masuk ke dompetnya sendiri, lalu fakturnya lunas otomatis begitu dana itu tiba. Dari sisimu keduanya terlihat sama: faktur paid biasa dan webhook invoice_paid — tidak ada parameter atau field tambahan yang perlu ditangani.

Di faktur fiat, jumlah kriptonya dihitung saat pembayaran dan dibulatkan ke atas untuk keuntunganmu, jadi kamu tidak pernah menerima kurang dari nilai fiat yang tertera. Kalau tidak ada kurs terbaru, pembayarannya gagal di sisi pembayar — bukan diselesaikan dengan kurs lama.

Mengunci kurs di faktur fiat

Kirim rate_lock_seconds untuk menyimpan kurs setiap aset yang diterima pada saat faktur dibuat. Selama kuncinya masih berlaku, pembayar melihat persis jumlah yang tersimpan itu, dan pembayarannya dihitung dengan kurs tersimpan — risiko kurs selama rentang itu kamu yang tanggung. Server membatasi rentangnya antara 60 detik dan maksimum platform (saat ini 15 menit).

Setelah kuncinya berakhir, fakturnya tetap bisa dibayar dan diam-diam kembali memakai kurs saat pembayaran. Kalau kamu ingin fakturnya ikut kedaluwarsa bersama kursnya, isi expires_in dengan nilai yang sama.

getInvoices

GET /pay/api/getInvoices — scope read. Filter: asset, fiat, invoice_ids (dipisah koma), status (active / paid / expiredexpired adalah ekstensi; active tidak menyertakan faktur yang sudah lewat tenggatnya), plus offset / count. Mengembalikan {"items": [invoice, …]}, diurutkan dari yang terbaru.

deleteInvoice

POST /pay/api/deleteInvoice — scope invoices. Satu parameter: invoice_id. Membatalkan faktur yang belum dibayar dan mengembalikan true. Error: 404 invoice_not_found, 409 invoice_already_paid — faktur yang sudah dibayar tidak bisa dihapus, uangnya sudah berpindah.

refundInvoice

POST /pay/api/refundInvoice — scope refunds, batas 30 per menit. Ekstensi di luar Crypto Bot: mengembalikan nilai faktur yang sudah dibayar — atau sebagiannya — dari saldo aplikasimu ke siapa pun yang membayarnya, termasuk pembayar anonim, tanpa membuka siapa mereka.

ParameterTipeWajibKeterangan
invoice_idintegeryafaktur yang sudah dibayar
amountstringtidakjumlah yang dikembalikan, dalam aset faktur itu. Dikosongkan = seluruh sisa yang belum dikembalikan. Pengembalian sebagian menumpuk sampai nilai penuh faktur
spend_idstringtidakkunci idempotensi — pakai saja, supaya percobaan ulang setelah timeout mengulang hasil lama, bukan mengembalikan dana dua kali

Hasilnya adalah objek faktur terbaru dengan refunded_amount / refunded_minor kumulatif; refunded_at dicatat begitu faktur dikembalikan sepenuhnya. Statusnya tetap paid. Biaya platform tidak ikut dikembalikan. Setiap pengembalian memicu webhook refund_completed — webhook opsional yang perlu kamu aktifkan dulu.

Error: 404 invoice_not_found, 409 invoice_not_paid, 409 already_refunded (tidak ada sisa yang bisa dikembalikan), 409 amount_too_big (lebih besar dari sisa yang belum dikembalikan), 409 insufficient_funds, 400 invalid_amount, dan pasangan spend_id 409 idempotency_conflict / 409 idempotency_in_progress.