tgpay cryptoAPI
crypto-payapiinvoicesrefunds

Referensi API: faktur dan pengembalian dana

Baca 6 menitDiperbarui 9 Okt 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 = masa berlaku bawaan. Baca expiration_date dari hasilnya
rate_lock_secondsintegertidakekstensi, khusus mode fiat: kunci kurs pada saat faktur dibuat selama rentang waktu ini (lihat di bawah)

Deskripsi, konten setelah pembayaran, dan tombol mungkin tidak ditampilkan kepada pembayar selama ditinjau atau belum disetujui. Jumlah faktur tetap bisa dibayar.

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 seluruh dana faktur dikembalikan.
  • 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, 400 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, dengan saldo yang cukup dan konfirmasi pembayaran. Pembayar juga bisa mendanai faktur dari dompet luar: jika pilihan tersedia, aplikasi menampilkan alamat deposit dan tenggat pembayaran. Deposit masuk ke dompet pembayar sendiri. Pembayaran otomatis membutuhkan deposit ke alamat itu, saldo tersedia yang cukup, tidak adanya pembatasan pembayaran keluar, serta permintaan pembayaran dan faktur yang belum kedaluwarsa. Deposit terlambat tetap berada di dompet pembayar; itu bukan bukti faktur sudah dibayar. Dari sisimu, hasilnya sama: faktur paid biasa dan event invoice_paid jika URL webhook diatur — tidak ada parameter atau field tambahan yang perlu ditangani.

Untuk faktur fiat, jumlah kripto dihitung saat pembayaran dan dibulatkan ke atas sampai satuan terkecil aset pilihan. Biaya merchant kemudian dipotong dari jumlah kripto itu. Jika tidak ada kurs terkunci yang masih berlaku atau kurs baru, pembayaran gagal di sisi pembayar, bukan diselesaikan dengan kurs kedaluwarsa.

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 menyesuaikan durasi yang diminta ke rentang yang didukung. Baca rate_lock_until dari hasilnya untuk mengetahui tenggat yang berlaku.

Setelah penguncian berakhir, faktur yang belum kedaluwarsa tetap bisa dibayar dengan kurs saat pembayaran. Agar kedua tenggat sama, gunakan expires_in dalam rentang penguncian yang didukung, lalu bandingkan expiration_date dan rate_lock_until dalam respons.

getInvoices

GET /pay/api/getInvoices — scope read. Filter: asset, fiat, invoice_ids (dipisah koma), status (active / paid / expired — expired 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 seluruh atau sebagian kripto yang benar-benar dibayar dari saldo aplikasimu kepada pembayar. Ini juga berlaku bagi pembayar anonim tanpa membuka identitasnya. Untuk faktur fiat, gunakan paid_asset dan paid_amount; jumlah pengembalian tidak dihitung ulang berdasarkan nilai fiat.

ParameterTipeWajibKeterangan
invoice_idintegeryafaktur yang sudah dibayar
amountstringtidakjumlah kripto yang dikembalikan dalam aset pembayaran awal (paid_asset untuk faktur fiat). Dikosongkan = seluruh sisa yang belum dikembalikan. Total pengembalian sebagian tidak boleh melebihi jumlah kripto yang awalnya dibayar
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 seluruh dana faktur dikembalikan. Statusnya tetap paid. Biaya platform tidak ikut dikembalikan. Aplikasimu perlu saldo yang cukup dalam aset pembayaran awal, meski swap_to mengubah penerimaan menjadi aset lain. 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.