Referensi API: faktur dan pengembalian dana
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.
| Parameter | Tipe | Wajib | Keterangan |
|---|---|---|---|
currency_type | string | tidak | crypto (bawaan) atau fiat |
asset | string | mode crypto | aset yang ditagih, misalnya USDT. Tidak boleh dipakai bersama fiat |
fiat | string | mode fiat | mata uang fiat yang dipakai untuk harganya (baris is_fiat dari getCurrencies) |
accepted_assets | string / array | tidak | khusus mode fiat: aset yang boleh dipakai pembayar — string dipisah koma ("USDT,GRAM") atau array JSON. Dikosongkan = semua aset yang didukung |
amount | string | ya, kecuali open_amount diisi | string desimal positif: satuan aset di mode crypto, satuan fiat (maksimal 2 angka di belakang koma) di mode fiat |
open_amount | boolean | tidak | ekstensi, khusus mode crypto: tanpa jumlah tetap — pembayar yang mengisinya saat membayar (donasi dan tip). Tidak bisa dipakai bersama amount |
description | string | tidak | maksimal 1024 karakter, ditampilkan ke pembayar |
hidden_message | string | tidak | maksimal 2048 karakter, baru terlihat oleh pembayar setelah pembayaran |
payload | string | tidak | maksimal 4096 karakter data milikmu sendiri, dikirim balik di objek faktur dan di webhook |
allow_comments | boolean | tidak | izinkan pembayar menyertakan komentar (bawaan true) |
allow_anonymous | boolean | tidak | izinkan pembayar menyembunyikan identitasnya (bawaan true) |
paid_btn_name | string | tidak | tombol setelah pembayaran: viewItem, openChannel, openBot, atau callback |
paid_btn_url | string | tidak | URL http(s) tombol itu — wajib kalau paid_btn_name diisi |
swap_to | string | tidak | tukar otomatis pembayaran yang masuk ke aset ini. Sifatnya best-effort: kalau penukaran tidak bisa jalan saat pembayaran, pembayarannya tetap berhasil tanpa ditukar |
expires_in | integer | tidak | detik sampai faktur kedaluwarsa, maksimal 2678400 (31 hari); dikosongkan atau 0 = masa berlaku bawaan. Baca expiration_date dari hasilnya |
rate_lock_seconds | integer | tidak | ekstensi, 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 dalampay_url),status(active/paid/expired),pay_url— linkt.meyang kamu kirim ke pembayar (bot_invoice_url,mini_app_invoice_url,web_app_invoice_urladalah aliasnya). - Jumlah:
amount(nilai faktur — satuan fiat di faktur fiat, kripto di selainnya;nullselama faktur open-amount belum dibayar),amount_minor, dan di faktur fiat yang sudah dibayarpaid_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 (feedanusd_rateadalah alias Crypto Bot yang sudah usang). Lihat biaya dan batas. - Pembayar:
paid_by_user_id(nullkalau pembayar memilih anonim),paid_anonymously,comment. - Pengembalian dana (ekstensi):
refunded_amount/refunded_minor(kumulatif) danrefunded_at, dicatat begitu seluruh dana faktur dikembalikan. - Penguncian kurs (ekstensi):
rate_lock_untildanrate_lock_rates— kurs per aset yang disimpan,nullkalau tidak ada penguncian yang diminta. - Sesuai saat dibuat:
description,hidden_message,payload,paid_btn_name/paid_btn_url,expiration_date(expires_atadalah 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.
| Parameter | Tipe | Wajib | Keterangan |
|---|---|---|---|
invoice_id | integer | ya | faktur yang sudah dibayar |
amount | string | tidak | jumlah 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_id | string | tidak | kunci 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.
Artikel ini membantu?
Terima kasih atas masukannya.