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). Diabaikan di mode kripto — untuk menetapkan harga dalam fiat, isi currency_type: "fiat" |
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, maksimal 512 karakter — wajib kalau paid_btn_name diisi, dan diabaikan kalau tidak |
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, saat ini juga 31 hari. 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(selalu dalam satuan terkecil kripto: di faktur kripto, nilai fakturnya; di faktur fiat,nullsampai dibayar lalu satuan terkecilpaid_asset; di faktur open-amount,nullsampai dibayar), dan di faktur fiat yang sudah dibayarpaid_asset/paid_amount/paid_fiat_rate— kripto yang benar-benar ditagih dan kurs yang dipakai. Di faktur fiat,assettetapnullbahkan setelah dibayar. - 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. - Waktu dan data pembayaran:
created_at,paid_at,paid_usd_rate(kurs USD yang dicatat saat pembayaran). - Sesuai saat dibuat:
currency_type,accepted_assets,open_amount,is_anonymous,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 (di mode kripto asset tidak diisi; di mode
fiat fiat tidak diisi, asset ikut dikirim, atau open_amount diisi),
400 invalid_amount (termasuk jumlah yang jadi nol pada presisi aset),
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).
400 invalid_request berarti parameternya tidak valid: currency_type atau
paid_btn_name yang tidak dikenal, teks yang melebihi panjang maksimalnya,
expires_in di luar 0–2678400, atau jumlah yang dikirim sebagai angka JSON.
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. Parameter menerima 0 sampai 86400 detik: 0 berarti tanpa penguncian kurs. Nilai lain disesuaikan dengan rentang yang didukung, minimal 60 detik dan maksimal sesuai batas platform. Nilai di luar 0–86400 ditolak dengan 400 invalid_request. 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 (bawaan 100, maksimal 1000). Mengembalikan
{"items": [invoice, …]}, diurutkan dari yang terbaru.
deleteInvoice
POST /pay/api/deleteInvoice — scope invoices. Satu parameter:
invoice_id. Menghapus faktur yang belum dibayar — aktif atau sudah
kedaluwarsa — dan mengembalikan true. Fakturnya benar-benar dihapus, bukan
sekadar ditandai: faktur itu hilang dari getInvoices, pay_url-nya tidak
berfungsi lagi, dan tidak ada webhook yang dikirim. Kalau kamu perlu jejak
penghapusannya, catat di sistemmu sendiri. Error: 404 invoice_not_found, 409 invoice_already_paid —
faktur yang sudah dibayar tidak bisa dihapus karena 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, 400 invalid_request
(invoice_id tidak diisi atau spend_id lebih dari 64 karakter),
403 verification_required (transaksi keluar dari akun pemilik dibatasi),
503 merchant_payouts_paused, dan pasangan spend_id
409 idempotency_conflict / 409 idempotency_in_progress.
Artikel ini membantu?
Terima kasih atas masukannya.