Akses programatik ke nomor virtual, pesanan, dan saldo akun.
Direkomendasikan
⟩Mulai dengan SDK resmi
Gunakan SDK TypeScript/JavaScript atau Python untuk integrasi baru. Kedua SDK default ke API publik /v2, menjaga idempotency key saat retry aman, mengekspos error bertipe, dan menjaga lifecycle OTP tetap konsisten.
Buat order dengan product_id untuk tier-slot stabil yang spesifik, atau dengan catalog_product_id, opsional operator_id, min_price/max_price, dan idempotency key agar panggilan berbayar aman saat retry.
catalog_product_idmax_priceIdempotency-Key
02
Gunakan OTP
Tunggu OTP, kirim di aplikasi target, lalu panggil finish untuk menutup order.
waitForOtpwait_for_otpfinish
03
Resend hanya bila perlu
Setelah resend, tunggu kode baru dengan afterCode di TypeScript atau after_code di Python.
can_resendresend_available_at
import { SmscodeClient, OtpTimeoutError } from "@smscode/sdk";const client = new SmscodeClient({ token: process.env.SMSCODE_TOKEN! });let orderId: number | undefined;try { const created = await client.orders.create({ catalog_product_id: Number(process.env.SMSCODE_CATALOG_PRODUCT_ID), max_price: "0.50", quantity: 1, }); const order = created.orders[0]!; orderId = order.id; const first = await client.orders.waitForOtp(orderId, { timeoutMs: 120_000 }); console.log(first.otpCode); // Kirim kode ini di aplikasi target. await client.orders.finish(orderId);} catch (err) { if (err instanceof OtpTimeoutError && orderId !== undefined) { const current = await client.orders.get(orderId); if (current.can_cancel) await client.orders.cancel(orderId); } throw err;}
import osfrom smscode import OtpTimeoutError, SmscodeClientwith SmscodeClient(token=os.environ["SMSCODE_TOKEN"]) as client: created = client.orders.create( catalog_product_id=int(os.environ["SMSCODE_CATALOG_PRODUCT_ID"]), max_price="0.50", quantity=1, ) order = created.orders[0] order_id = int(order["id"]) try: first = client.orders.wait_for_otp(order_id, timeout_ms=120_000) print(first.otp_code) # Kirim kode ini di aplikasi target. client.orders.finish(order_id) except OtpTimeoutError: current = client.orders.get(order_id) if current["can_cancel"]: client.orders.cancel(order_id) raise
Gunakan can_resend dan resend_available_at untuk timing resend. Timestamp resend level rendah bersifat internal dan bukan field respons publik.
⟩Gambaran Umum
Semua field uang pada API /v1 menggunakan IDR (Rupiah), sebagai satuan bilangan bulat — misalnya "price": 15000 dan "balance": 500000 berarti Rp 15.000 dan Rp 500.000. Untuk proyeksi USD-native dari ledger yang sama, beralihlah ke API v2 menggunakan tombol versi di atas.
⟩Autentikasi
Semua permintaan API memerlukan Bearer token. Buat token dari Pengaturan Akun di dashboard, lalu sertakan di setiap permintaan:
Authorization:Bearer YOUR_API_TOKEN
Permintaan tanpa token yang valid akan menerima respons 401 UNAUTHORIZED.
⟩URL Dasar
Semua path endpoint di bawah ini relatif terhadap:
https://api.smscode.gg/v1
⟩Format Respons
Setiap respons mengembalikan JSON dengan envelope yang konsisten. Semua respons menyertakan header x-request-id untuk debugging.
Semua field uang pada API /v1 menggunakan IDR (Rupiah), sebagai satuan bilangan bulat — misalnya "price": 15000 dan "balance": 500000 berarti Rp 15.000 dan Rp 500.000. Untuk proyeksi USD-native dari ledger yang sama, beralihlah ke API v2 menggunakan tombol versi di atas.
Mengembalikan daftar operator yang dapat dipilih untuk negara + layanan. Jika operator spesifik dan stok Any sama-sama tersedia, respons menyertakan baris Any dengan operator_id null; jika tidak ada produk operator-specific, daftar kosong.
Membuat pesanan nomor virtual baru. Memotong saldo secara otomatis. Mendukung header Idempotency-Key opsional untuk mencegah pesanan duplikat saat retry jaringan.
Isi Permintaan
Nama
Tipe
Wajib
Deskripsi
product_id
integer
Tidak
ID produk tier-slot stabil yang dipesan langsung. Isi SALAH SATU saja: product_id ATAU catalog_product_id, jangan keduanya.
catalog_product_id
integer
Tidak
ID umbrella negara+platform untuk routed order. Server memilih tier live yang cocok. Isi salah satu: ini atau product_id.
operator_id
integer
Tidak
ID operator opsional dari /catalog/operators. Hanya valid bersama catalog_product_id; kosongkan untuk Any.
min_price
integer
Tidak
Batas bawah harga opsional. Bilangan bulat IDR. Hanya valid bersama catalog_product_id.
max_price
integer
Tidak
Batas atas harga opsional. Bilangan bulat IDR. Hanya valid bersama catalog_product_id.
prefer_provider
string
Tidak
Kode provider opsional yang diutamakan saat beberapa penawaran setara.
policy
string
Tidak
Kebijakan routing opsional, hanya berlaku dengan catalog_product_id. Nilai: cheapest (default) memilih penawaran sehat termurah; best_success mengurutkan penawaran berdasarkan keberhasilan pengiriman terbaru lebih dulu. best_success menilai setiap provider dari proporsi pesanan yang menerima OTP selama 30 hari penuh terakhir, dalam pita 10%, dan baru menghitung suatu provider setelah punya minimal 20 pesanan pada rentang itu — provider di bawah ambang tersebut atau tanpa riwayat dianggap netral, sehingga penawaran baru tidak pernah terabaikan (opsional; sinyalnya mulai dari netral). Bila prefer_provider juga diisi, provider pilihan tetap diutamakan.
quantity
integer
Tidak
Jumlah item (1-100, default 1)
Kirim header Idempotency-Key untuk melakukan retry dengan aman tanpa membuat pesanan duplikat. Key boleh berisi huruf, angka, tanda hubung, dan garis bawah (A-Z a-z 0-9 _ -), maksimal 128 karakter; key yang tidak valid ditolak dengan 422 VALIDATION_ERROR. Retry dengan key dan body yang sama akan memutar ulang hasil aslinya (termasuk failed_count pada sukses sebagian). Retry yang sudah sampai ke penyedia tetapi gagal akan dicatat dan memutar ulang error yang sama — gunakan key BARU untuk mencoba lagi. Kegagalan tanpa efek samping (saldo tidak cukup, tidak ada penawaran tersedia) melepaskan key, sehingga Anda bisa top up dan retry dengan key yang sama. Menggunakan kembali key dengan body berbeda menghasilkan 422 IDEMPOTENCY_KEY_REUSED, dan permintaan yang masih berjalan dengan key tersebut menghasilkan 409 REQUEST_IN_PROGRESS. Field failed_reason pada respons create selalu null — field ini hanya terisi saat poll/list pesanan.
Contoh Request
curl -s -X POST https://api.smscode.gg/v1/orders/create \ -H "Authorization: Bearer YOUR_API_TOKEN" \ -H "Content-Type: application/json" \ -H "Idempotency-Key: unique-request-id-123" \ -d '{"product_id":142,"quantity":1}'# Or route by catalog_product_id — the server picks a current tier.# product_id is the stable exact tier-slot id. catalog_product_id is the# country+platform umbrella for routed ordering. Optional min_price/max_price# bound the tier; operator_id scopes to a carrier from /catalog/operators.# Pass EITHER product_id OR catalog_product_id.curl -s -X POST https://api.smscode.gg/v1/orders/create \ -H "Authorization: Bearer YOUR_API_TOKEN" \ -H "Content-Type: application/json" \ -H "Idempotency-Key: unique-request-id-124" \ -d '{"catalog_product_id":87,"min_price":12000,"max_price":20000,"operator_id":433}'
Mengaktifkan kembali nomor yang sudah selesai — memesan ulang nomor yang sama untuk kode verifikasi lain, tanpa menyewa nomor baru. Hanya pesanan yang sudah selesai yang nomornya mendukung reaktivasi yang memenuhi syarat (periksa can_reactivate pada pesanan, atau lihat pratinjau dengan reactivate-options). Pesanan anak hasil reaktivasi adalah pesanan BARU, dikembalikan dalam bentuk yang sama seperti create; saldo dipotong secara otomatis.
Isi Permintaan
Nama
Tipe
Wajib
Deskripsi
id
integer
Ya
Pesanan selesai yang akan diaktifkan kembali.
max_price
integer
Tidak
Batas atas biaya opsional. Bilangan bulat IDR. Reaktivasi ditolak dengan 422 VALIDATION_ERROR jika biaya terkini melebihinya.
Seperti create, ini adalah mutasi uang — kirim header Idempotency-Key untuk retry yang aman (sebuah create dan sebuah reactivate tidak akan pernah bertabrakan pada satu key). Menggunakan kembali key dengan body berbeda menghasilkan 422 IDEMPOTENCY_KEY_REUSED, dan permintaan yang masih diproses dengan key tersebut menghasilkan 409 REQUEST_IN_PROGRESS. Nomor yang tidak bisa diaktifkan kembali menghasilkan 409 CONFLICT; saldo yang terlalu sedikit menghasilkan 409 INSUFFICIENT_BALANCE.
Melihat pratinjau berapa biaya reaktivasi saat ini. Hanya-baca — tidak memakai Idempotency-Key dan tidak membuat apa pun. Mengembalikan biaya sebagai bilangan bulat IDR. Hanya tersedia untuk pesanan yang sudah selesai yang nomornya mendukung reaktivasi.
Path Parameter
Nama
Tipe
Wajib
Deskripsi
id
integer
Ya
ID Pesanan untuk melihat pratinjau biaya reaktivasi (parameter path).
Perbarui URL dan/atau secret webhook kamu. Secret dibuat otomatis saat kamu menetapkan URL untuk pertama kali. Kirim string kosong untuk menghapus. URL harus menggunakan HTTPS.
Isi Permintaan
Nama
Tipe
Wajib
Deskripsi
webhook_url
string
Tidak
URL HTTPS untuk menerima event webhook (string kosong untuk menghapus)
webhook_secret
string
Tidak
Shared secret untuk tanda tangan HMAC-SHA256 (dibuat otomatis jika tidak disertakan saat pertama kali)
Kirim event tes ke URL webhook yang sudah dikonfigurasi. Mengembalikan kode status HTTP dari server kamu. Berguna untuk memverifikasi endpoint berfungsi sebelum go live.
Parameter
Tidak ada
Contoh Request
curl -s -X POST https://api.smscode.gg/v1/webhook/test \ -H "Authorization: Bearer YOUR_API_TOKEN"
const res = await fetch("https://api.smscode.gg/v1/webhook/test", { method: "POST", headers: { Authorization: "Bearer YOUR_API_TOKEN" },});const data = await res.json();
Konfigurasi URL webhook untuk menerima notifikasi push real-time untuk event pesanan alih-alih polling. Ini adalah pendekatan yang direkomendasikan untuk bot script.
Event
Peristiwa
Pemicu
order.otp_received
SMS baru diterima; kode hasil parsing dapat null
order.completed
Pesanan ditandai selesai (manual atau kedaluwarsa)
order.expired
Pesanan kedaluwarsa sebelum ada SMS yang diterima (saldo dikembalikan)
order.canceled
Pesanan dibatalkan oleh pengguna (saldo dikembalikan)
Setiap SMS baru memicu event ini. otp_code dapat null saat otp_message tersedia. Beberapa event SMS dapat tiba tidak berurutan; gunakan sms_revision untuk mengabaikan pasangan agregat yang lebih lama.
Setiap permintaan webhook menyertakan header X-Webhook-Signature dengan tanda tangan HMAC-SHA256 dari body permintaan, menggunakan webhook_secret kamu sebagai kunci:
Verifikasi tanda tangan ini di server kamu untuk memastikan permintaan autentik. Pengiriman bersifat fire-and-forget dengan timeout 3 detik dan tanpa retry.
⟩Batas Permintaan
Permintaan API dibatasi per grup endpoint. Melebihi batas mengembalikan 429 Too Many Requests dengan header Retry-After yang menunjukkan berapa detik harus menunggu.
Respons error menyertakan salah satu kode berikut di error.code:
Kode
HTTP
Deskripsi
UNAUTHORIZED
401
Token API tidak ada atau tidak valid
FORBIDDEN
403
Akses ditolak
NOT_FOUND
404
Sumber daya tidak ditemukan (pesanan, kurs tukar, dll.)
CONFLICT
409
Permintaan duplikat atau konflik sumber daya
INSUFFICIENT_BALANCE
409
Saldo tidak cukup untuk membuat pesanan
VALIDATION_ERROR
422
Parameter permintaan gagal validasi
RATE_LIMIT_EXCEEDED
429
Terlalu banyak permintaan (cek header Retry-After)
INTERNAL_ERROR
500
Kesalahan server internal
PROVIDER_ERROR
422
Penyedia SMS upstream menolak permintaan. Pada kegagalan pembuatan pesanan, error dapat membawa details: cause_counts (pesanan product_id lama — rekap yang dikelompokkan per penyebab) atau attempts (pesanan catalog_product_id — hasil per percobaan), menggunakan nilai ok, no_numbers, insufficient_balance, price_rejected, provider_unavailable, provider_account_balance, provider_error.
NO_OFFER_AVAILABLE
422
Tidak ada penawaran aktif yang cocok dengan produk dan kebijakan yang diminta (batas harga, ketersediaan).
CANCEL_TOO_EARLY
409
Pesanan terlalu baru untuk dibatalkan — tunggu 2 menit
REQUEST_IN_PROGRESS
409
Permintaan pembuatan dengan idempotency key ini masih berjalan
IDEMPOTENCY_KEY_REUSED
422
Idempotency key ini sudah dipakai dengan body permintaan yang berbeda
SERVICE_UNAVAILABLE
503
Layanan sementara tidak tersedia (pemeliharaan)
⟩Gambaran Umum
Semua field uang pada API /v2 menggunakan USD, dikembalikan sebagai objek uang — { "amount": "0.92", "currency": "USD", "canonical_amount": 15000, "canonical_currency": "IDR" }. amount adalah string desimal; canonical_amount adalah nilai ledger IDR yang persis (pakai ini untuk rekonsiliasi). rate USD/IDR yang dipakai diungkap sekali per respons di meta.fx. v2 adalah proyeksi USD saat render di atas ledger IDR yang sama dengan v1 — tidak pernah menyimpan atau mentransaksikan USD.
Semua field uang pada API /v2 menggunakan USD, dikembalikan sebagai objek uang — { "amount": "0.92", "currency": "USD", "canonical_amount": 15000, "canonical_currency": "IDR" }. amount adalah string desimal; canonical_amount adalah nilai ledger IDR yang persis (pakai ini untuk rekonsiliasi). rate USD/IDR yang dipakai diungkap sekali per respons di meta.fx. v2 adalah proyeksi USD saat render di atas ledger IDR yang sama dengan v1 — tidak pernah menyimpan atau mentransaksikan USD.
Identik dengan v1 — hanya base path yang berubah (/v1 → /v2).
GET/catalog/operators
Mengembalikan daftar operator yang dapat dipilih untuk negara + layanan. Jika operator spesifik dan stok Any sama-sama tersedia, respons menyertakan baris Any dengan operator_id null; jika tidak ada produk operator-specific, daftar kosong.
v2: field uang berupa objek uang USD dan respons membawa satu meta.fx { pair, rate, rate_as_of }. rate adalah IDR bulat per 1 USD, jadi USD = canonical_amount / rate. Total memakai 2 desimal; harga/refund per item memakai 4. Nilai yang positif tidak pernah dibulatkan menjadi 0.00. rate_as_of adalah timestamp RFC3339 dari kurs tersebut (bentuk +00:00) atau null bila tidak ada timestamp yang tercatat.
v2 saja: jika tidak ada kurs USD/IDR yang dapat dipakai, endpoint uang mengembalikan 503 FX_RATE_UNAVAILABLE dengan header Retry-After alih-alih body uang. v1 tidak pernah mengembalikan ini.
GET/catalog/exchange-rate
Mengembalikan kurs tukar USD/IDR terkini yang digunakan untuk konversi mata uang.
Parameter
Tidak ada — v2 selalu mengembalikan USD/IDR; parameter ?pair dari v1 diabaikan.
v2: mengembalikan { pair, rate, rate_as_of } (tanpa base_currency/quote_currency, tanpa pembungkus meta — kursnya adalah datanya). ?pair diabaikan — v2 selalu mengembalikan USD/IDR (v1 menghormati ?pair). Mengembalikan 503 FX_RATE_UNAVAILABLE jika tidak ada kurs yang dapat dipakai.
GET/balance
Mengembalikan saldo akun pengguna yang terautentikasi.
v2: field uang berupa objek uang USD dan respons membawa satu meta.fx { pair, rate, rate_as_of }. rate adalah IDR bulat per 1 USD, jadi USD = canonical_amount / rate. Total memakai 2 desimal; harga/refund per item memakai 4. Nilai yang positif tidak pernah dibulatkan menjadi 0.00. rate_as_of adalah timestamp RFC3339 dari kurs tersebut (bentuk +00:00) atau null bila tidak ada timestamp yang tercatat.
v2 saja: jika tidak ada kurs USD/IDR yang dapat dipakai, endpoint uang mengembalikan 503 FX_RATE_UNAVAILABLE dengan header Retry-After alih-alih body uang. v1 tidak pernah mengembalikan ini.
GET/orders
Mengembalikan daftar pesanan pengguna yang terautentikasi, diurutkan dari yang terbaru. Mendukung filter berdasarkan status dan paginasi via offset.
Query Parameter
Nama
Tipe
Wajib
Deskripsi
limit
integer
Tidak
Maksimal hasil (1-100, default 20)
offset
integer
Tidak
Jumlah hasil yang dilewati (default 0)
status
string
Tidak
Filter berdasarkan status: ACTIVE, OTP_RECEIVED, COMPLETED, CANCELED, EXPIRED (tidak peka huruf besar/kecil)
v2: field uang berupa objek uang USD dan respons membawa satu meta.fx { pair, rate, rate_as_of }. rate adalah IDR bulat per 1 USD, jadi USD = canonical_amount / rate. Total memakai 2 desimal; harga/refund per item memakai 4. Nilai yang positif tidak pernah dibulatkan menjadi 0.00. rate_as_of adalah timestamp RFC3339 dari kurs tersebut (bentuk +00:00) atau null bila tidak ada timestamp yang tercatat.
v2 saja: jika tidak ada kurs USD/IDR yang dapat dipakai, endpoint uang mengembalikan 503 FX_RATE_UNAVAILABLE dengan header Retry-After alih-alih body uang. v1 tidak pernah mengembalikan ini.
GET/orders/{id}
Mengembalikan satu pesanan berdasarkan ID. Hanya mengembalikan pesanan milik pengguna yang terautentikasi.
v2: field uang berupa objek uang USD dan respons membawa satu meta.fx { pair, rate, rate_as_of }. rate adalah IDR bulat per 1 USD, jadi USD = canonical_amount / rate. Total memakai 2 desimal; harga/refund per item memakai 4. Nilai yang positif tidak pernah dibulatkan menjadi 0.00. rate_as_of adalah timestamp RFC3339 dari kurs tersebut (bentuk +00:00) atau null bila tidak ada timestamp yang tercatat.
v2 saja: jika tidak ada kurs USD/IDR yang dapat dipakai, endpoint uang mengembalikan 503 FX_RATE_UNAVAILABLE dengan header Retry-After alih-alih body uang. v1 tidak pernah mengembalikan ini.
GET/orders/active
Daftar semua pesanan yang sedang aktif (ACTIVE + OTP_RECEIVED). Gunakan ini untuk polling pembaruan status OTP.
v2: endpoint ini bukan pembawa uang — tidak mengembalikan amount maupun meta.fx (bentuknya sama dengan v1, di bawah /v2).
POST/orders/create
Membuat pesanan nomor virtual baru. Memotong saldo secara otomatis. Mendukung header Idempotency-Key opsional untuk mencegah pesanan duplikat saat retry jaringan.
Isi Permintaan
Nama
Tipe
Wajib
Deskripsi
product_id
integer
Tidak
ID produk tier-slot stabil yang dipesan langsung. Isi SALAH SATU saja: product_id ATAU catalog_product_id, jangan keduanya.
catalog_product_id
integer
Tidak
ID umbrella negara+platform untuk routed order. Server memilih tier live yang cocok. Isi salah satu: ini atau product_id.
operator_id
integer
Tidak
ID operator opsional dari /catalog/operators. Hanya valid bersama catalog_product_id; kosongkan untuk Any.
min_price
string
Tidak
Batas bawah harga opsional. String desimal USD (mis. "0.30"). Hanya valid bersama catalog_product_id.
max_price
string
Tidak
Batas atas harga opsional. String desimal USD (mis. "0.50"). Hanya valid bersama catalog_product_id.
prefer_provider
string
Tidak
Kode provider opsional yang diutamakan saat beberapa penawaran setara.
policy
string
Tidak
Kebijakan routing opsional, hanya berlaku dengan catalog_product_id. Nilai: cheapest (default) memilih penawaran sehat termurah; best_success mengurutkan penawaran berdasarkan keberhasilan pengiriman terbaru lebih dulu. best_success menilai setiap provider dari proporsi pesanan yang menerima OTP selama 30 hari penuh terakhir, dalam pita 10%, dan baru menghitung suatu provider setelah punya minimal 20 pesanan pada rentang itu — provider di bawah ambang tersebut atau tanpa riwayat dianggap netral, sehingga penawaran baru tidak pernah terabaikan (opsional; sinyalnya mulai dari netral). Bila prefer_provider juga diisi, provider pilihan tetap diutamakan.
quantity
integer
Tidak
Jumlah item (1-100, default 1)
Kirim header Idempotency-Key untuk melakukan retry dengan aman tanpa membuat pesanan duplikat. Key boleh berisi huruf, angka, tanda hubung, dan garis bawah (A-Z a-z 0-9 _ -), maksimal 128 karakter; key yang tidak valid ditolak dengan 422 VALIDATION_ERROR. Retry dengan key dan body yang sama akan memutar ulang hasil aslinya (termasuk failed_count pada sukses sebagian). Retry yang sudah sampai ke penyedia tetapi gagal akan dicatat dan memutar ulang error yang sama — gunakan key BARU untuk mencoba lagi. Kegagalan tanpa efek samping (saldo tidak cukup, tidak ada penawaran tersedia) melepaskan key, sehingga Anda bisa top up dan retry dengan key yang sama. Menggunakan kembali key dengan body berbeda menghasilkan 422 IDEMPOTENCY_KEY_REUSED, dan permintaan yang masih berjalan dengan key tersebut menghasilkan 409 REQUEST_IN_PROGRESS. Field failed_reason pada respons create selalu null — field ini hanya terisi saat poll/list pesanan.
v2: field uang berupa objek uang USD dan respons membawa satu meta.fx { pair, rate, rate_as_of }. rate adalah IDR bulat per 1 USD, jadi USD = canonical_amount / rate. Total memakai 2 desimal; harga/refund per item memakai 4. Nilai yang positif tidak pernah dibulatkan menjadi 0.00. rate_as_of adalah timestamp RFC3339 dari kurs tersebut (bentuk +00:00) atau null bila tidak ada timestamp yang tercatat.
v2 saja: jika tidak ada kurs USD/IDR yang dapat dipakai, endpoint uang mengembalikan 503 FX_RATE_UNAVAILABLE dengan header Retry-After alih-alih body uang. v1 tidak pernah mengembalikan ini.
POST/orders/cancel
Membatalkan pesanan yang aktif. Biaya sewa dikembalikan ke saldo akun kamu.
v2: field uang berupa objek uang USD dan respons membawa satu meta.fx { pair, rate, rate_as_of }. rate adalah IDR bulat per 1 USD, jadi USD = canonical_amount / rate. Total memakai 2 desimal; harga/refund per item memakai 4. Nilai yang positif tidak pernah dibulatkan menjadi 0.00. rate_as_of adalah timestamp RFC3339 dari kurs tersebut (bentuk +00:00) atau null bila tidak ada timestamp yang tercatat.
v2 saja: jika tidak ada kurs USD/IDR yang dapat dipakai, endpoint uang mengembalikan 503 FX_RATE_UNAVAILABLE dengan header Retry-After alih-alih body uang. v1 tidak pernah mengembalikan ini.
POST/orders/finish
Tandai pesanan sebagai selesai setelah menerima OTP. Ini melepaskan nomor segera alih-alih menunggu kedaluwarsa.
Identik dengan v1 — hanya base path yang berubah (/v1 → /v2).
POST/orders/reactivate
Mengaktifkan kembali nomor yang sudah selesai — memesan ulang nomor yang sama untuk kode verifikasi lain, tanpa menyewa nomor baru. Hanya pesanan yang sudah selesai yang nomornya mendukung reaktivasi yang memenuhi syarat (periksa can_reactivate pada pesanan, atau lihat pratinjau dengan reactivate-options). Pesanan anak hasil reaktivasi adalah pesanan BARU, dikembalikan dalam bentuk yang sama seperti create; saldo dipotong secara otomatis.
Isi Permintaan
Nama
Tipe
Wajib
Deskripsi
id
integer
Ya
Pesanan selesai yang akan diaktifkan kembali.
max_price
string
Tidak
Batas atas biaya opsional. String desimal USD (mis. "0.50"). Reaktivasi ditolak dengan 422 VALIDATION_ERROR jika biaya terkini melebihinya.
Seperti create, ini adalah mutasi uang — kirim header Idempotency-Key untuk retry yang aman (sebuah create dan sebuah reactivate tidak akan pernah bertabrakan pada satu key). Menggunakan kembali key dengan body berbeda menghasilkan 422 IDEMPOTENCY_KEY_REUSED, dan permintaan yang masih diproses dengan key tersebut menghasilkan 409 REQUEST_IN_PROGRESS. Nomor yang tidak bisa diaktifkan kembali menghasilkan 409 CONFLICT; saldo yang terlalu sedikit menghasilkan 409 INSUFFICIENT_BALANCE.
v2: field uang berupa objek uang USD dan respons membawa satu meta.fx { pair, rate, rate_as_of }. rate adalah IDR bulat per 1 USD, jadi USD = canonical_amount / rate. Total memakai 2 desimal; harga/refund per item memakai 4. Nilai yang positif tidak pernah dibulatkan menjadi 0.00. rate_as_of adalah timestamp RFC3339 dari kurs tersebut (bentuk +00:00) atau null bila tidak ada timestamp yang tercatat.
v2 saja: jika tidak ada kurs USD/IDR yang dapat dipakai, endpoint uang mengembalikan 503 FX_RATE_UNAVAILABLE dengan header Retry-After alih-alih body uang. v1 tidak pernah mengembalikan ini.
GET/orders/{id}/reactivate-options
Melihat pratinjau berapa biaya reaktivasi saat ini. Hanya-baca — tidak memakai Idempotency-Key dan tidak membuat apa pun. Mengembalikan biaya sebagai objek uang USD dengan tanda terima FX. Hanya tersedia untuk pesanan yang sudah selesai yang nomornya mendukung reaktivasi.
Path Parameter
Nama
Tipe
Wajib
Deskripsi
id
integer
Ya
ID Pesanan untuk melihat pratinjau biaya reaktivasi (parameter path).
v2: field uang berupa objek uang USD dan respons membawa satu meta.fx { pair, rate, rate_as_of }. rate adalah IDR bulat per 1 USD, jadi USD = canonical_amount / rate. Total memakai 2 desimal; harga/refund per item memakai 4. Nilai yang positif tidak pernah dibulatkan menjadi 0.00. rate_as_of adalah timestamp RFC3339 dari kurs tersebut (bentuk +00:00) atau null bila tidak ada timestamp yang tercatat.
v2 saja: jika tidak ada kurs USD/IDR yang dapat dipakai, endpoint uang mengembalikan 503 FX_RATE_UNAVAILABLE dengan header Retry-After alih-alih body uang. v1 tidak pernah mengembalikan ini.
GET/webhook
Mengembalikan konfigurasi notifikasi webhook kamu saat ini.
Identik dengan v1 — hanya base path yang berubah (/v1 → /v2).
PATCH/webhook
Perbarui URL dan/atau secret webhook kamu. Secret dibuat otomatis saat kamu menetapkan URL untuk pertama kali. Kirim string kosong untuk menghapus. URL harus menggunakan HTTPS.
Isi Permintaan
Nama
Tipe
Wajib
Deskripsi
webhook_url
string
Tidak
URL HTTPS untuk menerima event webhook (string kosong untuk menghapus)
webhook_secret
string
Tidak
Shared secret untuk tanda tangan HMAC-SHA256 (dibuat otomatis jika tidak disertakan saat pertama kali)
Identik dengan v1 — hanya base path yang berubah (/v1 → /v2).
POST/webhook/test
Kirim event tes ke URL webhook yang sudah dikonfigurasi. Mengembalikan kode status HTTP dari server kamu. Berguna untuk memverifikasi endpoint berfungsi sebelum go live.
Parameter
Tidak ada
Contoh Request
curl -s -X POST https://api.smscode.gg/v2/webhook/test \ -H "Authorization: Bearer YOUR_API_TOKEN"
const res = await fetch("https://api.smscode.gg/v2/webhook/test", { method: "POST", headers: { Authorization: "Bearer YOUR_API_TOKEN" },});const data = await res.json();
Identik dengan v1 — hanya base path yang berubah (/v1 → /v2).
⟩Notifikasi Webhook
Konfigurasi URL webhook untuk menerima notifikasi push real-time untuk event pesanan alih-alih polling. Ini adalah pendekatan yang direkomendasikan untuk bot script.
Event
Peristiwa
Pemicu
order.otp_received
SMS baru diterima; kode hasil parsing dapat null
order.completed
Pesanan ditandai selesai (manual atau kedaluwarsa)
order.expired
Pesanan kedaluwarsa sebelum ada SMS yang diterima (saldo dikembalikan)
order.canceled
Pesanan dibatalkan oleh pengguna (saldo dikembalikan)
Setiap SMS baru memicu event ini. otp_code dapat null saat otp_message tersedia. Beberapa event SMS dapat tiba tidak berurutan; gunakan sms_revision untuk mengabaikan pasangan agregat yang lebih lama.
Setiap permintaan webhook menyertakan header X-Webhook-Signature dengan tanda tangan HMAC-SHA256 dari body permintaan, menggunakan webhook_secret kamu sebagai kunci:
Verifikasi tanda tangan ini di server kamu untuk memastikan permintaan autentik. Pengiriman bersifat fire-and-forget dengan timeout 3 detik dan tanpa retry.
⟩Batas Permintaan
Permintaan API dibatasi per grup endpoint. Melebihi batas mengembalikan 429 Too Many Requests dengan header Retry-After yang menunjukkan berapa detik harus menunggu.
Respons error menyertakan salah satu kode berikut di error.code:
Kode
HTTP
Deskripsi
UNAUTHORIZED
401
Token API tidak ada atau tidak valid
FORBIDDEN
403
Akses ditolak
NOT_FOUND
404
Sumber daya tidak ditemukan (pesanan, kurs tukar, dll.)
CONFLICT
409
Permintaan duplikat atau konflik sumber daya
INSUFFICIENT_BALANCE
409
Saldo tidak cukup untuk membuat pesanan
VALIDATION_ERROR
422
Parameter permintaan gagal validasi
RATE_LIMIT_EXCEEDED
429
Terlalu banyak permintaan (cek header Retry-After)
INTERNAL_ERROR
500
Kesalahan server internal
PROVIDER_ERROR
422
Penyedia SMS upstream menolak permintaan. Pada kegagalan pembuatan pesanan, error dapat membawa details: cause_counts (pesanan product_id lama — rekap yang dikelompokkan per penyebab) atau attempts (pesanan catalog_product_id — hasil per percobaan), menggunakan nilai ok, no_numbers, insufficient_balance, price_rejected, provider_unavailable, provider_account_balance, provider_error.
NO_OFFER_AVAILABLE
422
Tidak ada penawaran aktif yang cocok dengan produk dan kebijakan yang diminta (batas harga, ketersediaan).
CANCEL_TOO_EARLY
409
Pesanan terlalu baru untuk dibatalkan — tunggu 2 menit
REQUEST_IN_PROGRESS
409
Permintaan pembuatan dengan idempotency key ini masih berjalan
IDEMPOTENCY_KEY_REUSED
422
Idempotency key ini sudah dipakai dengan body permintaan yang berbeda
SERVICE_UNAVAILABLE
503
Layanan sementara tidak tersedia (pemeliharaan)
FX_RATE_UNAVAILABLE
503
Kurs tukar USD/IDR tidak tersedia (endpoint uang v2) — mengembalikan 503 dengan header Retry-After.
v1 → v2
⟩Migrasi v1 → v2
v1 menyajikan IDR; v2 menyajikan USD. Kedua versi berdampingan secara permanen — tidak ada penghentian. Pilih satu versi per integrasi; jangan mencampur base path. v2 identik dengan v1 kecuali cara uang direpresentasikan.
Aspek
v1 · IDR
v2 · USD
Field uang
IDR bilangan bulat, mis. 15000
Objek uang { amount, currency, canonical_amount, canonical_currency }
meta.fx
Tidak ada
Wajib pada setiap respons pembawa uang
Mata uang
IDR
USD (hardcoded di kode)
FX_RATE_UNAVAILABLE
—
503 + Retry-After baru saat tidak ada kurs yang dapat dipakai
Presisi
—
Total 2 desimal, harga/refund 4 desimal, positive-floor
product_id adalah ID tier-slot SMSCode yang stabil. Simpan ini jika kamu ingin memesan tier spesifik yang sama; harga dan stoknya bisa berubah di baris yang sama. catalog_product_id adalah umbrella negara+platform yang stabil untuk routed order; gunakan bersama operator_id, min_price, max_price, prefer_provider, dan policy opsional saat ingin server memilih tier live yang cocok.