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 = tidak pernah |
rate_lock_seconds | integer | tidak | ekstensi, 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 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 faktur dikembalikan sepenuhnya. - 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, 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 / 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 nilai faktur yang sudah dibayar
— atau sebagiannya — dari saldo aplikasimu ke siapa pun yang membayarnya,
termasuk pembayar anonim, tanpa membuka siapa mereka.
| Parameter | Tipe | Wajib | Keterangan |
|---|---|---|---|
invoice_id | integer | ya | faktur yang sudah dibayar |
amount | string | tidak | jumlah yang dikembalikan, dalam aset faktur itu. Dikosongkan = seluruh sisa yang belum dikembalikan. Pengembalian sebagian menumpuk sampai nilai penuh faktur |
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 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.
Artikel ini membantu?
Terima kasih atas masukannya.