Masuk Daftar Mitra
API v1

H2H IndoTopup API

Dokumentasi H2H Partner API: cari produk, buat order, dan ikuti hasilnya. Semua contoh memakai data fiktif; ganti SKU dengan SKU dari katalog akunmu.

Base URLhttps://h2h.indotopup.com/api/v1

Mulai cepat

  1. Daftar, buka menu Kunci & Webhook di dashboard, lalu buat kunci uji (itp_test_…). Salin nilainya: hanya tampil sekali.
  2. Tes koneksi dengan GET /account.
  3. Ambil katalog lewat GET /catalog/products, pilih code produk.
  4. Buat order dengan POST /orders memakai kunci uji. Setelah yakin, pindahkan akun ke Produksi, daftarkan IP server, dan ganti ke kunci live (itp_live_…).

Autentikasi & batas

Satu token Bearer per kunci: kirim header Authorization: Bearer <kunci> di setiap request (selain /lookups/games dan /lookups/quota). Kunci uji dan kunci live adalah dua token berbeda; jangan taruh keduanya di kode browser publik.

  • itp_test_… mensimulasikan order dan webhook, tidak memotong saldo, bebas dari IP mana pun.
  • itp_live_… order sungguhan. Hanya aktif bila akun di mode Produksi, dan hanya menerima request dari IP/CIDR yang kamu daftarkan (kosong = semua IP).
  • Batas request per menit mengikuti level akun, dilaporkan di header RateLimit-Limit, RateLimit-Remaining, dan RateLimit-Reset. Respons 429 menyertakan Retry-After. Endpoint katalog dibatasi 30 request/menit.
  • Semua respons berupa JSON. Waktu memakai ISO 8601 UTC, nilai uang berupa bilangan bulat Rupiah.

Mode uji (test)

Order dengan kunci uji selesai dalam beberapa detik dengan serial SBX-… dan mengirim webhook seperti biasa. Target yang berakhiran 9999 mensimulasikan kegagalan. Order dari dashboard selalu live.

Status, refund & idempotensi

  • Status order: queued → processing → succeeded atau failed. HTTP 201 hanya berarti order diterima; tunggu webhook atau ambil GET /orders/{id}.
  • reference wajib unik per order. Saat timeout atau 5xx, kirim ulang request yang sama dengan reference yang sama: kamu menerima order asli (HTTP 200 + header Idempotent-Replay: true), tanpa potongan ganda. Header Idempotency-Key diterima sebagai pengganti.
  • Order gagal mengembalikan seluruh dana yang ditahan ke saldo secara otomatis. Dengan max_price, biaya akhir tidak pernah melebihi batas dan sisanya dikembalikan.

Webhook

Isi Webhook URL di dashboard. Kami mengirim POST JSON saat order API selesai (order.succeeded atau order.failed), dan order.verification_required saat order butuh kode. Pesanan dari dashboard tidak mengirim webhook. Amplop event:

Verifikasi tanda tangan

Header H2H-Signature berbentuk t=<unix>,v1=<hex>. Hitung HMAC-SHA256 dari string "<t>.<body mentah>" dengan rahasia webhook, bandingkan memakai perbandingan waktu-konstan, dan tolak bila t lebih tua dari 5 menit. Balas HTTP 2xx. Bila gagal, kami mencoba lagi setelah 1 menit, 5 menit, 15 menit, 1 jam, dan 6 jam. Deduplikasi dengan id event.

Galat

Semua galat berbentuk { "error": { "code": "…", "message": "…", "fields": { … } } }. Gunakan error.code untuk logika program, bukan teks pesan.

HTTPerror.codeArti
400bad_requestBody bukan JSON yang valid.
401unauthorized / invalid_keyHeader Authorization: Bearer <kunci> hilang atau kunci tidak dikenal.
402insufficient_balanceSaldo tidak cukup untuk menahan biaya order (atau cek pemain berbayar).
403live_not_enabled / ip_not_allowed / account_suspendedKunci live dipakai saat akun belum Produksi, IP belum terdaftar, atau akun ditangguhkan.
404not_foundOrder, batch, produk, atau endpoint tidak ditemukan atau bukan milikmu.
409conflictReference dipakai dengan isi berbeda, invoice belum tersedia, atau aksi verifikasi usang.
422validation_failed / product_not_found / max_price_too_low / product_out_of_stockIsian tidak valid. Rincian per kolom ada di error.fields.
429rate_limited / quota_exceededBatas request atau jatah cek terlampaui. Tunggu sesuai header Retry-After.
500server_errorGalat di sisi kami. Aman mengulang dengan reference yang sama.
502provider_unavailableLayanan cek pemain sementara tidak tersedia (tidak memakai jatah).

