Menu utama

Developer · API

Katalog & harga

Baca layanan, negara, dan opsi harga sebelum membuat order. Identitas dan harga selalu berasal dari server.

Unduh OpenAPI 3.1

Sebelum mengirim request

Katalog memerlukan sesi walaupun hanya dibaca. Jangan mengirim nama layanan, kode ISO negara, atau ID provider sebagai pengganti id dari katalog. Quote bukan reservasi nomor dan dapat berubah saat konfirmasi.

Kontrak nyata, nilai contoh

Endpoint, field, dan status HTTP mengikuti implementasi. Nilai ID, nomor, OTP, waktu, saldo, serta quote di contoh adalah ilustrasi, bukan data akun atau pilihan yang bisa langsung dibeli. Ganti dengan data dari instalasimu. Halaman ini tidak mengirim request atau menjalankan transaksi.

JavaScript dijalankan pada origin aplikasi setelah login. Contoh cURL memakai PING_ORIGIN dan cookie jar PING_COOKIE_JAR dari panduan autentikasi. Sukses memakai { ok: true, data }; create juga HTTP 200, bukan 201. Semua endpoint di halaman ini memerlukan sesi aktif dan dapat mengembalikan 401, 403, atau 500.

Daftar layanan

GET/api/catalog/servicesSession cookie

Mengembalikan layanan yang diaktifkan operator dan masih tercantum di katalog provider. Respons berupa array tanpa pagination. v1 menyertakan reliable dari riwayat penerimaan SMS nyata seluruh pengguna di ping, cukup minimal satu event CODE_RECEIVED tanpa batas usia atau syarat pesanan selesai; hanya boolean agregat yang dikirim tanpa identitas pelanggan atau isi SMS. UI memeriksa setiap 15 detik; katalog master tetap mengikuti sinkronisasi admin, bukan scan stok seluruh produk. Filter kategori/pencarian pada UI dilakukan client-side, bukan lewat parameter endpoint ini.

Daftar layanan
ParameterTipeWajibKeterangan
provider (query)all | v1 | v2 | v3 | v4TidakTanpa parameter, katalog menggabungkan server aktif. Pilih v1–v4 untuk satu server dan gunakan identitas dari quote untuk pembelian. Nama penyedia internal bukan bagian dari kontrak publik.
GET /api/catalog/services · JavaScript
const response = await fetch("/api/catalog/services?provider=all", {
  credentials: "same-origin",
  cache: "no-store",
});
const body = await response.json();

if (!response.ok || !body.ok) {
  throw Object.assign(
    new Error(body.error?.message ?? "Request gagal"),
    { code: body.error?.code, status: response.status },
  );
}

const data = body.data;
Daftar layanan
Kode errorHTTPTindakan
PROVIDER_ERROR502Baca ulang status. Jangan retry pembelian upstream secara otomatis.
PROVIDER_UNAVAILABLE503Periksa konfigurasi server; lanjutkan pembacaan dengan backoff.

Daftar negara

GET/api/catalog/countriesSession cookie

Tanpa serviceId mengembalikan katalog negara aktif. Dengan serviceId hanya negara yang memiliki penawaran tersedia pada layanan/server tersebut: Pada katalog gabungan, price_idr mengambil penawaran tersedia termurah dari semua server yang eligible. Opsi yang direkomendasikan memakai harga opsinya sendiri pada konfirmasi pembelian. qualitative_stock merangkum ketersediaan, dan stock_count menjumlahkan stok semua pilihan harga yang tersedia setelah deduplikasi bucket yang sama. Total bukan jaminan atau reservasi stok; null jika ada jumlah yang tidak diketahui atau total tidak aman direpresentasikan. Pembacaan provider digabung per layanan; v1 memakai cache maksimum 10 detik dan menunggu upstream saat kedaluwarsa, server lain tetap 60 detik. UI v1 memeriksa setiap 15 detik saat tab terlihat/online serta saat kembali fokus. Harga mulai adalah pilihan tersedia termurah, tidak mengikuti badge sukses. reliable bernilai true jika server, layanan, dan negara yang sama pernah menerima SMS minimal sekali dari riwayat seluruh pengguna, termasuk pesanan aktif dan riwayat lama. Hanya boolean yang dikirim, bukan identitas atau isi SMS; bukan jaminan OTP. Kegagalan provider bukan daftar kosong. Gunakan id untuk quote/order. Harga final tetap diperiksa lagi.

Daftar negara
ParameterTipeWajibKeterangan
provider (query)all | v1 | v2 | v3 | v4TidakTanpa parameter, katalog menggabungkan server aktif. Pilih v1–v4 untuk satu server dan gunakan identitas dari quote untuk pembelian. Nama penyedia internal bukan bagian dari kontrak publik.
serviceId (query)stringTidak
GET /api/catalog/countries · JavaScript
const response = await fetch("/api/catalog/countries?provider=all&serviceId=service-example", {
  credentials: "same-origin",
  cache: "no-store",
});
const body = await response.json();

