Developer · API
Quickstart
Buat request pertama menggunakan sesi yang sudah ada, kemudian pahami alur katalog → quote → order tanpa menjalankan pembelian secara tidak sengaja.
Unduh OpenAPI 3.1- Jalankan instalasi sendiri atau gunakan staging yang kamu kelola. Provider harus dikonfigurasi dan katalog disinkron sebelum quote tersedia.
- Masuk melalui /login dengan akun uji. Sesi milik akun itu akan menentukan akses resource.
- Mulai dari request GET. Jangan menguji pembelian, pembatalan, penyelesaian, atau top-up pada akun produksi tanpa memahami dampaknya.
Jalankan contoh ini dari frontend pada origin aplikasi, atau DevTools browser setelah login. Tidak perlu API key. Request ini tidak membuat order atau pembayaran.
const response = await fetch("/api/me", {
credentials: "same-origin",
cache: "no-store",
});
const body = await response.json();
if (!response.ok || !body.ok) {
throw new Error(body.error?.message ?? "Request gagal");
}
const { user, balance, held, available } = body.data;Untuk mengembangkan source ping, gunakan wrapper api yang sudah memeriksa envelope dan melempar RequestError. Isi pilihan layanan/negara dari kedua array katalog, lalu ambil quote saat pengguna memilih. ID di contoh referensi bukan ID katalog yang valid pada instalasimu.
import { api, quoteKey } from "@/lib/ping/client";
import type { Country, Quote, Service } from "@/lib/ping/types";
const [services, countries] = await Promise.all([
api<Service[]>("/api/catalog/services"),
api<Country[]>("/api/catalog/countries"),
]);
async function loadQuote(serviceId: string, countryId: string) {
return api<Quote>(quoteKey(countryId, serviceId));
}Tangani katalog kosong dan quote tidak tersedia sebagai keadaan nyata. Jangan mengganti katalog akun dengan demo-data. Jumlah qualitative_stock bukan stok kuantitatif yang dijamin.
Pemanggilan buyNumber menahan saldo dan dapat membeli nomor nyata. Buat clientRequestId satu kali saat niat pembelian dimulai, simpan bersama intent/payload pending, dan teruskan UUID yang sama untuk pemulihan request tersebut. Jangan memanggil fungsi dari render atau effect otomatis.
import { usePing } from "@/lib/ping/client";
import type { Quote } from "@/lib/ping/types";
const { buyNumber } = usePing();
async function submitConfirmedOrder(
quote: Quote,
optionId: string,
clientRequestId: string,
) {
const option = quote.options.find((item) => item.id === optionId);
if (!option) throw new Error("Pilih harga yang tersedia");
return buyNumber(
quote.countryId,
quote.serviceId,
clientRequestId,
option,
);
}Panggil usePing pada bagian atas client component atau custom hook, lalu gunakan fungsi di event handler konfirmasi. Nonaktifkan tombol selama request berjalan. priceOptionId dan expectedPriceIdr wajib dikirim pada setiap POST /api/orders, termasuk replay. maxPriceIdr opsional hanya setelah pengguna menyetujui batas per nomor secara eksplisit; simpan pada intent dan teruskan sebagai argumen keenam buyNumber. Tanpa persetujuan, fallback hanya boleh memakai harga yang tidak lebih tinggi dari harga awal. Rentang fallback_price_min_idr–fallback_price_max_idr berasal dari kandidat visible dan eligible, bukan izin menaikkan harga. Jika harga awal berubah, ambil quote baru dan minta persetujuan ulang; jangan menghapus field harga atau mengubah ceiling pada replay.
Gunakan useOrder(id) di client component untuk polling 5 detik, action cancel/complete, dan revalidasi cache. Hook berjalan di AccountProvider untuk akun nyata atau PreviewProvider untuk review UI. Jangan mengimpor store preview sebagai sumber data produksi.
import { useOrder } from "@/lib/ping/client";
const { data: order, error, cancel, complete } = useOrder(orderId);
const preparing = order?.isPreparing ?? false;
const otp = order?.code;
const showComplete = order?.canComplete ?? false;
const allowCancel = order?.canCancel ?? false;