Akun

GET/api/v1/account

Info akun

Profil, mode kunci yang dipakai (test/live), saldo, level, dan batas. Cara tercepat memastikan kunci dan IP kamu benar.

Contoh request

Contoh respons

200401403429

Katalog

GET/api/v1/catalog/brands

Daftar brand

Brand yang punya produk. Dibatasi 30 request/menit untuk semua endpoint katalog; simpan katalog di sisimu dan sinkronkan berkala.

Query

NamaTipeKeterangan
type stringstandard | fallback

Contoh request

Contoh respons

200401403422429
GET/api/v1/catalog/products

Daftar produk

Produk dengan harga untuk level akunmu dan field isian yang menempel (fields). Produk fallback (type=fallback) wajib memakai max_price saat dipesan.

Query

NamaTipeKeterangan
brand stringID atau slug brand.
type stringstandard | fallback
q stringCari nama produk.
limit integerJumlah item (1–200).
after stringSalin paging.next_after dari halaman sebelumnya.

Contoh request

Contoh respons

200401403422429
GET/api/v1/catalog/products/{code}

Detail produk

Satu produk berdasarkan kode.

Path

NamaTipeKeterangan
code *stringKode produk, mis. P12319.

Contoh request

Contoh respons

200401403404429

Order

POST/api/v1/orders

Buat order

Membuat satu order. 201 berarti order diterima; lihat status untuk hasilnya (queued → processing → succeeded / failed). reference adalah kunci idempotensimu: bila respons tidak pasti, kirim ulang request yang sama dan kamu menerima order asli (200 + header Idempotent-Replay: true), bukan order baru. Header Idempotency-Key diterima sebagai pengganti reference. Seluruh max_price (bila ada) ditahan di muka; sisa dikembalikan saat sukses, semuanya kembali saat gagal.

Body (JSON)

NamaTipeKeterangan
product *stringKode produk dari katalog (P… standar, F… fallback).
target.id *stringID pemain / nomor tujuan.
target.zone string|nullServer/zona bila produk meminta (pakai value opsi, bukan label).
target.extra object|nullIsian tambahan lain; kuncinya dari fields produk.
reference *stringReferensi unik milikmu, maks 64 karakter.
max_price integer|nullBatas biaya akhir (Rupiah). Wajib untuk produk fallback.

Contoh request

Contoh respons

201200400401402403422429
POST/api/v1/orders

Buat order fallback

Produk fallback (kode F…) mencoba jalur termurah dulu lalu pindah jalur bila gagal. Kirim max_price sebagai batas harga; biaya akhir tidak pernah melebihinya dan selisihnya dikembalikan.

Body (JSON)

NamaTipeKeterangan
product *stringKode produk fallback (F…).
target.id *stringID pemain.
target.zone string|nullServer/zona.
reference *stringReferensi unik.
max_price *integerBatas harga maksimal (≥ harga saat ini).

Contoh request

Contoh respons

201200400401402403422429
GET/api/v1/orders/{id}

Detail order

Ambil order lewat ID atau reference. serial berisi kode voucher/serial bila ada; failure terisi bila gagal (saldo dikembalikan otomatis).

Path

NamaTipeKeterangan
id *stringID order (ord_…) atau reference milikmu.

Contoh request

Contoh respons

200401403404429
GET/api/v1/orders

Daftar order

Order terbaru lebih dulu.

Query

NamaTipeKeterangan
status stringqueued | processing | succeeded | failed
mode stringtest | live
from stringTanggal/waktu awal (ISO 8601).
to stringTanggal/waktu akhir.
limit integerJumlah item (1–200).
after stringSalin paging.next_after dari halaman sebelumnya.

Contoh request

Contoh respons

200401403422429
POST/api/v1/orders/{id}/verification

Kirim kode verifikasi

Sebagian order meminta kode dari pembeli: order.verification.state = "required" dan can_submit = true. Kirim kodenya di sini. 202 hanya berarti kode diterima untuk diproses, bukan bukti valid. Kode sama dikirim ulang mengembalikan hasil sebelumnya; kode berbeda ditolak 409. Batas 5 request/menit per order.