if (!response.ok || !body.ok) {
  throw Object.assign(
    new Error(body.error?.message ?? "Request gagal"),
    { code: body.error?.code, status: response.status },
  );
}

const data = body.data;
Daftar negara
Kode errorHTTPTindakan
VALIDATION_ERROR400Periksa tipe, field wajib, format UUID, dan field tambahan.
SERVICE_UNAVAILABLE422Muat ulang katalog dan pilih layanan yang tersedia.
PROVIDER_ERROR502Baca ulang status. Jangan retry pembelian upstream secara otomatis.
RATE_LIMITED429Hormati Retry-After sebelum meminta ulang. Jangan retry pembelian otomatis atau membuat clientRequestId baru saat hasil awal belum pasti.

Kecepatan SMS server

GET/api/catalog/serversSession cookie

Status orderingEnabled menggabungkan pengaturan admin dan konfigurasi provider untuk pesanan baru per server. orderingPauseReason membedakan jeda manual dari provider yang belum dikonfigurasi. Saldo provider tidak menjeda pembelian secara otomatis. Bukan jaminan stok. Statistik milik akun bersesi dari SMS pertama yang tercatat dalam 30 hari terakhir; tidak membaca isi SMS atau histori akun lain. Mengukur purchaseFinishedAt ke event CODE_RECEIVED unik, termasuk jeda polling. Tanpa waktu aktivasi tidak dihitung. Label tercepat memerlukan minimal 3 sampel setiap server aktif; server dijeda dan hasil seri tidak diberi label. Bukan jaminan pengiriman berikutnya. Parameter query ditolak.

GET /api/catalog/servers · JavaScript
const response = await fetch("/api/catalog/servers", {
  credentials: "same-origin",
  cache: "no-store",
});
const body = await response.json();

if (!response.ok || !body.ok) {
  throw Object.assign(
    new Error(body.error?.message ?? "Request gagal"),
    { code: body.error?.code, status: response.status },
  );
}

const data = body.data;
Kecepatan SMS server
Kode errorHTTPTindakan
VALIDATION_ERROR400Periksa tipe, field wajib, format UUID, dan field tambahan.

Ambil penawaran harga

GET/api/catalog/quotesSession cookie

Membaca quote satu pasangan layanan/negara pada provider yang dipilih, dengan refresh cache bila diperlukan. Quote v1 kedaluwarsa maksimal 10 detik sejak fetch, termasuk cache lama; server lain tetap 5 menit. UI konfirmasi v1 memeriksa setiap 15 detik dan saat kembali fokus, tanpa polling saat hasil pembelian belum pasti. reliable pada opsi v1 berasal dari riwayat SMS nyata di ping untuk bucket yang sama, bukan jaminan sukses. serviceId dan countryId wajib; parameter query lain di luar kontrak ditolak. Pada katalog gabungan, opsi dengan riwayat OTP 7 hari yang cukup dapat diberi recommended=true dan menjadi pilihan awal konfirmasi; bila beberapa server sama kuatnya, pilihan awal bergiliran antarakun dan berganti tiap jam. Tanpa riwayat cukup, tidak ada opsi yang diberi recommended dan opsi termurah menjadi pilihan awal. Opsi tetap diurutkan dari harga termurah; pengguna dapat memilih harga lain. Rekomendasi bukan klaim kecepatan atau jaminan OTP. Harga dan opsi tetap divalidasi lagi saat pembelian.

Ambil penawaran harga
ParameterTipeWajibKeterangan
provider (query)all | v1 | v2 | v3 | v4TidakTanpa parameter, katalog menggabungkan server aktif. Pilih v1–v4 untuk satu server dan gunakan identitas dari quote untuk pembelian. Nama penyedia internal bukan bagian dari kontrak publik.
serviceId (query)stringYaService.id dari katalog.
countryId (query)stringYaCountry.id dari katalog.
GET /api/catalog/quotes · JavaScript
const response = await fetch("/api/catalog/quotes?provider=all&serviceId=service-example&countryId=country-example", {
  credentials: "same-origin",
  cache: "no-store",
});
const body = await response.json();

if (!response.ok || !body.ok) {
  throw Object.assign(
    new Error(body.error?.message ?? "Request gagal"),
    { code: body.error?.code, status: response.status },
  );
}

