Melostore H2H · API v1
Dokumentasi H2H API
Mulai integrasi, pilih produk, dan ikuti hasil setiap pesanan.
Base URL https://api.melostore.id/api/v1/h2h
Import OpenAPI atau Postman, lalu isi environment dengan kredensial Anda. Contoh order memakai sandbox.
Mulai integrasi
Base URL: https://api.melostore.id/api/v1/h2h. Semua contoh menggunakan data fiktif; SKU contoh harus diganti dari katalog akun Anda. Tidak ada endpoint pengenalan atau autentikasi terpisah: gunakan GET /profile untuk memeriksa akses.
Di menu API Credentials dashboard, klik Rotate Keys untuk membuat API Key, Secret Key, dan Webhook Secret. Ketiganya ditampilkan sekali pada modal hasil generate; simpan sebelum menutup modal. Rotate Keys berikutnya langsung mengganti ketiganya, sehingga kredensial API dan secret pada server penerima webhook perlu diperbarui.
Import salah satu koleksi di bawah, pilih environment, isi api_key dan secret_key dari hasil generate, lalu ambil SKU aktif dari katalog reguler atau Smart. Pertahankan buyer_trx_id/buyer_bulk_id saat mengulang request yang belum mendapat respons. Simpan ID hasil create untuk cek status.
Contoh create reguler, Smart, dan bulk memakai sandbox_mode=true. Sandbox mensimulasikan proses/history/callback tanpa debit atau invoice finansial/email. Order dashboard selalu live. Pemeriksaan akun mengikuti mode akun dan billingnya sendiri; sandbox_mode pada create bukan pengaturan untuk pemeriksaan akun.
Autentikasi, IP, dan rate limit
Kirim Accept: application/json agar galat validasi dikembalikan sebagai JSON; invoice berhasil tetap memakai Content-Type application/pdf. Kirim X-API-Key dan X-Secret-Key bersama pada endpoint terautentikasi. Kredensial berasal dari dashboard; jangan menaruhnya di browser publik. GET /check-nickname/games dan GET /check-nickname/plan tidak memerlukan header ini. Akun harus aktif dan tidak ditangguhkan.
Jika Anda menggunakan whitelist IP, daftarkan IP publik server integrasi melalui dashboard sebelum mengirim pesanan live. HTTP 403 dapat menunjukkan akses akun atau IP tidak diizinkan; periksa pengaturan akun dan IP server Anda.
Batas umum mengikuti tier, terlihat pada X-RateLimit-Limit dan X-RateLimit-Remaining. Endpoint katalog reguler/Smart/kategori juga berbagi batas 20 request/menit per profil. Pemeriksaan akun memakai X-Nickname-RateLimit-Limit dan X-Nickname-RateLimit-Remaining. Jika HTTP 429 memuat Retry-After, tunggu sejumlah detik itu; kuota harian kembali pukul 00.00 UTC.
Profil
/api/v1/h2h/profileProfil dan tier terautentikasi. Saldo tetap MC/IDR; USD hanya perkiraan.
Dua header: X-API-Key dan X-Secret-Key
Parameter
Tanpa parameter.
curl -X GET 'https://api.melostore.id/api/v1/h2h/profile' \
-H 'Accept: application/json' \
-H "X-API-Key: $H2H_API_KEY" \
-H "X-Secret-Key: $H2H_SECRET_KEY"Request berhasil.
{
"success": true,
"data": {
"id": "11111111-1111-4111-8111-111111111111",
"name": "Example Partner",
"email": "[email protected]",
"tier": {
"name": "Basic",
"code": "basic",
"rate_limit": 30,
"max_ips": 3
},
"h2h_balance": 100000,
"is_sandbox_mode": true,
"total_volume_30_days": 5000,
"webhook_url": "https://partner.example.com/h2h-callback",
"created_at": "2026-10-02T03:00:00+00:00",
"usd_idr_rate": 17000,
"display_usd_idr_rate": 17000,
"display_rate_updated_at": "2026-10-02T03:00:00+00:00"
}
}successbooleanWajibdataobjectWajibdata.idstringWajibdata.namestringWajibdata.emailstringWajibdata.tierobjectWajibdata.tier.namestringWajibdata.tier.codestringWajibdata.tier.rate_limitintegerWajibdata.tier.max_ipsintegerWajibdata.h2h_balancenumberWajibdata.is_sandbox_modebooleanWajibdata.total_volume_30_daysnumberWajibdata.webhook_urlstring | nullWajibdata.created_atstringWajibdata.usd_idr_ratenumberWajib- Configured deposit conversion rate; separate from the reference display rate.
data.display_usd_idr_ratenumber | nullWajibdata.display_rate_updated_atstring | nullWajib- Last reference FX update, or null when a valid reference rate is unavailable.
Saldo dan kurs
/api/v1/h2h/profile/balanceKurs tampilan terpisah dari kurs deposit. Perkiraan USD null saat kurs belum tersedia.
Dua header: X-API-Key dan X-Secret-Key
Parameter
Tanpa parameter.
curl -X GET 'https://api.melostore.id/api/v1/h2h/profile/balance' \
-H 'Accept: application/json' \
-H "X-API-Key: $H2H_API_KEY" \
-H "X-Secret-Key: $H2H_SECRET_KEY"Request berhasil.
{
"success": true,
"data": {
"h2h_balance": 100000,
"is_sandbox_mode": true,
"usd_idr_rate": 17000,
"display_usd_idr_rate": 17000,
"display_rate_updated_at": "2026-10-02T03:00:00+00:00",
"h2h_balance_usd": 5.88
}
}successbooleanWajibdataobjectWajibdata.h2h_balancenumberWajibdata.is_sandbox_modebooleanWajibdata.usd_idr_ratenumberWajib- Configured deposit conversion rate; separate from the reference display rate.
data.display_usd_idr_ratenumber | nullWajibdata.display_rate_updated_atstring | nullWajib- Last reference FX update, or null when a valid reference rate is unavailable.
data.h2h_balance_usdnumber | nullWajib
Ambil harga per brand
1. Ambil GET /pricelists/categories untuk brand reguler, atau GET /smart-pricelists/categories untuk brand Smart. Setiap record adalah brand, dilengkapi category sebagai objek kategori induk dan type sebagai daftar tipe anak. Urutan berdasarkan ID kategori induk naik, lalu nama brand A–Z.
2. Pilih brand dari data[]. Gunakan brand_id sebagai filter: GET /pricelists?brand_id=10&limit=500 atau GET /smart-pricelists?brand_id=10&limit=500. Ganti 10 dengan brand_id dari respons Anda. Field brand_id menggantikan id pada daftar brand; sesuaikan pembacaan field pada integrasi Anda.
3. Alternatif tanpa ID: gunakan slug brand pada /pricelists/{category_slug} atau /smart-pricelists/{category_slug}. Gunakan slug persis dari daftar brand katalog yang sama, jangan menebaknya dari nama game.
meta.brands hanya memuat brand pada halaman harga yang sedang dibaca. Untuk daftar lengkap, gunakan endpoint daftar brand. Brand yang terdaftar dapat memiliki produk out_of_stock; pesan hanya produk active.
category bernilai null jika brand tidak memiliki kategori induk; brand tersebut tampil di akhir. type berisi semua tipe anak langsung, diurutkan menurut nama A–Z, atau [] jika tidak ada. Adanya tipe tidak menjamin produk tersedia pada katalog yang dipilih.
Kenali SKU, server, dan form
sku_code adalah kode produk reguler untuk /transaction dan bulk. smart_sku_code adalah kode produk Smart; kirim nilainya pada field sku_code ke /smart-transaction. Keduanya berasal dari katalog, bukan dari kode game pemeriksaan akun.
brand_id dan slug berasal dari daftar brand. server_code menunjukkan kelompok produk pada katalog; customer_target_zone adalah zone/server akun pembeli sesuai form produk. Nilainya tidak harus sama.
Pada katalog reguler, server boleh tidak dikirim atau kosong untuk mengambil semua server. format boleh tidak dikirim atau kosong untuk memakai compact; pilih legacy jika memerlukan inquiry_fields langsung pada setiap produk tanpa pagination.
Cari inquiry_form_key produk di meta.inquiry_forms pada halaman yang sama. Isi customer_target dari field pertama, customer_target_zone dari field kedua bila ada, dan additional_data untuk field berikutnya memakai key form. Untuk pilihan, kirim value yang tersedia, bukan label. Baca notice.id atau notice.en jika ada petunjuk tambahan.
game_code khusus pemeriksaan akun dan berasal dari games[].game_code pada GET /check-nickname/games. Pemeriksaan akun tidak menjamin semua SKU dengan nama game serupa mempunyai zone atau ketentuan yang sama.
Pagination dan data pelanggan
Ambil katalog dengan limit=500. Gunakan meta.pagination.next_cursor sebagai cursor pada request berikutnya dan lanjutkan sampai meta.pagination.has_more=false. Nilai limit yang tersedia adalah 1–1000; gunakan maksimal 500 per halaman. Panduan ini berlaku untuk katalog reguler dan Smart.
Ikuti form produk yang dipilih untuk mengisi data pelanggan. Pada format compact, gunakan inquiry_form_key untuk menemukan form di meta.inquiry_forms. Isi customer_target dari field pertama, customer_target_zone dari field kedua jika diperlukan, dan additional_data untuk field lainnya sesuai key pada form. Pada format legacy reguler, form tersedia langsung di inquiry_fields.
Satu request reguler atau Smart membuat satu pesanan. Untuk memesan SKU reguler berulang kali ke target yang sama, gunakan bulk dengan order_count (1–100). Pesanan bulk diproses satu per satu sesuai urutan.
Katalog reguler
/api/v1/h2h/pricelistsHarga sesuai tier akun Anda. Pilih sku_code aktif untuk POST /transaction. Gunakan bulk dengan order_count untuk pesanan berulang. Untuk satu brand, gunakan brand_id dari daftar brand katalog ini atau slug brand pada path. Ikuti next_cursor sampai has_more=false.
Dua header: X-API-Key dan X-Secret-Key
Parameter
| Nama | Tipe / sumber | Wajib | Keterangan |
|---|---|---|---|
| limit | integer · query | Opsional | Jumlah produk per halaman, 1–1000. Gunakan 500 untuk sinkronisasi. Tanpa limit, respons reguler berisi seluruh hasil; kirim limit untuk pagination. min=1 max=1000 |
| cursor | string · query | Opsional | Salin meta.pagination.next_cursor dari halaman sebelumnya. Pertahankan filter yang sama selama pagination. |
| server | string · query | Opsional | server_code produk dari katalog, bukan zone akun pelanggan. Tidak dikirim atau kosong berarti semua server katalog. |
| format | compact | legacy · query | Opsional | Tidak dikirim atau kosong memakai compact. legacy menyertakan inquiry_fields langsung dan mengembalikan semua hasil tanpa pagination cursor. |
| brand_id | integer · query | Opsional | Filter memakai data[].brand_id dari daftar brand katalog yang sama. Kosongkan untuk mengambil semua brand. min=1 |
curl -X GET 'https://api.melostore.id/api/v1/h2h/pricelists?limit=500' \
-H 'Accept: application/json' \
-H "X-API-Key: $H2H_API_KEY" \
-H "X-Secret-Key: $H2H_SECRET_KEY"Request berhasil.
{
"success": true,
"data": [
{
"name": "Example product",
"sku_code": "EXAMPLE-10",
"price": 1000,
"category_name": "Example category",
"brand_id": 10,
"type_name": "Example type",
"category_order": 1,
"type_order": 1,
"server_code": "global",
"server_name": "Global",
"status": "active",
"inquiry_form_key": "example-form",
"h2h_description": null,
"description": null,
"id": 1
}
],
"meta": {
"brands": [
{
"id": 10,
"name": "Example brand",
"thumbnail": null,
"order": 1
}
],
"inquiry_forms": {
"example-form": {
"fields": [
{
"key": "customer_target",
"name": "Player ID",
"type": "text"
},
{
"key": "customer_target_zone",
"name": "Zone",
"type": "text"
}
],
"notice": {
"id": "Masukkan ID dan zone sesuai akun pembeli.",
"en": "Enter the ID and zone from the buyer account."
}
}
},
"pagination": {
"cursor": null,
"next_cursor": null,
"limit": 100,
"total": 1,
"has_more": false
}
}
}successbooleanWajibdataarrayWajibdata[].namestringWajibdata[].sku_codestringWajibdata[].pricenumberWajibdata[].category_namestringWajibdata[].brand_idinteger | nullWajib- ID brand; daftar lengkap tersedia pada endpoint categories katalog yang sama.
data[].type_namestringWajibdata[].category_orderintegerWajibdata[].type_orderintegerWajibdata[].server_codestring | nullWajib- Server produk pada katalog, terpisah dari customer_target_zone.
data[].server_namestring | nullWajibdata[].statusactive | out_of_stockWajib- Pesan hanya produk active. out_of_stock berarti tidak tersedia.
data[].inquiry_form_keystring- Cari key ini pada meta.inquiry_forms di halaman yang sama.
data[].h2h_descriptionstring | nullWajibdata[].descriptionstring | nullWajibdata[].idintegermetaobjectmeta.brandsarray- Metadata brand pada halaman ini saja. Gunakan endpoint categories untuk daftar lengkap.
meta.brands[].idintegermeta.brands[].namestring | nullmeta.brands[].thumbnailstring | nullmeta.brands[].orderinteger | nullmeta.inquiry_formsobject / array- Form input produk berdasarkan inquiry_form_key. Hasil kosong dapat berupa {} atau [].
meta.inquiry_forms.{key}.fieldsarraymeta.inquiry_forms.{key}.fields[].keystringmeta.inquiry_forms.{key}.fields[].namestringmeta.inquiry_forms.{key}.fields[].typestringmeta.inquiry_forms.{key}.fields[].requiredboolean- Apakah field wajib diisi oleh pembeli.
meta.inquiry_forms.{key}.fields[].optionsarray- Untuk pilihan, tampilkan label dan kirim value.
meta.inquiry_forms.{key}.fields[].options[].labelstringmeta.inquiry_forms.{key}.fields[].options[].valuestring | numbermeta.inquiry_forms.{key}.fields[].placeholderstring | nullmeta.inquiry_forms.{key}.noticeobject | null- Petunjuk berdasarkan bahasa. Baca notice.id atau notice.en; null jika tidak ada.
meta.inquiry_forms.{key}.notice.idstringmeta.inquiry_forms.{key}.notice.enstringmeta.paginationobject- Ikuti next_cursor selama has_more=true. Pada respons reguler, objek ini muncul saat limit dikirim.
meta.pagination.cursorstring | nullmeta.pagination.next_cursorstring | nullmeta.pagination.limitintegermeta.pagination.totalintegermeta.pagination.has_morebooleancategoryobjectcategory.namestringWajibcategory.slugstringWajibdata[].inquiry_fieldsobject- Disertakan langsung hanya pada format legacy reguler.
data[].inquiry_fields.fieldsarraydata[].inquiry_fields.fields[].keystringdata[].inquiry_fields.fields[].namestringdata[].inquiry_fields.fields[].typestringdata[].inquiry_fields.fields[].requiredboolean- Apakah field wajib diisi oleh pembeli.
data[].inquiry_fields.fields[].optionsarray- Untuk pilihan, tampilkan label dan kirim value.
data[].inquiry_fields.fields[].options[].labelstringdata[].inquiry_fields.fields[].options[].valuestring | numberdata[].inquiry_fields.fields[].placeholderstring | nulldata[].inquiry_fields.noticeobject | null- Petunjuk berdasarkan bahasa. Baca notice.id atau notice.en; null jika tidak ada.
data[].inquiry_fields.notice.idstringdata[].inquiry_fields.notice.enstringdata[].brand_namestring | null- Disertakan langsung hanya pada format legacy reguler.
data[].brand_orderinteger | null- Disertakan langsung hanya pada format legacy reguler.
data[].brand_thumbnailstring | null- Disertakan langsung hanya pada format legacy reguler.
Harga reguler per brand
/api/v1/h2h/pricelists/{category_slug}Harga sesuai tier akun Anda. Pilih sku_code aktif untuk POST /transaction. Gunakan bulk dengan order_count untuk pesanan berulang. Untuk satu brand, gunakan brand_id dari daftar brand katalog ini atau slug brand pada path. Ikuti next_cursor sampai has_more=false.
Dua header: X-API-Key dan X-Secret-Key
Parameter
| Nama | Tipe / sumber | Wajib | Keterangan |
|---|---|---|---|
| category_slug | string · path | Wajib | Slug brand dari data[].slug pada daftar brand katalog yang sama. Slug kategori/tipe lama tetap didukung. |
| limit | integer · query | Opsional | Jumlah produk per halaman, 1–1000. Gunakan 500 untuk sinkronisasi. Tanpa limit, respons reguler berisi seluruh hasil; kirim limit untuk pagination. min=1 max=1000 |
| cursor | string · query | Opsional | Salin meta.pagination.next_cursor dari halaman sebelumnya. Pertahankan filter yang sama selama pagination. |
| server | string · query | Opsional | server_code produk dari katalog, bukan zone akun pelanggan. Tidak dikirim atau kosong berarti semua server katalog. |
| format | compact | legacy · query | Opsional | Tidak dikirim atau kosong memakai compact. legacy menyertakan inquiry_fields langsung dan mengembalikan semua hasil tanpa pagination cursor. |
| brand_id | integer · query | Opsional | Filter memakai data[].brand_id dari daftar brand katalog yang sama. Kosongkan untuk mengambil semua brand. min=1 |
curl -X GET 'https://api.melostore.id/api/v1/h2h/pricelists/example-brand?limit=500' \
-H 'Accept: application/json' \
-H "X-API-Key: $H2H_API_KEY" \
-H "X-Secret-Key: $H2H_SECRET_KEY"Request berhasil.
{
"success": true,
"data": [
{
"name": "Example product",
"sku_code": "EXAMPLE-10",
"price": 1000,
"category_name": "Example category",
"brand_id": 10,
"type_name": "Example type",
"category_order": 1,
"type_order": 1,
"server_code": "global",
"server_name": "Global",
"status": "active",
"inquiry_form_key": "example-form",
"h2h_description": null,
"description": null,
"id": 1
}
],
"meta": {
"brands": [
{
"id": 10,
"name": "Example brand",
"thumbnail": null,
"order": 1
}
],
"inquiry_forms": {
"example-form": {
"fields": [
{
"key": "customer_target",
"name": "Player ID",
"type": "text"
},
{
"key": "customer_target_zone",
"name": "Zone",
"type": "text"
}
],
"notice": null
}
},
"pagination": {
"cursor": null,
"next_cursor": null,
"limit": 100,
"total": 1,
"has_more": false
}
},
"category": {
"name": "Example brand",
"slug": "example-brand"
}
}successbooleanWajibdataarrayWajibdata[].namestringWajibdata[].sku_codestringWajibdata[].pricenumberWajibdata[].category_namestringWajibdata[].brand_idinteger | nullWajib- ID brand; daftar lengkap tersedia pada endpoint categories katalog yang sama.
data[].type_namestringWajibdata[].category_orderintegerWajibdata[].type_orderintegerWajibdata[].server_codestring | nullWajib- Server produk pada katalog, terpisah dari customer_target_zone.
data[].server_namestring | nullWajibdata[].statusactive | out_of_stockWajib- Pesan hanya produk active. out_of_stock berarti tidak tersedia.
data[].inquiry_form_keystring- Cari key ini pada meta.inquiry_forms di halaman yang sama.
data[].h2h_descriptionstring | nullWajibdata[].descriptionstring | nullWajibdata[].idintegermetaobjectmeta.brandsarray- Metadata brand pada halaman ini saja. Gunakan endpoint categories untuk daftar lengkap.
meta.brands[].idintegermeta.brands[].namestring | nullmeta.brands[].thumbnailstring | nullmeta.brands[].orderinteger | nullmeta.inquiry_formsobject / array- Form input produk berdasarkan inquiry_form_key. Hasil kosong dapat berupa {} atau [].
meta.inquiry_forms.{key}.fieldsarraymeta.inquiry_forms.{key}.fields[].keystringmeta.inquiry_forms.{key}.fields[].namestringmeta.inquiry_forms.{key}.fields[].typestringmeta.inquiry_forms.{key}.fields[].requiredboolean- Apakah field wajib diisi oleh pembeli.
meta.inquiry_forms.{key}.fields[].optionsarray- Untuk pilihan, tampilkan label dan kirim value.
meta.inquiry_forms.{key}.fields[].options[].labelstringmeta.inquiry_forms.{key}.fields[].options[].valuestring | numbermeta.inquiry_forms.{key}.fields[].placeholderstring | nullmeta.inquiry_forms.{key}.noticeobject | null- Petunjuk berdasarkan bahasa. Baca notice.id atau notice.en; null jika tidak ada.
meta.inquiry_forms.{key}.notice.idstringmeta.inquiry_forms.{key}.notice.enstringmeta.paginationobject- Ikuti next_cursor selama has_more=true. Pada respons reguler, objek ini muncul saat limit dikirim.
meta.pagination.cursorstring | nullmeta.pagination.next_cursorstring | nullmeta.pagination.limitintegermeta.pagination.totalintegermeta.pagination.has_morebooleancategoryobjectcategory.namestringWajibcategory.slugstringWajibdata[].inquiry_fieldsobject- Disertakan langsung hanya pada format legacy reguler.
data[].inquiry_fields.fieldsarraydata[].inquiry_fields.fields[].keystringdata[].inquiry_fields.fields[].namestringdata[].inquiry_fields.fields[].typestringdata[].inquiry_fields.fields[].requiredboolean- Apakah field wajib diisi oleh pembeli.
data[].inquiry_fields.fields[].optionsarray- Untuk pilihan, tampilkan label dan kirim value.
data[].inquiry_fields.fields[].options[].labelstringdata[].inquiry_fields.fields[].options[].valuestring | numberdata[].inquiry_fields.fields[].placeholderstring | nulldata[].inquiry_fields.noticeobject | null- Petunjuk berdasarkan bahasa. Baca notice.id atau notice.en; null jika tidak ada.
data[].inquiry_fields.notice.idstringdata[].inquiry_fields.notice.enstringdata[].brand_namestring | null- Disertakan langsung hanya pada format legacy reguler.
data[].brand_orderinteger | null- Disertakan langsung hanya pada format legacy reguler.
data[].brand_thumbnailstring | null- Disertakan langsung hanya pada format legacy reguler.
Katalog Smart
/api/v1/h2h/smart-pricelistsHarga sesuai tier akun Anda. Pilih smart_sku_code aktif untuk POST /smart-transaction. Untuk satu brand, gunakan brand_id dari daftar brand katalog ini atau slug brand pada path. Ikuti next_cursor sampai has_more=false.
Dua header: X-API-Key dan X-Secret-Key
Parameter
| Nama | Tipe / sumber | Wajib | Keterangan |
|---|---|---|---|
| limit | integer · query | Opsional | Jumlah produk per halaman, 1–1000. Gunakan 500 untuk sinkronisasi. Default 500. min=1 max=1000 |
| cursor | string · query | Opsional | Salin meta.pagination.next_cursor dari halaman sebelumnya. Pertahankan filter yang sama selama pagination. |
| brandKompatibilitas | integer / string · query | Opsional | Alias kompatibilitas: ID atau nama brand persis. Gunakan brand_id untuk integrasi baru. |
| categoryKompatibilitas | integer / string · query | Opsional | Filter kompatibilitas kategori utama berdasarkan ID atau nama persis. Gunakan brand_id atau slug brand. |
| search | string · query | Opsional | Cari nama produk atau Smart SKU. |
| brand_id | integer · query | Opsional | Filter memakai data[].brand_id dari daftar brand katalog yang sama. Kosongkan untuk mengambil semua brand. min=1 |
curl -X GET 'https://api.melostore.id/api/v1/h2h/smart-pricelists?limit=500' \
-H 'Accept: application/json' \
-H "X-API-Key: $H2H_API_KEY" \
-H "X-Secret-Key: $H2H_SECRET_KEY"Request berhasil.
{
"success": true,
"data": [
{
"name": "Example product",
"category_name": "Example category",
"brand_id": 10,
"type_name": "Example type",
"category_order": 1,
"type_order": 1,
"status": "active",
"inquiry_form_key": "example-form",
"h2h_description": null,
"description": null,
"smart_sku_code": "smartEXAMPLE",
"min_price": 1000,
"max_price": 1000,
"variant_count": 1,
"variants": [
{
"sku_code": "EXAMPLE-10",
"price": 1000,
"status": "active"
}
]
}
],
"meta": {
"brands": [
{
"id": 10,
"name": "Example brand",
"thumbnail": null,
"order": 1
}
],
"inquiry_forms": {
"example-form": {
"fields": [
{
"key": "customer_target",
"name": "Player ID",
"type": "text"
},
{
"key": "customer_target_zone",
"name": "Zone",
"type": "text"
}
],
"notice": null
}
},
"pagination": {
"cursor": null,
"next_cursor": null,
"limit": 100,
"has_more": false
}
}
}successbooleanWajibdataarrayWajibdata[].namestringWajibdata[].category_namestringWajibdata[].brand_idinteger | nullWajib- ID brand; daftar lengkap tersedia pada endpoint categories katalog yang sama.
data[].type_namestringWajibdata[].category_orderintegerWajibdata[].type_orderintegerWajibdata[].statusactive | out_of_stockWajib- Pesan hanya produk active. out_of_stock berarti tidak tersedia.
data[].inquiry_form_keystringWajib- Cari key ini pada meta.inquiry_forms di halaman yang sama.
data[].h2h_descriptionstring | nullWajibdata[].descriptionstring | nullWajibdata[].smart_sku_codestringWajibdata[].min_priceintegerWajibdata[].max_priceintegerWajibdata[].variant_countintegerWajibdata[].variantsarrayWajibdata[].variants[].sku_codestringWajibdata[].variants[].priceinteger | nullWajibdata[].variants[].statusstringWajibmetaobjectWajibmeta.brandsarrayWajib- Metadata brand pada halaman ini saja. Gunakan endpoint categories untuk daftar lengkap.
meta.brands[].idintegerWajibmeta.brands[].namestring | nullWajibmeta.brands[].thumbnailstring | nullWajibmeta.brands[].orderinteger | nullWajibmeta.inquiry_formsobject / arrayWajib- Form input produk berdasarkan inquiry_form_key. Hasil kosong dapat berupa {} atau [].
meta.inquiry_forms.{key}.fieldsarraymeta.inquiry_forms.{key}.fields[].keystringmeta.inquiry_forms.{key}.fields[].namestringmeta.inquiry_forms.{key}.fields[].typestringmeta.inquiry_forms.{key}.fields[].requiredboolean- Apakah field wajib diisi oleh pembeli.
meta.inquiry_forms.{key}.fields[].optionsarray- Untuk pilihan, tampilkan label dan kirim value.
meta.inquiry_forms.{key}.fields[].options[].labelstringmeta.inquiry_forms.{key}.fields[].options[].valuestring | numbermeta.inquiry_forms.{key}.fields[].placeholderstring | nullmeta.inquiry_forms.{key}.noticeobject | null- Petunjuk berdasarkan bahasa. Baca notice.id atau notice.en; null jika tidak ada.
meta.inquiry_forms.{key}.notice.idstringmeta.inquiry_forms.{key}.notice.enstringmeta.paginationobjectWajib- Ikuti next_cursor selama has_more=true. Pada respons reguler, objek ini muncul saat limit dikirim.
meta.pagination.cursorstring | nullWajibmeta.pagination.next_cursorstring | nullWajibmeta.pagination.limitintegerWajibmeta.pagination.has_morebooleanWajib
Harga Smart per brand
/api/v1/h2h/smart-pricelists/{category_slug}Harga sesuai tier akun Anda. Pilih smart_sku_code aktif untuk POST /smart-transaction. Untuk satu brand, gunakan brand_id dari daftar brand katalog ini atau slug brand pada path. Ikuti next_cursor sampai has_more=false.
Dua header: X-API-Key dan X-Secret-Key
Parameter
| Nama | Tipe / sumber | Wajib | Keterangan |
|---|---|---|---|
| category_slug | string · path | Wajib | Slug brand dari data[].slug pada daftar brand katalog yang sama. Slug kategori/tipe lama tetap didukung. |
| limit | integer · query | Opsional | Jumlah produk per halaman, 1–1000. Gunakan 500 untuk sinkronisasi. Default 500. min=1 max=1000 |
| cursor | string · query | Opsional | Salin meta.pagination.next_cursor dari halaman sebelumnya. Pertahankan filter yang sama selama pagination. |
| brandKompatibilitas | integer / string · query | Opsional | Alias kompatibilitas: ID atau nama brand persis. Gunakan brand_id untuk integrasi baru. |
| categoryKompatibilitas | integer / string · query | Opsional | Filter kompatibilitas kategori utama berdasarkan ID atau nama persis. Gunakan brand_id atau slug brand. |
| search | string · query | Opsional | Cari nama produk atau Smart SKU. |
| brand_id | integer · query | Opsional | Filter memakai data[].brand_id dari daftar brand katalog yang sama. Kosongkan untuk mengambil semua brand. min=1 |
curl -X GET 'https://api.melostore.id/api/v1/h2h/smart-pricelists/example-brand?limit=500' \
-H 'Accept: application/json' \
-H "X-API-Key: $H2H_API_KEY" \
-H "X-Secret-Key: $H2H_SECRET_KEY"Request berhasil.
{
"success": true,
"data": [
{
"name": "Example product",
"category_name": "Example category",
"brand_id": 10,
"type_name": "Example type",
"category_order": 1,
"type_order": 1,
"status": "active",
"inquiry_form_key": "example-form",
"h2h_description": null,
"description": null,
"smart_sku_code": "smartEXAMPLE",
"min_price": 1000,
"max_price": 1000,
"variant_count": 1,
"variants": [
{
"sku_code": "EXAMPLE-10",
"price": 1000,
"status": "active"
}
]
}
],
"meta": {
"brands": [
{
"id": 10,
"name": "Example brand",
"thumbnail": null,
"order": 1
}
],
"inquiry_forms": {
"example-form": {
"fields": [
{
"key": "customer_target",
"name": "Player ID",
"type": "text"
},
{
"key": "customer_target_zone",
"name": "Zone",
"type": "text"
}
],
"notice": null
}
},
"pagination": {
"cursor": null,
"next_cursor": null,
"limit": 100,
"has_more": false
}
}
}successbooleanWajibdataarrayWajibdata[].namestringWajibdata[].category_namestringWajibdata[].brand_idinteger | nullWajib- ID brand; daftar lengkap tersedia pada endpoint categories katalog yang sama.
data[].type_namestringWajibdata[].category_orderintegerWajibdata[].type_orderintegerWajibdata[].statusactive | out_of_stockWajib- Pesan hanya produk active. out_of_stock berarti tidak tersedia.
data[].inquiry_form_keystringWajib- Cari key ini pada meta.inquiry_forms di halaman yang sama.
data[].h2h_descriptionstring | nullWajibdata[].descriptionstring | nullWajibdata[].smart_sku_codestringWajibdata[].min_priceintegerWajibdata[].max_priceintegerWajibdata[].variant_countintegerWajibdata[].variantsarrayWajibdata[].variants[].sku_codestringWajibdata[].variants[].priceinteger | nullWajibdata[].variants[].statusstringWajibmetaobjectWajibmeta.brandsarrayWajib- Metadata brand pada halaman ini saja. Gunakan endpoint categories untuk daftar lengkap.
meta.brands[].idintegerWajibmeta.brands[].namestring | nullWajibmeta.brands[].thumbnailstring | nullWajibmeta.brands[].orderinteger | nullWajibmeta.inquiry_formsobject / arrayWajib- Form input produk berdasarkan inquiry_form_key. Hasil kosong dapat berupa {} atau [].
meta.inquiry_forms.{key}.fieldsarraymeta.inquiry_forms.{key}.fields[].keystringmeta.inquiry_forms.{key}.fields[].namestringmeta.inquiry_forms.{key}.fields[].typestringmeta.inquiry_forms.{key}.fields[].requiredboolean- Apakah field wajib diisi oleh pembeli.
meta.inquiry_forms.{key}.fields[].optionsarray- Untuk pilihan, tampilkan label dan kirim value.
meta.inquiry_forms.{key}.fields[].options[].labelstringmeta.inquiry_forms.{key}.fields[].options[].valuestring | numbermeta.inquiry_forms.{key}.fields[].placeholderstring | nullmeta.inquiry_forms.{key}.noticeobject | null- Petunjuk berdasarkan bahasa. Baca notice.id atau notice.en; null jika tidak ada.
meta.inquiry_forms.{key}.notice.idstringmeta.inquiry_forms.{key}.notice.enstringmeta.paginationobjectWajib- Ikuti next_cursor selama has_more=true. Pada respons reguler, objek ini muncul saat limit dikirim.
meta.pagination.cursorstring | nullWajibmeta.pagination.next_cursorstring | nullWajibmeta.pagination.limitintegerWajibmeta.pagination.has_morebooleanWajib
Daftar brand reguler
/api/v1/h2h/pricelists/categoriesBrand yang memiliki produk pada katalog reguler tier Anda. Setiap record berisi brand_id, name, slug, kategori induk pada category, serta tipe produk anak langsung pada type[]. Urutan berdasarkan ID kategori induk naik, lalu nama brand A-Z; brand tanpa kategori induk di akhir. Gunakan brand_id sebagai filter katalog atau slug pada /pricelists/{category_slug}. Brand atau tipe yang terdaftar tidak menjamin SKU aktif; periksa daftar harga terkait.
Dua header: X-API-Key dan X-Secret-Key
Parameter
Tanpa parameter.
curl -X GET 'https://api.melostore.id/api/v1/h2h/pricelists/categories' \
-H 'Accept: application/json' \
-H "X-API-Key: $H2H_API_KEY" \
-H "X-Secret-Key: $H2H_SECRET_KEY"Request berhasil.
{
"success": true,
"data": [
{
"brand_id": 10,
"name": "Example brand",
"slug": "example-brand",
"category": {
"id": 1,
"name": "Games",
"slug": "games"
},
"type": [
{
"id": 11,
"name": "Diamonds",
"slug": "example-diamonds"
},
{
"id": 12,
"name": "Passes",
"slug": "example-passes"
}
]
}
]
}successbooleanWajibdataarrayWajibdata[].brand_idintegerWajib- ID brand untuk filter brand_id pada katalog. Menggantikan field id sebelumnya pada daftar brand ini.
data[].namestringWajibdata[].slugstringWajib- Slug brand untuk path /pricelists/{category_slug} atau /smart-pricelists/{category_slug} yang sesuai.
data[].categoryobject | nullWajib- Kategori induk brand ini, atau null jika tidak memiliki kategori induk.
data[].category.idintegerWajibdata[].category.namestringWajibdata[].category.slugstring | nullWajibdata[].typearrayWajib- Seluruh tipe produk anak langsung dari brand ini, diurutkan menurut nama A-Z. Kosong jika brand tidak memiliki tipe. Adanya tipe tidak menjamin SKU tersedia; periksa daftar harga terkait.
data[].type[].idintegerWajibdata[].type[].namestringWajibdata[].type[].slugstring | nullWajib
Daftar brand Smart
/api/v1/h2h/smart-pricelists/categoriesBrand yang memiliki produk pada katalog Smart tier Anda. Setiap record berisi brand_id, name, slug, kategori induk pada category, serta tipe produk anak langsung pada type[]. Urutan berdasarkan ID kategori induk naik, lalu nama brand A-Z; brand tanpa kategori induk di akhir. Gunakan brand_id sebagai filter katalog atau slug pada /smart-pricelists/{category_slug}. Brand atau tipe yang terdaftar tidak menjamin SKU aktif; periksa daftar harga terkait.
Dua header: X-API-Key dan X-Secret-Key
Parameter
Tanpa parameter.
curl -X GET 'https://api.melostore.id/api/v1/h2h/smart-pricelists/categories' \
-H 'Accept: application/json' \
-H "X-API-Key: $H2H_API_KEY" \
-H "X-Secret-Key: $H2H_SECRET_KEY"Request berhasil.
{
"success": true,
"data": [
{
"brand_id": 10,
"name": "Example brand",
"slug": "example-brand",
"category": {
"id": 1,
"name": "Games",
"slug": "games"
},
"type": [
{
"id": 11,
"name": "Diamonds",
"slug": "example-diamonds"
},
{
"id": 12,
"name": "Passes",
"slug": "example-passes"
}
]
}
]
}successbooleanWajibdataarrayWajibdata[].brand_idintegerWajib- ID brand untuk filter brand_id pada katalog. Menggantikan field id sebelumnya pada daftar brand ini.
data[].namestringWajibdata[].slugstringWajib- Slug brand untuk path /pricelists/{category_slug} atau /smart-pricelists/{category_slug} yang sesuai.
data[].categoryobject | nullWajib- Kategori induk brand ini, atau null jika tidak memiliki kategori induk.
data[].category.idintegerWajibdata[].category.namestringWajibdata[].category.slugstring | nullWajibdata[].typearrayWajib- Seluruh tipe produk anak langsung dari brand ini, diurutkan menurut nama A-Z. Kosong jika brand tidak memiliki tipe. Adanya tipe tidak menjamin SKU tersedia; periksa daftar harga terkait.
data[].type[].idintegerWajibdata[].type[].namestringWajibdata[].type[].slugstring | nullWajib
Jika request gagal atau terputus
Timeout, HTTP 500, atau koneksi terputus: simpan buyer_trx_id dan cek status dengan referensi itu. Jika perlu, ulangi request yang sama dengan referensi yang sama. Jangan langsung membuat referensi baru karena pesanan pertama mungkin sudah diterima.
HTTP 401: periksa dua header kredensial. HTTP 403: periksa akses akun dan whitelist IP yang berlaku. HTTP 422: periksa errors dan parameter; MAX_PRICE_TOO_LOW meminta batas minimal sesuai harga katalog. HTTP 429: tunggu Retry-After sebelum retry.
HTTP 201 hanya berarti pesanan diterima. pending/processing masih berjalan; success berhasil; failed gagal dan saldo yang dipotong dikembalikan. Buat pesanan pengganti hanya setelah hasil sebelumnya final.
PROVIDER_PRICE_CHANGED: setelah hasil failed, ambil harga terbaru sebelum membuat pesanan baru. HTTP 409 pada bulk dapat berarti referensi dipakai dengan isi berbeda atau invoice belum tersedia; baca message sesuai endpoint.
Tindakan pelanggan dan verifikasi 2FA
Tindakan pelanggan terpisah dari status transaksi. Pesanan reguler dan Smart tetap processing selama verifikasi berjalan: required → submitted → resolved. need_action=true hanya pada required; tampilkan form hanya bila action.can_submit=true.
Saat required, minta pembeli mengirim kode melalui POST /api/v1/h2h/transactions/2fa dengan buyer_trx_id dan code. Sertakan action_id serta action_version terbaru untuk mencegah pengiriman ke permintaan lama. Kode berupa string 1–128 karakter setelah trim, tanpa karakter kontrol; tidak terbatas enam digit.
HTTP 202 berarti kode diterima untuk penanganan admin, bukan kode sudah terbukti valid. Setelah submitted, sembunyikan form dan tampilkan menunggu admin. resolved menyembunyikan flag. Admin dapat meminta ulang: state kembali required dengan versi lebih besar. Ambil kode terbaru dari pembeli saat itu.
Gunakan autentikasi serta IP whitelist yang sama. Batas 5 permintaan/menit per pemilik dan transaksi. Retry kode yang sama mengembalikan hasil sebelumnya tanpa pemberitahuan baru; kode berbeda mendapat 409. Versi lama, transaksi final, atau tindakan tidak tersedia mendapat 409. Referensi milik akun lain mendapat 404.
Webhook transaction.action_change dapat diterima sebelum hasil akhir. Verifikasi X-H2H-Signature terhadap raw body menggunakan Webhook Secret. Deduplicasi dengan event_id dan versi; abaikan action.version yang lebih lama. Simpan tindakan secara terpisah: event tindakan tidak boleh menyelesaikan pesanan, mengubah saldo, atau memicu refund. Webhook hasil akhir juga menyertakan snapshot tindakan terbaru.
Status, refund, dan referensi
HTTP 201/200 berarti request diterima atau status berhasil dibaca. Periksa data.status untuk hasil pesanan: pending/processing masih diproses, success berhasil, dan failed gagal. Saldo yang terpotong untuk pesanan gagal dikembalikan. serial_number dapat kosong sampai hasil tersedia; detail pemeriksaan akun dapat memakai null. Gunakan error_code/message untuk membaca alasan kegagalan.
Regular order menerima max_price opsional berupa integer positif dalam MC/IDR. Nilainya harus mencakup harga tier saat ini; jika lebih kecil, request ditolak HTTP 422 dengan MAX_PRICE_TOO_LOW sebelum saldo dipotong. Nilai yang sama diperbolehkan. Tanpa parameter atau null memakai aturan otomatis.
Jika max_price dikirim, saldo harus cukup untuk seluruh batas tersebut. Biaya akhir pesanan sukses tidak melebihi max_price. Selisih saldo yang ditahan dikembalikan saat sukses; seluruh nilai dikembalikan saat gagal.
Contoh: max_price 1.100 MC membuat saldo ditahan 1.100 MC. Jika biaya akhir 1.000 MC, selisih 100 MC dikembalikan. Angka ini hanya ilustrasi; tentukan batas memakai harga katalog akun Anda.
PROVIDER_PRICE_CHANGED berarti harga berubah sehingga pesanan tidak dapat diselesaikan. Setelah status pesanan sebelumnya failed, ambil harga terbaru dan gunakan buyer_trx_id baru jika ingin memesan lagi. Mengulang referensi pesanan gagal tetap mengembalikan hasil sebelumnya.
Reguler dan Smart mewajibkan buyer_trx_id sebagai referensi unik pesanan Anda. Jika request terputus, cek GET /transaction/{id} menggunakan buyer_trx_id atau ulangi request yang sama dengan referensi tersebut. Referensi yang sudah dipakai mengembalikan transaksi sebelumnya. Gunakan referensi baru untuk pesanan baru. Smart menahan saldo sebesar max_bid dan mengembalikan selisih setelah harga akhir diketahui.
Simpan SKU yang Anda pesan bersama id dan buyer_trx_id. Cocokkan respons status dan callback melalui id/buyer_trx_id karena sku_code pada hasil Smart dapat berbeda dari SKU saat pemesanan. fulfilled_sku_code menunjukkan SKU yang berhasil dipenuhi. Pada detail pemeriksaan akun berbayar, buyer_trx_id dan sku_code bernilai null.
Selama status masih pending/processing, tunggu hasil akhir melalui callback atau cek status; jangan membuat pesanan pengganti untuk request yang sama. Harga pada respons transaksi memakai price, sedangkan callback memakai price_charged. Harga awal Smart dapat menunjukkan max_bid, dan regular dengan max_price menunjukkan nilai hold sebelum harga akhir tersedia. price_charged pada pesanan gagal tidak menunjukkan biaya akhir setelah refund; periksa saldo dan invoice untuk rekonsiliasi.
Buat transaksi reguler
/api/v1/h2h/transactionBuat satu pesanan memakai sku_code reguler. HTTP 201 berarti pesanan diterima; baca data.status untuk hasilnya. Jika respons belum pasti, ulangi request yang sama dengan buyer_trx_id yang sama. Gunakan referensi baru untuk pesanan baru. max_price opsional membatasi biaya akhir dan seluruh batas ditahan di awal. Sisa saldo dikembalikan saat sukses; pesanan gagal mendapat refund penuh.
Dua header: X-API-Key dan X-Secret-Key
Parameter
| Nama | Tipe / sumber | Wajib | Keterangan |
|---|---|---|---|
| sku_code | string · body | Wajib | sku_code persis dari katalog reguler. |
| customer_target | string · body | Wajib | ID pelanggan, nomor telepon, atau email sesuai field pertama pada form katalog. Kirim sebagai string. maxLength=255 |
| customer_target_zone | string | null · body | Opsional | Wajib jika form produk/game memerlukan field zone kedua. Gunakan nilai opsi, bukan label tampilannya. maxLength=100 |
| additional_data | object | null · body | Opsional | Nilai field form lainnya, memakai key dari meta.inquiry_forms. Kosongkan jika tidak diperlukan. |
| buyer_trx_id | string · body | Wajib | Referensi unik pesanan Anda. Pertahankan saat retry pesanan yang sama; gunakan referensi baru untuk pesanan baru. maxLength=64 |
| sandbox_mode | boolean | null · body | Opsional | true untuk simulasi tanpa debit saldo; false untuk pesanan live. Kosongkan/null mengikuti mode akun. |
| max_price | integer | null · body | Opsional | Batas biaya akhir opsional dalam MC/IDR, minimal harga tier saat ini. Saldo harus cukup untuk seluruh batas yang ditahan di awal. Sisa dikembalikan saat sukses; gagal mendapat refund penuh. Kosongkan/null untuk harga otomatis. min=1 max=99999999999 |
curl -X POST 'https://api.melostore.id/api/v1/h2h/transaction' \
-H 'Accept: application/json' \
-H "X-API-Key: $H2H_API_KEY" \
-H "X-Secret-Key: $H2H_SECRET_KEY" \
-H 'Content-Type: application/json' \
--data '{
"sku_code": "EXAMPLE-10",
"customer_target": "123456789",
"customer_target_zone": "1234",
"buyer_trx_id": "example-order-001",
"sandbox_mode": true,
"additional_data": {
"email": "[email protected]"
}
}'Request diterima. Baca data.status untuk hasil pesanan.
{
"success": true,
"message": "Transaction successfully created and queued.",
"data": {
"id": "11111111-1111-4111-8111-111111111111",
"buyer_trx_id": "example-order-001",
"sku_code": "EXAMPLE-10",
"product_name": "Example product",
"customer_target": "123456789",
"customer_target_zone": "1234",
"price": 1000,
"status": "processing",
"serial_number": "",
"webhook_delivery_status": "pending",
"is_sandbox": true,
"created_at": "2026-10-02T03:00:00+00:00"
}
}successbooleanWajibdataobjectWajibdata.idstringWajibdata.buyer_trx_idstring | nullWajib- Buyer reference for product orders; null for paid account-check transactions.
data.sku_codestring | nullWajib- Product SKU in the transaction result. For Smart, it may differ from the ordered SKU; match by id/buyer_trx_id and use fulfilled_sku_code for successful fulfillment. May be null, including on paid account checks.
data.product_namestring | nulldata.customer_targetstringWajibdata.customer_target_zonestring | nullWajibdata.pricenumberWajib- MC/IDR. While processing, Smart shows max_bid and a capped regular order shows its max_price hold. On success this is the final charge; a failed order is refunded.
data.statuspending | processing | success | failed | refundedWajibdata.serial_numberstring | nullWajibdata.webhook_delivery_statusstringWajibdata.is_sandboxbooleanWajibdata.created_atstringWajibdata.error_codestring | nulldata.messagestring | nulldata.max_priceinteger- Present only on regular orders submitted with max_price. Original hold and maximum final charge in MC/IDR.
data.need_actionboolean- True only when customer action is required. Independent of transaction status.
data.actionobject / null- Current customer action. Submit only when can_submit=true; compare version before applying updates.
data.action.idstringdata.action.typetwo_factordata.action.staterequired | submitted | resolveddata.action.versionintegerdata.action.messagestringdata.action.can_submitbooleandata.action.updated_atstring
Buat Smart Order
/api/v1/h2h/smart-transactionBuat satu pesanan Smart dengan smart_sku_code sebagai sku_code dan max_bid sebagai anggaran. Seluruh anggaran ditahan di awal. Biaya akhir pesanan sukses tidak melebihi max_bid; sisa saldo dikembalikan. Pesanan gagal mendapat refund penuh. Untuk PROVIDER_PRICE_CHANGED, perbarui katalog dan buat pesanan baru setelah pesanan sebelumnya final.
Dua header: X-API-Key dan X-Secret-Key
Parameter
| Nama | Tipe / sumber | Wajib | Keterangan |
|---|---|---|---|
| sku_code | string · body | Wajib | Isi dengan nilai smart_sku_code dari katalog Smart. maxLength=100 |
| customer_target | string · body | Wajib | ID pelanggan, nomor telepon, atau email sesuai field pertama pada form katalog. Kirim sebagai string. maxLength=255 |
| customer_target_zone | string | null · body | Opsional | Wajib jika form produk/game memerlukan field zone kedua. Gunakan nilai opsi, bukan label tampilannya. maxLength=100 |
| additional_data | object | null · body | Opsional | Nilai field form lainnya, memakai key dari meta.inquiry_forms. Kosongkan jika tidak diperlukan. |
| buyer_trx_id | string · body | Wajib | Referensi unik pesanan Anda. Pertahankan saat retry pesanan yang sama; gunakan referensi baru untuk pesanan baru. maxLength=64 |
| sandbox_mode | boolean | null · body | Opsional | true untuk simulasi tanpa debit saldo; false untuk pesanan live. Kosongkan/null mengikuti mode akun. |
| max_bid | integer · body | Wajib | Anggaran maksimal Smart Order dalam MC/IDR. Seluruh nilai ditahan di awal; sisanya dikembalikan. min=1 |
curl -X POST 'https://api.melostore.id/api/v1/h2h/smart-transaction' \
-H 'Accept: application/json' \
-H "X-API-Key: $H2H_API_KEY" \
-H "X-Secret-Key: $H2H_SECRET_KEY" \
-H 'Content-Type: application/json' \
--data '{
"sku_code": "smartEXAMPLE",
"customer_target": "123456789",
"customer_target_zone": "1234",
"buyer_trx_id": "example-smart-order-001",
"sandbox_mode": true,
"additional_data": {
"email": "[email protected]"
},
"max_bid": 1100
}'Request berhasil.
{
"success": true,
"message": "Transaction successfully created and queued.",
"data": {
"id": "11111111-1111-4111-8111-111111111111",
"buyer_trx_id": "example-smart-order-001",
"sku_code": "smartEXAMPLE",
"product_name": "Example product",
"customer_target": "123456789",
"customer_target_zone": "1234",
"price": 1100,
"status": "processing",
"serial_number": "",
"webhook_delivery_status": "pending",
"is_sandbox": true,
"created_at": "2026-10-02T03:00:00+00:00",
"max_bid": 1100
}
}successbooleanWajibdataobjectWajibdata.idstringWajibdata.buyer_trx_idstringWajibdata.sku_codestringWajib- Smart order results may use a different sku_code from creation. Store the ordered SKU and match by id/buyer_trx_id; use fulfilled_sku_code for successful fulfillment.
data.product_namestring | nullWajibdata.customer_targetstringWajibdata.customer_target_zonestring | nullWajibdata.pricenumberWajibdata.statusstringWajibdata.serial_numberstringWajibdata.webhook_delivery_statusstringWajibdata.is_sandboxbooleanWajibdata.created_atstringWajibdata.max_bidinteger | nullWajibdata.error_codestring | nulldata.messagestring | null
Status transaksi
/api/v1/h2h/transaction/{id}Cari transaksi Anda melalui UUID atau buyer_trx_id. Berlaku untuk reguler, Smart, dan setiap pesanan bulk; gunakan billing.transaction_id untuk pemeriksaan akun berbayar. Cocokkan hasil Smart melalui id/buyer_trx_id karena sku_code dapat berbeda dari SKU yang dipesan. fulfilled_sku_code menunjukkan SKU yang berhasil dipenuhi. buyer_trx_id, sku_code, dan serial_number pemeriksaan akun bernilai null. Field Smart/bulk hanya muncul sesuai jenis pesanan.
Dua header: X-API-Key dan X-Secret-Key
Parameter
| Nama | Tipe / sumber | Wajib | Keterangan |
|---|---|---|---|
| id | string · path | Wajib | ID milik akun Anda dari hasil create; status transaksi juga menerima buyer_trx_id. |
curl -X GET 'https://api.melostore.id/api/v1/h2h/transaction/11111111-1111-4111-8111-111111111111' \
-H 'Accept: application/json' \
-H "X-API-Key: $H2H_API_KEY" \
-H "X-Secret-Key: $H2H_SECRET_KEY"Detail pesanan. Baca data.status untuk hasil saat ini.
{
"success": true,
"data": {
"id": "11111111-1111-4111-8111-111111111111",
"buyer_trx_id": "example-order-001",
"sku_code": "EXAMPLE-10",
"product_name": "Example product",
"customer_target": "123456789",
"customer_target_zone": "1234",
"price": 1000,
"status": "processing",
"serial_number": "",
"webhook_delivery_status": "pending",
"is_sandbox": true,
"created_at": "2026-10-02T03:00:00+00:00"
}
}successbooleanWajibdataobject / objectWajibdata.idstringWajibdata.buyer_trx_idstring | nullWajib- Buyer reference for product orders; null for paid account-check transactions.
data.sku_codestring | nullWajib- Product SKU in the transaction result. For Smart, it may differ from the ordered SKU; match by id/buyer_trx_id and use fulfilled_sku_code for successful fulfillment. May be null, including on paid account checks.
data.product_namestring | nulldata.customer_targetstringWajibdata.customer_target_zonestring | nullWajibdata.pricenumberWajib- MC/IDR. While processing, Smart shows max_bid and a capped regular order shows its max_price hold. On success this is the final charge; a failed order is refunded.
data.statuspending | processing | success | failed | refundedWajibdata.serial_numberstring | nullWajibdata.webhook_delivery_statusstringWajibdata.is_sandboxbooleanWajibdata.created_atstringWajibdata.error_codestring | nulldata.messagestring | nulldata.max_priceinteger- Present only on regular orders submitted with max_price. Original hold and maximum final charge in MC/IDR.
data.need_actionboolean- True only when customer action is required. Independent of transaction status.
data.actionobject / null- Current customer action. Submit only when can_submit=true; compare version before applying updates.
data.action.idstringdata.action.typetwo_factordata.action.staterequired | submitted | resolveddata.action.versionintegerdata.action.messagestringdata.action.can_submitbooleandata.action.updated_atstringdata.max_bidinteger | nulldata.fulfilled_sku_codestring | nulldata.attempts_countinteger
Kirim kode verifikasi 2FA
/api/v1/h2h/transactions/2faKirim kode yang diminta untuk penanganan admin pada transaksi reguler atau Smart. Gunakan X-API-Key, X-Secret-Key, dan IP whitelist yang berlaku. Batas 5 permintaan/menit per pemilik dan transaksi. HTTP 202 berarti diterima, bukan terbukti valid. Ulangi kode yang sama jika respons belum diterima; kode berbeda ditolak sampai permintaan baru. Status transaksi dan keuangan tidak berubah.
Dua header: X-API-Key dan X-Secret-Key
Parameter
| Nama | Tipe / sumber | Wajib | Keterangan |
|---|---|---|---|
| buyer_trx_id | string · body | Wajib | buyer_trx_id pesanan yang sedang meminta kode ini. Gunakan referensi pesanan yang sama. maxLength=255 |
| code | string · body | Wajib | Kode verifikasi terbaru dari pembeli, 1–128 karakter setelah trim, tanpa karakter kontrol. maxLength=128 |
| action_id | string · body | Opsional | action.id terbaru dari status pesanan ini atau webhook tindakan. Disarankan agar kode tidak terkirim ke permintaan lama. |
| action_version | integer · body | Opsional | action.version terbaru dari pesanan yang sama. Kirim sebagai integer JSON. min=1 |
curl -X POST 'https://api.melostore.id/api/v1/h2h/transactions/2fa' \
-H 'Accept: application/json' \
-H "X-API-Key: $H2H_API_KEY" \
-H "X-Secret-Key: $H2H_SECRET_KEY" \
-H 'Content-Type: application/json' \
--data '{
"buyer_trx_id": "example-order-001",
"code": "fictional-alpha-91",
"action_id": "11111111-1111-4111-8111-111111111111",
"action_version": 1
}'Kode diterima untuk penanganan admin.
{
"success": true,
"message": "Your verification code has been received and is awaiting admin handling.",
"data": {
"need_action": false,
"action": {
"id": "11111111-1111-4111-8111-111111111111",
"type": "two_factor",
"state": "submitted",
"version": 2,
"message": "Your verification code has been received and is awaiting admin handling.",
"can_submit": false,
"updated_at": "2026-10-10T08:02:00+07:00"
}
}
}successbooleanWajibmessagestringWajibdataobjectWajibdata.need_actionbooleanWajib- True only when customer action is required. Independent of transaction status.
data.actionobject / nullWajib- Current customer action. Submit only when can_submit=true; compare version before applying updates.
data.action.idstringdata.action.typetwo_factordata.action.staterequired | submitted | resolveddata.action.versionintegerdata.action.messagestringdata.action.can_submitbooleandata.action.updated_atstring
Panduan bulk order
Satu bulk berisi satu SKU reguler, satu target, dan 1–100 pesanan. Harga dikunci saat pesanan diterima. Setiap pesanan memiliki referensi dan hasil sendiri. Total biaya seluruh pesanan dipotong di awal. Pastikan saldo cukup untuk seluruh bulk; jika saldo kurang, bulk tidak dibuat.
Gunakan order_count untuk jumlah pesanan bulk. Jangan kirim quantity, max_bid, atau order_mode pada request bulk; nilai terisi pada parameter tersebut ditolak dengan HTTP 422.
Gunakan buyer_bulk_id unik untuk setiap bulk dan simpan sebelum mengirim request. Request pertama mengembalikan HTTP 201. Pengulangan request yang sama dengan referensi yang sama mengembalikan HTTP 200 tanpa pemotongan saldo tambahan. Jika isi request berbeda, referensi yang sama menghasilkan HTTP 409. Gunakan referensi baru untuk bulk baru.
Pesanan dalam satu bulk diproses berurutan. Pantau hasil setiap pesanan pada detail bulk; biaya pesanan yang gagal dikembalikan. Jika ingin memesan ulang, gunakan referensi transaksi baru setelah hasil sebelumnya final. Bulk hanya tersedia untuk katalog reguler dengan satu SKU dan satu target; pause dan pembatalan belum tersedia.
Baca success_count dan failed_count untuk jumlah pesanan yang sudah selesai, serta remaining_count untuk yang belum selesai. processing_count menunjukkan pesanan yang sedang diproses dan queued_count menunjukkan pesanan yang menunggu. Status bulk: queued, processing, completed, partially_failed, atau failed. Gunakan GET /bulk-orders/{id} untuk ringkasan progres; callback dikirim per transaksi.
Unduh invoice PDF setelah seluruh pesanan selesai. HTTP 409 berarti invoice belum tersedia atau bulk menggunakan sandbox. Bulk live memiliki satu invoice yang merangkum biaya dan refund, termasuk refund penuh dan biaya akhir nol jika semua pesanan gagal. Invoice dikirim melalui email setelah selesai. Setiap pesanan juga dapat dilihat pada menu Transaksi. Sandbox tidak menghasilkan invoice atau email invoice.
| Aspek | Transaksi reguler | Bulk order |
|---|---|---|
| Jumlah transaksi | Satu | order_count transaksi anak |
| Referensi pelanggan | buyer_trx_id | buyer_bulk_id + referensi unik anak |
| Saldo | Debit satu transaksi | Debit semua anak di awal |
| Pemrosesan | Satu transaksi async | Berurutan dalam satu bulk |
| History | Detail transaksi | Ringkasan progres dan detail anak |
| Invoice/email bulk | Tidak berlaku | Satu dokumen dan email akhir |
Buat bulk order
/api/v1/h2h/bulk-ordersMembuat 1–100 pesanan terpisah untuk satu SKU reguler dan satu target. Total biaya dipotong di awal; saldo kurang membuat bulk tidak dapat dibuat. Gunakan buyer_bulk_id unik untuk setiap bulk dan pertahankan saat retry. Isi order_count dan jangan kirim quantity, max_bid, atau order_mode; nilai terisi pada parameter tersebut menghasilkan HTTP 422.
Dua header: X-API-Key dan X-Secret-Key
Parameter
| Nama | Tipe / sumber | Wajib | Keterangan |
|---|---|---|---|
| sku_code | string · body | Wajib | sku_code persis dari katalog reguler. maxLength=100 |
| customer_target | string · body | Wajib | ID pelanggan, nomor telepon, atau email sesuai field pertama pada form katalog. Kirim sebagai string. maxLength=255 |
| customer_target_zone | string | null · body | Opsional | Wajib jika form produk/game memerlukan field zone kedua. Gunakan nilai opsi, bukan label tampilannya. maxLength=100 |
| additional_data | object | null · body | Opsional | Nilai field form lainnya, memakai key dari meta.inquiry_forms. Kosongkan jika tidak diperlukan. |
| sandbox_mode | boolean | null · body | Opsional | true untuk simulasi tanpa debit saldo; false untuk pesanan live. Kosongkan/null mengikuti mode akun. |
| buyer_bulk_id | string · body | Wajib | Referensi unik bulk Anda. Retry identik mengembalikan bulk sebelumnya; isi berbeda menghasilkan HTTP 409. maxLength=64 |
| order_count | integer · body | Wajib | Jumlah pesanan terpisah, 1–100, diproses berurutan untuk satu SKU reguler dan target. min=1 max=100 |
curl -X POST 'https://api.melostore.id/api/v1/h2h/bulk-orders' \
-H 'Accept: application/json' \
-H "X-API-Key: $H2H_API_KEY" \
-H "X-Secret-Key: $H2H_SECRET_KEY" \
-H 'Content-Type: application/json' \
--data '{
"sku_code": "EXAMPLE-10",
"customer_target": "123456789",
"customer_target_zone": "1234",
"sandbox_mode": true,
"additional_data": {
"email": "[email protected]"
},
"order_count": 3,
"buyer_bulk_id": "example-bulk-001"
}'Request diterima. Baca data.status untuk hasil pesanan.
{
"success": true,
"message": "Bulk order created and queued.",
"data": {
"id": "22222222-2222-4222-8222-222222222222",
"buyer_bulk_id": "example-bulk-001",
"sku_code": "EXAMPLE-10",
"product_name": "Example product",
"customer_target": "123456789",
"customer_target_zone": "1234",
"order_count": 3,
"unit_price": 1000,
"total_debit": 0,
"status": "queued",
"via": "api",
"is_sandbox": true,
"invoice_available": false,
"created_at": "2026-10-02T03:00:00+00:00",
"completed_at": null,
"total_count": 3,
"success_count": 0,
"failed_count": 0,
"processed_count": 0,
"remaining_count": 3,
"processing_count": 0,
"queued_count": 3
}
}successbooleanWajibmessagestringWajibdataobjectWajibdata.idstringWajibdata.buyer_bulk_idstringWajibdata.sku_codestringWajibdata.product_namestringWajibdata.customer_targetstringWajibdata.customer_target_zonestring | nullWajibdata.order_countintegerWajibdata.unit_pricenumberWajibdata.total_debitnumberWajibdata.statusqueued | processing | completed | partially_failed | failedWajibdata.viastringWajibdata.is_sandboxbooleanWajibdata.invoice_availablebooleanWajibdata.created_atstringWajibdata.completed_atstring | nullWajibdata.total_countintegerWajibdata.success_countintegerWajibdata.failed_countintegerWajibdata.processed_countintegerWajibdata.remaining_countintegerWajibdata.processing_countintegerWajibdata.queued_countintegerWajib
History bulk
/api/v1/h2h/bulk-ordersPesanan milik profil, 15 per halaman. Filter tanggal inklusif zona Asia/Jakarta.
Dua header: X-API-Key dan X-Secret-Key
Parameter
| Nama | Tipe / sumber | Wajib | Keterangan |
|---|---|---|---|
| page | integer · query | Opsional | Nomor halaman, mulai dari 1. |
| status | queued | processing | completed | partially_failed | failed · query | Opsional | Filter status bulk sesuai nilai yang tersedia. |
| search | string · query | Opsional | Cari referensi, target, SKU, atau nama produk. |
| start_date | string · query | Opsional | Tanggal awal YYYY-MM-DD, zona Asia/Jakarta. |
| end_date | string · query | Opsional | Tanggal akhir YYYY-MM-DD, tidak sebelum tanggal awal. |
curl -X GET 'https://api.melostore.id/api/v1/h2h/bulk-orders?page=1' \
-H 'Accept: application/json' \
-H "X-API-Key: $H2H_API_KEY" \
-H "X-Secret-Key: $H2H_SECRET_KEY"Data dan progres pesanan bulk.
{
"success": true,
"data": {
"current_page": 1,
"data": [
{
"id": "22222222-2222-4222-8222-222222222222",
"buyer_bulk_id": "example-bulk-001",
"sku_code": "EXAMPLE-10",
"product_name": "Example product",
"customer_target": "123456789",
"customer_target_zone": "1234",
"order_count": 3,
"unit_price": 1000,
"total_debit": 0,
"status": "processing",
"via": "api",
"is_sandbox": true,
"invoice_available": false,
"created_at": "2026-10-02T03:00:00+00:00",
"completed_at": null,
"total_count": 3,
"success_count": 1,
"failed_count": 1,
"processed_count": 2,
"remaining_count": 1,
"processing_count": 1,
"queued_count": 0
}
],
"first_page_url": "https://api.melostore.id/api/v1/h2h/bulk-orders?page=1",
"from": 1,
"last_page": 1,
"last_page_url": "https://api.melostore.id/api/v1/h2h/bulk-orders?page=1",
"links": [
{
"url": null,
"label": "Previous",
"active": false
}
],
"next_page_url": null,
"path": "https://api.melostore.id/api/v1/h2h/bulk-orders",
"per_page": 15,
"prev_page_url": null,
"to": 1,
"total": 1
}
}successbooleanWajibdataobjectWajibdata.current_pageintegerWajibdata.dataarrayWajibdata.data[].idstringWajibdata.data[].buyer_bulk_idstringWajibdata.data[].sku_codestringWajibdata.data[].product_namestringWajibdata.data[].customer_targetstringWajibdata.data[].customer_target_zonestring | nullWajibdata.data[].order_countintegerWajibdata.data[].unit_pricenumberWajibdata.data[].total_debitnumberWajibdata.data[].statusqueued | processing | completed | partially_failed | failedWajibdata.data[].viastringWajibdata.data[].is_sandboxbooleanWajibdata.data[].invoice_availablebooleanWajibdata.data[].created_atstringWajibdata.data[].completed_atstring | nullWajibdata.data[].total_countintegerWajibdata.data[].success_countintegerWajibdata.data[].failed_countintegerWajibdata.data[].processed_countintegerWajibdata.data[].remaining_countintegerWajibdata.data[].processing_countintegerWajibdata.data[].queued_countintegerWajibdata.first_page_urlstringWajibdata.frominteger | nullWajib- Item position, or null when this page contains no items.
data.last_pageintegerWajibdata.last_page_urlstringWajibdata.linksarrayWajibdata.links[].urlstring | nullWajibdata.links[].labelstringWajibdata.links[].activebooleanWajibdata.next_page_urlstring | nullWajibdata.pathstringWajibdata.per_pageintegerWajibdata.prev_page_urlstring | nullWajibdata.tointeger | nullWajib- Item position, or null when this page contains no items.
data.totalintegerWajib
Progres bulk
/api/v1/h2h/bulk-orders/{id}Lihat status bulk dan jumlah pesanan. processed_count mencakup pesanan berhasil dan gagal; remaining_count mencakup pesanan yang masih menunggu atau diproses.
Dua header: X-API-Key dan X-Secret-Key
Parameter
| Nama | Tipe / sumber | Wajib | Keterangan |
|---|---|---|---|
| id | string · path | Wajib | UUID bulk dari POST /bulk-orders. Gunakan ID bulk, bukan buyer_bulk_id atau ID transaksi anak. |
curl -X GET 'https://api.melostore.id/api/v1/h2h/bulk-orders/22222222-2222-4222-8222-222222222222' \
-H 'Accept: application/json' \
-H "X-API-Key: $H2H_API_KEY" \
-H "X-Secret-Key: $H2H_SECRET_KEY"Data dan progres pesanan bulk.
{
"success": true,
"data": {
"id": "22222222-2222-4222-8222-222222222222",
"buyer_bulk_id": "example-bulk-001",
"sku_code": "EXAMPLE-10",
"product_name": "Example product",
"customer_target": "123456789",
"customer_target_zone": "1234",
"order_count": 3,
"unit_price": 1000,
"total_debit": 0,
"status": "processing",
"via": "api",
"is_sandbox": true,
"invoice_available": false,
"created_at": "2026-10-02T03:00:00+00:00",
"completed_at": null,
"total_count": 3,
"success_count": 1,
"failed_count": 1,
"processed_count": 2,
"remaining_count": 1,
"processing_count": 1,
"queued_count": 0
}
}successbooleanWajibdataobjectWajibdata.idstringWajibdata.buyer_bulk_idstringWajibdata.sku_codestringWajibdata.product_namestringWajibdata.customer_targetstringWajibdata.customer_target_zonestring | nullWajibdata.order_countintegerWajibdata.unit_pricenumberWajibdata.total_debitnumberWajibdata.statusqueued | processing | completed | partially_failed | failedWajibdata.viastringWajibdata.is_sandboxbooleanWajibdata.invoice_availablebooleanWajibdata.created_atstringWajibdata.completed_atstring | nullWajibdata.total_countintegerWajibdata.success_countintegerWajibdata.failed_countintegerWajibdata.processed_countintegerWajibdata.remaining_countintegerWajibdata.processing_countintegerWajibdata.queued_countintegerWajib
Transaksi anak bulk
/api/v1/h2h/bulk-orders/{id}/transactionsPesanan anak diurutkan berdasarkan giliran, 15 per halaman. Setiap anak memiliki UUID transaksi dan buyer_trx_id sendiri.
Dua header: X-API-Key dan X-Secret-Key
Parameter
| Nama | Tipe / sumber | Wajib | Keterangan |
|---|---|---|---|
| id | string · path | Wajib | UUID bulk dari POST /bulk-orders. Gunakan ID bulk, bukan buyer_bulk_id atau ID transaksi anak. |
| page | integer · query | Opsional | Nomor halaman, mulai dari 1. |
curl -X GET 'https://api.melostore.id/api/v1/h2h/bulk-orders/22222222-2222-4222-8222-222222222222/transactions?page=1' \
-H 'Accept: application/json' \
-H "X-API-Key: $H2H_API_KEY" \
-H "X-Secret-Key: $H2H_SECRET_KEY"Data dan progres pesanan bulk.
{
"success": true,
"data": {
"current_page": 1,
"data": [
{
"id": "11111111-1111-4111-8111-111111111111",
"buyer_trx_id": "BULK-22222222-2222-4222-8222-222222222222-1",
"bulk_order_id": "22222222-2222-4222-8222-222222222222",
"buyer_bulk_id": "example-bulk-001",
"bulk_sequence": 1,
"sku_code": "EXAMPLE-10",
"customer_target": "123456789",
"customer_target_zone": "1234",
"price": 1000,
"status": "success",
"serial_number": "EXAMPLE-SN-001",
"error_code": null,
"message": null,
"created_at": "2026-10-02T03:00:00+00:00",
"updated_at": "2026-10-02T03:00:00+00:00"
}
],
"first_page_url": "https://api.melostore.id/api/v1/h2h/bulk-orders/22222222-2222-4222-8222-222222222222/transactions?page=1",
"from": 1,
"last_page": 1,
"last_page_url": "https://api.melostore.id/api/v1/h2h/bulk-orders/22222222-2222-4222-8222-222222222222/transactions?page=1",
"links": [
{
"url": null,
"label": "Previous",
"active": false
}
],
"next_page_url": null,
"path": "https://api.melostore.id/api/v1/h2h/bulk-orders/22222222-2222-4222-8222-222222222222/transactions",
"per_page": 15,
"prev_page_url": null,
"to": 1,
"total": 1
}
}successbooleanWajibdataobjectWajibdata.current_pageintegerWajibdata.dataarrayWajibdata.data[].idstringWajibdata.data[].buyer_trx_idstringWajibdata.data[].bulk_order_idstringWajibdata.data[].buyer_bulk_idstringWajibdata.data[].bulk_sequenceintegerWajibdata.data[].sku_codestring | nullWajibdata.data[].customer_targetstringWajibdata.data[].customer_target_zonestring | nullWajibdata.data[].pricenumberWajibdata.data[].statuspending | processing | success | failed | refundedWajibdata.data[].serial_numberstringWajibdata.data[].error_codestring | nullWajibdata.data[].messagestring | nullWajibdata.data[].created_atstringWajibdata.data[].updated_atstringWajibdata.first_page_urlstringWajibdata.frominteger | nullWajib- Item position, or null when this page contains no items.
data.last_pageintegerWajibdata.last_page_urlstringWajibdata.linksarrayWajibdata.links[].urlstring | nullWajibdata.links[].labelstringWajibdata.links[].activebooleanWajibdata.next_page_urlstring | nullWajibdata.pathstringWajibdata.per_pageintegerWajibdata.prev_page_urlstring | nullWajibdata.tointeger | nullWajib- Item position, or null when this page contains no items.
data.totalintegerWajib
Unduh invoice akhir bulk
/api/v1/h2h/bulk-orders/{id}/invoiceUnduh satu PDF yang merangkum biaya dan refund bulk yang selesai. HTTP 409 berarti invoice belum tersedia atau bulk menggunakan sandbox. Jika semua pesanan live gagal, invoice menunjukkan refund penuh dan biaya akhir nol.
Dua header: X-API-Key dan X-Secret-Key
Parameter
| Nama | Tipe / sumber | Wajib | Keterangan |
|---|---|---|---|
| id | string · path | Wajib | UUID bulk dari POST /bulk-orders. Gunakan ID bulk, bukan buyer_bulk_id atau ID transaksi anak. |
curl -X GET 'https://api.melostore.id/api/v1/h2h/bulk-orders/22222222-2222-4222-8222-222222222222/invoice' \
-H 'Accept: application/json' \
-H "X-API-Key: $H2H_API_KEY" \
-H "X-Secret-Key: $H2H_SECRET_KEY" \
--fail-with-body --output bulk-invoice.pdfLampiran PDF akhir dengan nomor invoice tetap H2H-BULK-{UUID}.
Content-Type: application/pdf · Content-Disposition: attachment
Billing pemeriksaan akun
Lihat GET /check-nickname/plan untuk jatah gratis dan tarif aktif. Pemeriksaan nickname dan purchase limit berbagi jatah. Hasil ditemukan maupun tidak ditemukan menggunakan jatah gratis, atau dikenakan biaya jika pemeriksaan berbayar aktif pada akun live. Setiap pemeriksaan ulang tetap menggunakan jatah atau biaya.
Hasil ditemukan dan tidak ditemukan memuat billing.charged_mc, free_remaining_today, dan transaction_id bila ditagih. Gangguan/verifikasi yang tidak pasti tidak disamakan dengan akun tidak ditemukan. HTTP 402 berarti saldo pemeriksaan tidak cukup; 429 kuota; 404 hasil tidak ditemukan; 422 validasi; 502 layanan belum tersedia. Mode sandbox akun hanya memakai jatah gratis.
Gunakan tarif dari respons plan terbaru sebelum menawarkan pemeriksaan berbayar. Jika tarif tidak tersedia, coba lagi sebelum melanjutkan. Angka pada contoh respons hanya ilustrasi; tarif aktif ditampilkan pada bagian paket pemeriksaan akun.
…
Referensi zone adalah snapshot. Validasi kebutuhan zone melalui endpoint games dan gunakan kode zone sesuai game.
Referensi kode zone
Pilih game untuk melihat kode yang digunakan pada customer_target_zone. Cari berdasarkan nama atau kode zone.
Game/akun yang didukung
/api/v1/h2h/check-nickname/gamesDaftar publik serta kebutuhan zone. Referensi zone docs merupakan snapshot.
Publik, tanpa autentikasi
Parameter
Tanpa parameter.
curl -X GET 'https://api.melostore.id/api/v1/h2h/check-nickname/games' \
-H 'Accept: application/json'Request berhasil.
{
"success": true,
"games": [
{
"game_code": "mobile-legends",
"name": "Mobile Legends",
"type": "game",
"zone_required": true,
"zone_values": null,
"params": [
{
"name": "customer_target"
},
{
"name": "customer_target_zone"
}
],
"status": "available"
}
]
}successbooleanWajibgamesarrayWajibgames[].game_codestringWajibgames[].namestringWajibgames[].typestringWajibgames[].zone_requiredbooleanWajibgames[].zone_valuesstring | nullWajibgames[].paramsarrayWajibgames[].params[].namestringWajibgames[].statusstringWajib
Paket pemeriksaan akun
/api/v1/h2h/check-nickname/planJatah/tarif aktif publik. Angka contoh adalah snapshot fiktif, bukan tarif aktif.
Publik, tanpa autentikasi
Parameter
Tanpa parameter.
curl -X GET 'https://api.melostore.id/api/v1/h2h/check-nickname/plan' \
-H 'Accept: application/json'Request berhasil.
{
"success": true,
"data": {
"free_daily_limit": 40,
"free_minute_limit": 20,
"paid_price_mc": 1,
"paid_minute_limit": 20,
"resets_at": "00:00 UTC"
}
}successbooleanWajibdataobjectWajibdata.free_daily_limitintegerWajibdata.free_minute_limitintegerWajibdata.paid_price_mcintegerWajibdata.paid_minute_limitintegerWajibdata.resets_atstringWajib
Periksa nama akun
/api/v1/h2h/check-nicknameMode akun menentukan billing; tidak ada override sandbox per request. Ditemukan/tidak ditemukan memakai jatah atau biaya, termasuk pemeriksaan ulang.
Dua header: X-API-Key dan X-Secret-Key
Parameter
| Nama | Tipe / sumber | Wajib | Keterangan |
|---|---|---|---|
| game_code | string · body | Wajib | Ambil games[].game_code dari GET /check-nickname/games. Nilai ini berbeda dari slug brand produk. maxLength=100 |
| customer_target | string · body | Wajib | ID akun atau nomor pelanggan untuk pemeriksaan game/akun yang dipilih. Kirim sebagai string. maxLength=255 |
| customer_target_zone | string | null · body | Opsional | Zone/server akun sesuai zone_required dan zone_values dari GET /check-nickname/games. Wajib untuk pemeriksaan batas pembelian Mobile Legends. maxLength=100 |
curl -X POST 'https://api.melostore.id/api/v1/h2h/check-nickname' \
-H 'Accept: application/json' \
-H "X-API-Key: $H2H_API_KEY" \
-H "X-Secret-Key: $H2H_SECRET_KEY" \
-H 'Content-Type: application/json' \
--data '{
"game_code": "mobile-legends",
"customer_target": "123456789",
"customer_target_zone": "1234"
}'Request berhasil.
{
"success": true,
"data": {
"game_code": "mobile-legends",
"customer_target": "123456789",
"customer_target_zone": "1234",
"username": "Example Player",
"region": "ID",
"region_type": "country"
},
"billing": {
"charged_mc": 0,
"free_remaining_today": 39,
"transaction_id": null
}
}successbooleanWajibdataobjectWajibdata.game_codestringWajibdata.customer_targetstringWajibdata.customer_target_zonestring | nullWajibdata.usernamestringWajibdata.regionstring | nullWajibdata.region_typestring | nullWajibbillingobjectWajibbilling.charged_mcnumberWajibbilling.free_remaining_todayintegerWajibbilling.transaction_idstring | nullWajib
Batas pembelian Mobile Legends
/api/v1/h2h/mobile-legends/purchase-limitEndpoint pemeriksaan terpisah. Mengembalikan flag per paket; kegagalan bukan batas numerik. Berbagi jatah/billing nickname.
Dua header: X-API-Key dan X-Secret-Key
Parameter
| Nama | Tipe / sumber | Wajib | Keterangan |
|---|---|---|---|
| customer_target | string · body | Wajib | ID akun atau nomor pelanggan untuk pemeriksaan game/akun yang dipilih. Kirim sebagai string. maxLength=255 |
| customer_target_zone | string · body | Wajib | Zone/server akun sesuai zone_required dan zone_values dari GET /check-nickname/games. Wajib untuk pemeriksaan batas pembelian Mobile Legends. maxLength=100 |
curl -X POST 'https://api.melostore.id/api/v1/h2h/mobile-legends/purchase-limit' \
-H 'Accept: application/json' \
-H "X-API-Key: $H2H_API_KEY" \
-H "X-Secret-Key: $H2H_SECRET_KEY" \
-H 'Content-Type: application/json' \
--data '{
"customer_target": "123456789",
"customer_target_zone": "1234"
}'Request berhasil.
{
"success": true,
"data": {
"game_code": "mobile-legends",
"customer_target": "123456789",
"customer_target_zone": "1234",
"username": "Example Player",
"weekly_pass": {
"limit_reached": false,
"items": [
{
"package_code": "weekly-pass",
"limit_reached": false
}
]
},
"double_diamonds": {
"eligible": true,
"items": [
{
"package_code": "double-diamonds-50",
"limit_reached": false
}
]
}
},
"billing": {
"charged_mc": 0,
"free_remaining_today": 39,
"transaction_id": null
}
}successbooleanWajibdataobjectWajibdata.game_codestringWajibdata.customer_targetstringWajibdata.customer_target_zonestringWajibdata.usernamestringWajibdata.weekly_passobjectWajibdata.weekly_pass.limit_reachedbooleanWajibdata.weekly_pass.itemsarrayWajibdata.weekly_pass.items[].package_codestringWajibdata.weekly_pass.items[].limit_reachedbooleanWajibdata.double_diamondsobjectWajibdata.double_diamonds.eligiblebooleanWajibdata.double_diamonds.itemsarrayWajibdata.double_diamonds.items[].package_codestringWajibdata.double_diamonds.items[].limit_reachedbooleanWajibbillingobjectWajibbilling.charged_mcnumberWajibbilling.free_remaining_todayintegerWajibbilling.transaction_idstring | nullWajib
Callback reguler, Smart, dan anak bulk
Masukkan hanya Webhook URL di dashboard. Webhook Secret dibuat otomatis bersama API Key dan Secret Key melalui Rotate Keys, ditampilkan sekali, lalu disimpan pada server penerima webhook. Setiap rotasi mengganti ketiganya; perbarui secret penerima agar verifikasi callback berikutnya tetap berhasil.
Callback hasil akhir dikirim pada success/failed; event transaction.action_change juga dapat dikirim saat processing. Pesanan yang dibuat manual melalui dashboard tidak mengirim callback. Untuk bulk, callback dikirim per transaksi; gunakan GET /bulk-orders/{id} untuk ringkasan progres. Callback yang sama dapat diterima lebih dari sekali.
Field umum: id, buyer_trx_id, sku_code, customer_target, customer_target_zone, price_charged, status, serial_number, is_sandbox, created_at, updated_at. Cocokkan callback dengan pesanan melalui id/buyer_trx_id. Pada Smart, simpan SKU yang dipesan dan baca fulfilled_sku_code untuk SKU yang berhasil dipenuhi. Harga memakai price pada respons transaksi dan price_charged pada callback; periksa saldo dan invoice untuk biaya akhir setelah refund.
Hanya Smart menambahkan max_bid, fulfilled_sku_code (null jika belum berhasil), attempts_count. Hanya anak bulk menambahkan bulk_order_id, buyer_bulk_id, bulk_sequence. Failed menambahkan error_code dan message jika tersedia. Tidak ada tambahan Smart/bulk pada callback reguler.
Verifikasi X-H2H-Signature sebagai hex HMAC-SHA256 terhadap raw body menggunakan webhook_secret. Simpan identitas event tindakan berdasarkan event_id dan versi, serta hasil akhir berdasarkan id:status sebelum merespons 2xx. Pastikan pengiriman ulang tidak memproses pesanan atau saldo dua kali. Contoh penerima lanjutan dapat dibuka di bawah; sesuaikan penyimpanan event dengan aplikasi Anda.
{
"id": "11111111-1111-4111-8111-111111111111",
"buyer_trx_id": "example-order-001",
"sku_code": "EXAMPLE-10",
"customer_target": "123456789",
"customer_target_zone": "1234",
"status": "success",
"serial_number": "EXAMPLE-SN-001",
"is_sandbox": true,
"created_at": "2026-10-02T03:00:00+00:00",
"price_charged": 1000,
"updated_at": "2026-10-02T03:00:00+00:00"
}Contoh ini memakai PostgreSQL untuk menyimpan event sebelum merespons. Sesuaikan penyimpanan dengan aplikasi Anda; pertahankan verifikasi signature dan pencegahan proses ganda.
CREATE TABLE h2h_callback_inbox (
event_key VARCHAR(128) PRIMARY KEY,
payload JSONB NOT NULL,
received_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);
CREATE TABLE h2h_action_state (
transaction_id VARCHAR(255) PRIMARY KEY,
action_id UUID NOT NULL,
version BIGINT NOT NULL,
payload JSONB NOT NULL
);// npm install express pg; apply the PostgreSQL schema below first.
import express from 'express';
import { createHmac, timingSafeEqual } from 'node:crypto';
import pg from 'pg';
const secret = process.env.H2H_WEBHOOK_SECRET;
if (!secret) throw new Error('H2H_WEBHOOK_SECRET is required');
const db = new pg.Pool({ connectionString: process.env.DATABASE_URL });
const app = express();
const uuid = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
const validAction = a => a && uuid.test(a.id) && a.type === 'two_factor'
&& Number.isSafeInteger(a.version) && a.version > 0
&& ['required', 'submitted', 'resolved'].includes(a.state)
&& a.can_submit === (a.state === 'required') && typeof a.message === 'string';
// Register the raw-body route before express.json().
app.post('/h2h-callback', express.raw({ type: 'application/json', limit: '1mb' }), async (req, res) => {
const signature = req.get('X-H2H-Signature') || '';
if (!Buffer.isBuffer(req.body) || !/^[a-f0-9]{64}$/i.test(signature)) return res.sendStatus(401);
const expected = createHmac('sha256', secret).update(req.body).digest();
if (!timingSafeEqual(expected, Buffer.from(signature, 'hex'))) return res.sendStatus(401);
let event;
try { event = JSON.parse(req.body.toString('utf8')); } catch { return res.sendStatus(400); }
if (!event || typeof event.id !== 'string') return res.sendStatus(422);
const actionEvent = event.event === 'transaction.action_change';
if (actionEvent) {
if (!uuid.test(event.event_id) || !validAction(event.action)
|| !['pending', 'processing', 'success', 'failed'].includes(event.status)
|| event.need_action !== (event.action.state === 'required')) return res.sendStatus(422);
} else if (event.event || !['success', 'failed'].includes(event.status)) return res.sendStatus(422);
if (event.action && !validAction(event.action)) return res.sendStatus(422);
const key = actionEvent ? 'action:' + event.event_id + ':' + event.action.version : event.id + ':' + event.status;
let client;
try {
client = await db.connect(); await client.query('BEGIN');
const inserted = await client.query('INSERT INTO h2h_callback_inbox(event_key, payload) VALUES ($1, $2::jsonb) ON CONFLICT (event_key) DO NOTHING RETURNING event_key', [key, JSON.stringify(event)]);
if (inserted.rowCount && event.action) {
await client.query('INSERT INTO h2h_action_state(transaction_id, action_id, version, payload) VALUES ($1, $2, $3, $4::jsonb) ON CONFLICT (transaction_id) DO UPDATE SET version=EXCLUDED.version, payload=EXCLUDED.payload WHERE h2h_action_state.action_id=EXCLUDED.action_id AND h2h_action_state.version < EXCLUDED.version', [event.id, event.action.id, event.action.version, JSON.stringify(event.action)]);
}
await client.query('COMMIT');
// Inbox workers handle action events separately from final results.
// An action event never settles an order or changes balances. Read the
// latest h2h_action_state; older versions must not reopen the buyer form.
return res.sendStatus(200); // Includes duplicates and older action versions.
} catch { if (client) await client.query('ROLLBACK'); return res.sendStatus(500); }
finally { client?.release(); }
});
app.listen(3000);<?php
// Apply the PostgreSQL schema below first.
$secret = getenv('H2H_WEBHOOK_SECRET');
if (!$secret) { http_response_code(500); exit; }
$raw = file_get_contents('php://input');
$signature = $_SERVER['HTTP_X_H2H_SIGNATURE'] ?? '';
if (!preg_match('/^[a-f0-9]{64}$/i', $signature) || !hash_equals(hash_hmac('sha256', $raw, $secret), strtolower($signature))) { http_response_code(401); exit; }
try { $event = json_decode($raw, true, 512, JSON_THROW_ON_ERROR); } catch (JsonException $e) { http_response_code(400); exit; }
$uuid = fn($s) => is_string($s) && preg_match('/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i', $s);
$validAction = fn($a) => is_array($a) && $uuid($a['id'] ?? null) && ($a['type'] ?? '') === 'two_factor'
&& is_int($a['version'] ?? null) && $a['version'] > 0
&& in_array($a['state'] ?? '', ['required', 'submitted', 'resolved'], true)
&& ($a['can_submit'] ?? null) === ($a['state'] === 'required') && is_string($a['message'] ?? null);
if (!is_array($event) || !is_string($event['id'] ?? null)) { http_response_code(422); exit; }
$actionEvent = ($event['event'] ?? '') === 'transaction.action_change';
if ($actionEvent) {
if (!$uuid($event['event_id'] ?? null) || !$validAction($event['action'] ?? null)
|| !in_array($event['status'] ?? '', ['pending','processing','success','failed'], true)
|| ($event['need_action'] ?? null) !== ($event['action']['state'] === 'required')) { http_response_code(422); exit; }
} elseif (isset($event['event']) || !in_array($event['status'] ?? '', ['success','failed'], true)) { http_response_code(422); exit; }
if (isset($event['action']) && !$validAction($event['action'])) { http_response_code(422); exit; }
$key = $actionEvent ? 'action:'.$event['event_id'].':'.$event['action']['version'] : $event['id'].':'.$event['status'];
try {
$db = new PDO(getenv('DATABASE_DSN'), getenv('DATABASE_USER'), getenv('DATABASE_PASSWORD'), [PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION]);
$db->beginTransaction();
$stmt = $db->prepare('INSERT INTO h2h_callback_inbox(event_key, payload) VALUES (:key, CAST(:payload AS jsonb)) ON CONFLICT (event_key) DO NOTHING RETURNING event_key');
$stmt->execute(['key' => $key, 'payload' => $raw]);
if ($stmt->fetchColumn() && isset($event['action'])) {
$upsert = $db->prepare('INSERT INTO h2h_action_state(transaction_id, action_id, version, payload) VALUES (:trx, :action, :version, CAST(:payload AS jsonb)) ON CONFLICT (transaction_id) DO UPDATE SET version=EXCLUDED.version, payload=EXCLUDED.payload WHERE h2h_action_state.action_id=EXCLUDED.action_id AND h2h_action_state.version < EXCLUDED.version');
$upsert->execute(['trx' => $event['id'], 'action' => $event['action']['id'], 'version' => $event['action']['version'], 'payload' => json_encode($event['action'])]);
}
$db->commit();
// Separate action events from final results in inbox workers. Never settle
// an order for an action event; use the latest action version for the form.
http_response_code(200); echo 'OK';
} catch (Throwable $e) { if (isset($db) && $db->inTransaction()) $db->rollBack(); http_response_code(500); }
Import koleksi dan environment
Unduh OpenAPI 3.1.0 atau Postman Collection v2.1 serta environment template. Di Postman pilih Import file, import environment, lalu pilih environment tersebut. Isi api_key/secret_key dari hasil Generate/Rotate Keys; semua kredensial template kosong. Simpan webhook_secret dari modal yang sama pada server penerima callback. base_url menunjuk API, tanpa prefix locale.
Ambil katalog terlebih dahulu. Isi sku_code untuk reguler/bulk, smart_sku_code untuk Smart, customer_target, zone, dan additional_data sesuai inquiry. Set buyer_trx_id untuk reguler, smart_buyer_trx_id untuk Smart, dan buyer_bulk_id untuk bulk sekali per pesanan; script tidak menggantinya otomatis saat retry. Script create menyimpan transaction_id/bulk_order_id untuk request berikutnya. Buka daftar brand sesuai katalog; script menyimpan brand_id dan category_slug dari hasil pertama. Untuk 2FA, cek status pesanan yang benar terlebih dahulu agar action_buyer_trx_id, action_id, dan action_version terisi, lalu isi two_factor_code dari pembeli.
Folder callback hanya saved examples dan petunjuk penerima, tanpa request otomatis ke URL partner. Template webhook_secret digunakan untuk penerima callback, bukan header autentikasi API. Jangan menjalankan bulk invoice pada sandbox: endpoint akan memberikan 409. Untuk bulk live yang sudah final gunakan Send and Download pada endpoint invoice atau menu Bulk Order.