Path

NamaTipeKeterangan
id *stringID order (ord_…) atau reference milikmu.

Body (JSON)

NamaTipeKeterangan
code *stringKode dari pembeli, 1–128 karakter.
action_id stringverification.id terbaru.
version integerverification.version terbaru.

Contoh request

Contoh respons

202401403404409422429

Batch

POST/api/v1/batches

Buat batch

Satu produk standar, satu tujuan, 1–100 order berurutan. Seluruh biaya dipotong di muka dan harga dikunci. reference unik; kirim ulang request identik mengembalikan batch asli, request berbeda dengan reference sama ditolak 409.

Body (JSON)

NamaTipeKeterangan
product *stringKode produk dari katalog (P… standar, F… fallback).
target.id *stringID pemain / nomor tujuan.
target.zone string|nullServer/zona bila produk meminta (pakai value opsi, bukan label).
target.extra object|nullIsian tambahan lain; kuncinya dari fields produk.
reference *stringReferensi batch unik.
count *integerJumlah order, 1–100.

Contoh request

Contoh respons

201200401402403409422429
GET/api/v1/batches

Daftar batch

Batch terbaru lebih dulu.

Query

NamaTipeKeterangan
status stringqueued | processing | completed | partially_failed | failed
from stringAwal (ISO 8601).
to stringAkhir.
limit integerJumlah item (1–200).
after stringSalin paging.next_after dari halaman sebelumnya.

Contoh request

Contoh respons

200401403422429
GET/api/v1/batches/{id}

Progres batch

Status dan hitungan progres.

Path

NamaTipeKeterangan
id *stringID batch (bat_…) atau reference milikmu.

Contoh request

Contoh respons

200401403404429
GET/api/v1/batches/{id}/orders

Order di dalam batch

Order anak berurutan (field sequence), masing-masing dengan ID sendiri.

Path

NamaTipeKeterangan
id *stringID batch (bat_…) atau reference milikmu.

Query

NamaTipeKeterangan
limit integerJumlah item (1–200).
after stringSalin paging.next_after dari halaman sebelumnya.

Contoh request

Contoh respons

200401403404429
GET/api/v1/batches/{id}/invoice

Invoice batch (PDF)

Satu PDF ringkasan biaya dan refund setelah semua order selesai. 409 bila belum selesai atau batch uji. Respons sukses berupa berkas application/pdf.

Path

NamaTipeKeterangan
id *stringID batch (bat_…) atau reference milikmu.

Contoh request

200401403404409429

Cek Pemain

GET/api/v1/lookups/gamespublik

Game yang bisa dicek

Daftar kode game dan kebutuhan zona. Publik, tanpa kunci.

Contoh request

Contoh respons

200429
GET/api/v1/lookups/quotapublik

Jatah & tarif cek pemain

Jatah gratis harian dan tarif tambahan. Publik. Cek pemain dan cek batas pembelian memakai jatah yang sama; reset pukul 00:00 UTC.

Contoh request

Contoh respons

200429
POST/api/v1/lookups/player

Cek nama pemain

Validasi ID pemain sebelum order. Hasil ditemukan maupun tidak ditemukan memakai jatah. 404 akun tidak ada, 402 saldo kurang untuk cek berbayar, 429 jatah habis.

Body (JSON)

NamaTipeKeterangan
game *stringKode game dari /lookups/games.
id *stringID akun pemain.
zone string|nullServer/zona bila diwajibkan.

Contoh request

Contoh respons

200401402403404422429502
POST/api/v1/lookups/purchase-limit/mobile-legends

Batas pembelian Mobile Legends

Cek apakah paket mingguan/double diamond sudah mencapai batas pembelian. Memakai jatah yang sama dengan cek pemain.

Body (JSON)

NamaTipeKeterangan
id *stringID akun.
zone *stringZona.

Contoh request

Contoh respons

200401402403404422429502

Webhook

POST/api/v1/webhooks/test

Kirim webhook uji

Mengirim event webhook.test bertanda tangan ke Webhook URL-mu, supaya penerimamu bisa diuji tanpa membuat order. Isi Webhook URL dan buat rahasia webhook di dashboard terlebih dulu.

Contoh request

Contoh respons

200401403422429