const data = body.data;
Ambil penawaran harga
Kode errorHTTPTindakan
VALIDATION_ERROR400Periksa tipe, field wajib, format UUID, dan field tambahan.
SERVICE_UNAVAILABLE422Muat ulang katalog dan pilih layanan yang tersedia.
COUNTRY_UNAVAILABLE422Muat ulang katalog dan pilih negara yang tersedia.
PRICE_UNAVAILABLE422Tawarkan pasangan lain atau coba baca quote lagi nanti.
PROVIDER_ERROR502Baca ulang status. Jangan retry pembelian upstream secara otomatis.
RATE_LIMITED429Hormati Retry-After sebelum meminta ulang. Jangan retry pembelian otomatis atau membuat clientRequestId baru saat hasil awal belum pasti.

Schema · Service

Schema · Service
FieldTipeWajibKeterangan
providerv1 | v2 | v3 | v4YaIdentitas server publik v1–v4. Gunakan nilai dari katalog atau quote, bukan nama penyedia di belakang server. Setiap pesanan tetap terikat ke servernya. Fallback sebelum aktivasi memakai pesanan terpisah setelah penolakan terkonfirmasi, bukan memindahkan pesanan aktif.
idstringYaID internal dari katalog server yang dipilih. Bukan nama layanan atau kode provider.
namestringYaNama layanan untuk ditampilkan.
iconstringYaKunci ikon layanan, bukan URL gambar.
categorystringYaLabel kategori untuk tampilan.
descriptionstringYaSesuai tipe yang ditampilkan.
reliablebooleanTidakOpsional pada katalog v1: true jika layanan pada server ini pernah menerima SMS minimal sekali dari riwayat nyata seluruh pengguna di ping. Tanpa batas usia atau syarat pesanan selesai. Tanpa bukti bernilai false; bukan jaminan OTP atau statistik upstream.

Schema · Country

Schema · Country
FieldTipeWajibKeterangan
providerv1 | v2 | v3 | v4YaIdentitas server publik v1–v4. Gunakan nilai dari katalog atau quote, bukan nama penyedia di belakang server. Setiap pesanan tetap terikat ke servernya. Fallback sebelum aktivasi memakai pesanan terpisah setelah penolakan terkonfirmasi, bukan memindahkan pesanan aktif.
idstringYaID internal dari katalog server yang dipilih. Bukan kode ISO atau kode provider.
namestringYaSesuai tipe yang ditampilkan.
flagstringYaLabel bendera untuk tampilan; jangan dipakai sebagai identifier.
dialstringYaKode panggilan negara untuk tampilan.
iso2stringYaKode negara yang tersedia pada metadata.
price_idrintegerTidakHanya pada daftar negara dengan serviceId: harga mulai, bukan reservasi.
qualitative_stockavailable | limitedTidakHanya pada daftar negara dengan serviceId.
reliablebooleanTidakHanya pada daftar negara dengan serviceId: true jika server, layanan, dan negara yang sama pernah menerima SMS minimal sekali dari riwayat seluruh pengguna, termasuk pesanan aktif dan riwayat lama. Tidak mengungkap identitas atau isi SMS; bukan jaminan OTP.
otp_delivery_7dobjectTidakOpsional pada daftar negara dengan serviceId: jumlah nomor yang menerima CODE_RECEIVED kanonis dibanding sampel nomor yang dibuat dalam 7 hari, sudah terbit, dan sudah menerima OTP atau berstatus COMPLETED/CANCELLED/EXPIRED. Pesanan menunggu tanpa OTP dan gagal provisioning dikecualikan. Katalog gabungan hanya menjumlahkan sumber yang sedang visible dan eligible. Persentase baru ditampilkan mulai 10 sampel; tanpa identitas atau isi SMS, bukan peluang atau jaminan OTP berikutnya.
stock_countinteger | nullTidakHanya pada daftar negara dengan serviceId: total stok pilihan harga eligible dan visible menurut filter selector dengan biaya provider maksimal USD0.50 (inklusif); negara yang hanya punya stok di atas batas ini tidak ditampilkan, setelah deduplikasi bucket yang sama. Null jika ada jumlah tidak diketahui atau total tidak aman; laporan pool dapat overlap, bukan jumlah nomor unik atau reservasi.

Schema · Quote

Schema · Quote
FieldTipeWajibKeterangan
providerv1 | v2 | v3 | v4TidakAda pada kuotasi satu provider; tidak dikirim untuk provider=all. Gunakan options[].selection untuk katalog gabungan.
serviceIdstringYaSesuai tipe yang ditampilkan.
countryIdstringYaSesuai tipe yang ditampilkan.
price_idrintegerYaHarga opsi pertama. Konfirmasi memakai harga opsi yang dipilih.
price_min_idrintegerTidakPada katalog gabungan: harga minimum dari pilihan visible dan eligible.
price_max_idrintegerTidakPada katalog gabungan: harga maksimum dari pilihan visible dan eligible; bukan batas yang otomatis disetujui.
qualitative_stockavailable | limitedYaKetersediaan kualitatif, bukan jumlah stok yang dijamin.
stock_countinteger | nullYaJumlah yang dilaporkan provider untuk pilihan harga ini, bukan jaminan atau reservasi stok. Null jika snapshot cache lama belum menyimpan jumlah.
optionsQuoteOption[]YaPilihan harga yang tersedia saat quote diambil.
fetched_atstring · date-timeYaISO 8601 dengan zona waktu.
expires_atstring · date-timeYaMasa berlaku terpendek kandidat quote; bukan reservasi harga atau nomor.

Schema · QuoteOption

Schema · QuoteOption
FieldTipeWajibKeterangan
idstringYaID pilihan harga; teruskan sebagai priceOptionId, jangan buat sendiri.
price_idrintegerYaRupiah utuh, bukan sen atau string berformat.
qualitative_stockavailable | limitedYaKetersediaan kualitatif, bukan jumlah stok yang dijamin.
stock_countinteger | nullYaJumlah yang dilaporkan provider untuk pilihan harga ini, bukan jaminan atau reservasi stok. Null jika snapshot cache lama belum menyimpan jumlah.
operatorobjectTidakOpsional: operator seluler yang dipin pilihan ini ketika didukung provider. Key stabil dan opaque, bukan ID upstream atau nama provider. Kelompokkan menurut key, lalu kirim id opsi sebagai priceOptionId; fallback tetap operator yang sama. Tanpa field ini tidak ada batasan operator.
selectionobjectTidakPada katalog gabungan: target pembelian awal yang persis, termasuk provider dan ID sumbernya.
recommendedbooleanTidakOpsional pada katalog gabungan: pilihan awal, tetap memakai harga opsi ini. Jika ada riwayat tier valid minimal 10 sampel dan pernah OTP, acuannya batas bawah Wilson 95%; tier lain yang tidak terbukti lebih buruk (batas atas Wilson-nya mencapai acuan itu) dan paling mahal 10% di atasnya bergiliran menjadi pilihan awal per akun, layanan, negara, dan jam. Tanpa bukti cukup, tidak ada opsi yang diberi recommended. Bukan peluang, klaim kecepatan, atau jaminan OTP. Opsi termurah tetap diurutkan lebih dulu dan dapat dipilih.
otp_delivery_7dobjectTidakOpsional: received dan samples dari nomor yang dibuat dalam 7 hari pada exact tier upstream pilihan awal. Hanya nomor terbit yang sudah menerima OTP atau berstatus COMPLETED/CANCELLED/EXPIRED; menunggu tanpa OTP dan gagal provisioning dikecualikan. Menggunakan CODE_RECEIVED kanonis, tidak mencampur provider/produk/operator/tier atau opsi berharga sama. Persentase tampil mulai 10 sampel; bukan peluang atau jaminan OTP berikutnya.
fallback_price_min_idrintegerTidakPada katalog gabungan: harga minimum pilihan awal dan alternatif eligible. Jika opsi memiliki operator, hanya alternatif dengan operator.key yang sama.
fallback_price_max_idrintegerTidakPada katalog gabungan: harga maksimum pilihan awal dan alternatif eligible untuk operator yang sama jika dipin, bukan persetujuan otomatis. Harga di atas pilihan awal memerlukan maxPriceIdr eksplisit.
otp_eta_secondsintegerTidakOpsional: median detik ACTIVE ke CODE_RECEIVED pertama pada exact tier upstream. Mengutamakan 6 jam terakhir, lalu histori hingga 7 hari, minimal 1 sampel dengan identity dan latency terverifikasi. Tidak menunggu aktivasi kedaluwarsa atau mensyaratkan persentase keberhasilan; hanya mengukur waktu pada OTP yang masuk, bukan peluang OTP. Pada katalog gabungan mengikuti tier pilihan awal, tidak mencampur histori opsi berharga sama atau provider fallback. Sampel bisa terbatas; bukan jaminan OTP.
last_otp_received_atstring · date-timeTidakOpsional: waktu CODE_RECEIVED kanonis terakhir yang valid dalam histori 7 hari pada exact tier upstream pilihan awal. Tidak mencampur provider, produk, operator, atau tier harga; tidak berisi kode OTP atau identitas pengguna. Bukan jaminan OTP berikutnya.
reliablebooleanTidakOpsional untuk v1: true jika server, layanan, negara, produk, operator, dan bucket harga yang sama pernah menerima SMS minimal sekali dari riwayat seluruh pengguna. Termasuk pesanan aktif dan riwayat lama. Tidak memakai stok atau status selesai sebagai bukti, dan bukan jaminan OTP.

ping! · Panduan yang tumbuh bersama produknya.