API v1 · Aktif 24 jam

Hubungkan bisnis Anda ke NokosKilat

Jual nomor virtual & OTP langsung dari website atau bot Telegram Anda. Saldo, harga dan transaksinya sama persis dengan dashboard, jadi tinggal pasang dan jalan.

5 Server

SMS OTP

Email OTP

Siap pakai

Polling 5–10 dtk

Kode cepat

Refund 1x

Otomatis

Mulai di sini

Dokumentasi API Lengkap

Semua endpoint, parameter dan contoh respons dalam satu file. Pilih format yang paling nyaman, isinya sama dan selalu mengikuti versi terbaru.

Pilihan 1

YAML

Ringkas & paling mudah dibaca. Cocok dibaca langsung atau diberikan ke asisten AI.

https://nokoskilat.com/api/v1/openapi.yaml

Pilihan 2

JSON

Format standar untuk Postman, Swagger, Insomnia dan generator SDK.

https://nokoskilat.com/api/v1/openapi.json

Siap pakai

Starter Kit

Satu paket berisi SDK, bot Telegram dan contoh lengkap. Tempel API key, jalankan, selesai.

Satu paket · Lengkap

NokosKilat Starter Kit

  • SDK PHP, Node.js & Python
  • Bot Telegram siap jalan
  • Postman Collection
  • Panduan lengkap offline
Download .zip

Gambaran

Cara kerjanya

01

Website / bot Anda

02

API NokosKilat

03

Nomor & OTP

04

Kembali ke pelanggan

Harga dalam Rupiah dan memakai saldo akun pemilik API key. Isi saldo kapan saja lewat menu Deposit (QRIS atau kripto).

Cepat

Jalan dalam 4 langkah

  1. 1

    Buat API key

    Buka Developer Portal, tekan Buat Key, lalu simpan baik-baik. Key hanya tampil sekali.

  2. 2

    Lihat produk

    Panggil /countries → /services → /products untuk harga & stok terkini.

  3. 3

    Buat pesanan

    Kirim POST /orders dengan product_id dan Idempotency-Key. Nomor langsung didapat.

  4. 4

    Ambil kode

    Cek /otp/{order_id} tiap 5–10 detik, atau pasang webhook.

Produk

Yang bisa Anda pakai

ProdukWebsiteAPI v1
OTP SMS (Server 1)Tersediasemua endpoint di halaman ini
OTP SMS (Server 2–4)Tersedia/servers/{n}/…
OTP SMS (Server 5)Tersedia/servers/5/…
Email OTPTersedia/email/… (via Server 5)
Sewa NomorTersediaLewat website
Saldo, riwayat, webhookTersediaTersedia

Panduan

Panduan per produk

Server 1

API + Website
  1. 1.GET /products untuk harga & stok
  2. 2.POST /orders dengan Idempotency-Key
  3. 3.Ambil kode dengan polling GET /otp/{order_id} tiap 5–10 detik
  4. 4.Tidak ada OTP → POST /orders/{id}/cancel

Endpoint utama tanpa awalan /servers/{n} mengarah ke Server 1.

Server 2

API + Website
  1. 1.GET /servers/2/countries → /services?country_id=
  2. 2.GET /servers/2/products?country_id=&service_id=
  3. 3.POST /servers/2/orders dengan Idempotency-Key
  4. 4.Polling GET /otp/{order_id}; tanpa OTP → POST /orders/{id}/cancel

Harga, stok dan refund sama dengan website.

Server 3

API + Website
  1. 1.GET /servers/3/countries → /services?country_id=
  2. 2.GET /servers/3/products?country_id=&service=
  3. 3.POST /servers/3/orders dengan Idempotency-Key
  4. 4.Polling GET /otp/{order_id}; tanpa OTP → POST /orders/{id}/cancel

Harga, stok dan refund sama dengan website.

Server 4

API + Website
  1. 1.GET /servers/4/countries → /services?country_id=
  2. 2.GET /servers/4/products?country_id=&service=
  3. 3.POST /servers/4/orders dengan Idempotency-Key
  4. 4.Polling GET /otp/{order_id}; tanpa OTP → POST /orders/{id}/cancel

Harga, stok dan refund sama dengan website.

Server 5

API + Website
  1. 1.GET /servers/5/countries → /services?country_id=
  2. 2.GET /servers/5/products?country_id=&service=
  3. 3.POST /servers/5/orders dengan Idempotency-Key
  4. 4.Polling GET /otp/{order_id}; tanpa OTP → POST /orders/{id}/cancel

Harga, stok dan refund sama dengan website.

Email OTP

API + Website
  1. 1.GET /email/offers?site=telegram.com
  2. 2.POST /email/orders dengan Idempotency-Key
  3. 3.Polling GET /otp/{order_id} (field email & otp)
  4. 4.Belum ada pesan → POST /orders/{id}/cancel

Disediakan oleh Server 5.

Sewa Nomor

Website
  1. 1.Menu Sewa Nomor
  2. 2.Pilih negara, layanan & durasi
  3. 3.Semua SMS selama masa sewa tampil di pesanan

Untuk sementara tersedia lewat website NokosKilat.

Jalur

Server & jalur otomatis

Cukup satu alamat API. Jalur terbaik dipilih otomatis oleh NokosKilat, jadi saat kami meningkatkan layanan, kode Anda tetap jalan tanpa diubah.

ServerWebsiteAPI v1
Server 1Tersediaendpoint utama
Server 2Tersedia/servers/2
Server 3Tersedia/servers/3
Server 4Tersedia/servers/4
Server 5Tersedia/servers/5

Alur

Alur semua produk

Semua produk memakai saldo dan aturan refund yang sama: dipotong sekali saat pesan, kembali satu kali bila batal tanpa kode.

ProdukAlurRefundAkses
OTP SMS · Server 1Pilih negara → layanan → produk → order → nomor → OTPOtomatis saat batal/kedaluwarsa tanpa OTPAPI v1 + website
OTP SMS · Server 2–5Pilih server → layanan → negara → order → nomor → OTPOtomatis saat batal/kedaluwarsa tanpa OTPAPI v1 (/servers/{n}) + website
Email OTPKetik situs tujuan → pilih domain → beli → email masukOtomatis bila dibatalkan sebelum pesan masukAPI v1 (/email) + website
Sewa NomorPilih negara → layanan → durasi → sewa → SMS masuk selama masa sewaOtomatis sekali bila dibatalkan sesuai aturan sewaWebsite
alur-order.txt
[Klien Anda]
   │ 1. GET  /balance                 cek saldo
   │ 2. GET  /countries → /services → /products
   │ 3. POST /orders  (Idempotency-Key)   saldo dipotong 1x
   ▼
[NokosKilat] ── nomor + order_id ──► klien
   │ 4a. webhook order.otp_received (terdeteksi saat polling)
   │ 4b. GET /otp/{order_id} tiap 5–10 detik
   ▼
 OTP masuk → status "diterima" → "selesai"
 Tidak ada OTP → POST /orders/{id}/cancel atau kedaluwarsa
              → status "dibatalkan"/"gagal" → refund otomatis 1x

Transaksi

Saldo & refund

  1. 01Saldo terpotong — saat pesanan berhasil dibuat, sesuai field price.
  2. 02Nomor aktif — masukkan nomor ke aplikasi tujuan.
  3. 03Kode masuk — kode muncul di latest_code.
  4. 04Batal tanpa kode — saldo kembali otomatis, satu kali.
  5. 05Pesanan gagal dibuat — saldo langsung kembali, tanpa pesanan tercatat.

Transaksi

Status pesanan

StatusArtinyaLangkah berikutnya
menungguNomor siap, kode belum masukMasukkan nomor, tunggu kode
diterimaKode sudah masukAmbil dari latest_code
selesaiPesanan ditutupTidak perlu apa-apa
dibatalkanDibatalkan, saldo kembaliBisa pesan lagi
gagalWaktu habis tanpa kode, saldo kembaliBisa pesan lagi

Dasar

API key

Buat key di Developer Portal dan kirim lewat header di setiap request. Simpan di server Anda, jangan di browser atau aplikasi publik.

Headers
X-API-Key: nk_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
# atau
Authorization: Bearer nk_live_xxxx…

Dasar

Alamat & format respons

Base URL
https://nokoskilat.com/api/v1
Berhasil / Gagal
{ "ok": true,  "data": { … } }
{ "ok": false, "error": { "code": "SALDO_KURANG", "message": "Saldo tidak mencukupi…" } }

Dasar

Kode error

HTTPKodeArtinya
401UNAUTHORIZEDAPI key tidak ada, salah, atau dicabut.
422VALIDATION_ERRORParameter atau body tidak valid.
422IDEMPOTENCY_KEY_REQUIREDHeader Idempotency-Key tidak dikirim.
400SALDO_KURANGSaldo tidak cukup.
409OUT_OF_STOCKProduk habis.
409REQUEST_IN_PROGRESSOrder dengan key sama masih diproses.
409CANCEL_NOT_ALLOWEDPesanan belum 3 menit atau OTP sudah masuk.
403AKUN_DIBLOKIRAkun dibatasi admin.
404NOT_FOUNDEndpoint/pesanan tidak ditemukan.
429RATE_LIMITEDMelebihi batas request per key per menit.
409NO_NUMBERS / PRICE_CHANGEDStok jalur habis atau harga berubah; ambil ulang /products. Saldo tidak dipotong/sudah dikembalikan.
409ALREADY_CANCELLEDPesanan sudah dibatalkan sebelumnya — tidak ada refund kedua.
503SERVER_OFF / MAINTENANCE / NOT_CONFIGUREDServer sedang pemeliharaan. Saldo tidak dipotong; coba lagi nanti tanpa mengubah integrasi.
503SERVICE_UNAVAILABLELayanan sementara tidak tersedia/pemeliharaan.

Dasar

Batas request

60 request per menit untuk tiap API key, maksimal 5 key per akun. Pantau header X-RateLimit-Remaining; bila mendapat 429, tunggu sebentar lalu coba lagi.

Referensi

Endpoint

Saldo

GET
/api/v1/balance

Saldo akun Anda dalam IDR.

cURL
curl "https://nokoskilat.com/api/v1/balance" \
  -H "X-API-Key: $NOKOSKILAT_API_KEY"
Contoh respons
{ "ok": true, "data": { "balance": 125000, "currency": "IDR" } }

Countries

GET
/api/v1/countries

Daftar negara aktif.

cURL
curl "https://nokoskilat.com/api/v1/countries" \
  -H "X-API-Key: $NOKOSKILAT_API_KEY"
Contoh respons
{ "ok": true, "data": [ { "id": 6, "name": "Indonesia" } ] }

Services

GET
/api/v1/services?country_id=6

Layanan (aplikasi) yang tersedia di negara tertentu.

Parameter · country_id (integer, wajib)

cURL
curl "https://nokoskilat.com/api/v1/services?country_id=6" \
  -H "X-API-Key: $NOKOSKILAT_API_KEY"
Contoh respons
{ "ok": true, "data": [ { "id": 1, "code": "wa", "name": "WhatsApp" } ] }

Operators

GET
/api/v1/operators?country_id=6&service_id=1

Operator opsional untuk layanan & negara.

Parameter · country_id, service_id (integer, wajib)

cURL
curl "https://nokoskilat.com/api/v1/operators?country_id=6&service_id=1" \
  -H "X-API-Key: $NOKOSKILAT_API_KEY"
Contoh respons
{ "ok": true, "data": [ { "id": 0, "code": "any", "name": "Operator apa saja" } ] }

Products

GET
/api/v1/products?country_id=6&service_id=1

Produk dengan stok dan harga jual NokosKilat (termurah lebih dulu). Harga dikonfirmasi ulang saat order.

Parameter · country_id, service_id (wajib), operator_id (opsional)

cURL
curl "https://nokoskilat.com/api/v1/products?country_id=6&service_id=1" \
  -H "X-API-Key: $NOKOSKILAT_API_KEY"
Contoh respons
{ "ok": true, "data": [ { "id": 9912, "name": "WhatsApp Indonesia", "stock": 340, "price": 3500, "currency": "IDR" } ] }

Create Order

POST
/api/v1/orders

Membuat pesanan, memotong saldo secara atomik, dan mengembalikan nomor. Wajib header Idempotency-Key — kirim ulang dengan key yang sama tidak membuat order ganda. Respons menyertakan balance: snapshot saldo IDR setelah pembuatan pesanan (null bila belum dapat dibaca).

Parameter · Header: Idempotency-Key (8–80 karakter)

cURL
curl -X POST "https://nokoskilat.com/api/v1/orders" \
  -H "X-API-Key: $NOKOSKILAT_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: 7b1e2c90-order-001" \
  -d '{ "country_id": 6, "service_id": 1, "product_id": 9912, "operator_id": null }'
Contoh respons
{
  "ok": true,
  "data": {
    "id": "3f6c…",
    "status": "menunggu",
    "phone": "+62812xxxx",
    "price": 3500,
    "currency": "IDR",
    "expires_at": "2026-10-08T09:20:00Z",
    "otp": [],
    "balance": 121500
  }
}

Check Order

GET
/api/v1/orders/{id}

Status terbaru pesanan (selalu terbaru).

cURL
curl "https://nokoskilat.com/api/v1/orders/{id}" \
  -H "X-API-Key: $NOKOSKILAT_API_KEY"
Contoh respons
{ "ok": true, "data": { "id": "3f6c…", "status": "diterima", "phone": "+62812xxxx", "otp": [ { "code": "482913", "received_at": "…" } ] } }

Get OTP

GET
/api/v1/otp/{order_id}

Ambil kode OTP. Polling setiap 5–10 detik — ini satu-satunya cara mengambil kode OTP saat ini (belum ada webhook khusus OTP).

cURL
curl "https://nokoskilat.com/api/v1/otp/{order_id}" \
  -H "X-API-Key: $NOKOSKILAT_API_KEY"
Contoh respons
{ "ok": true, "data": { "order_id": "3f6c…", "status": "diterima", "latest_code": "482913", "otp": [ … ] } }

Cancel Order

POST
/api/v1/orders/{id}/cancel

Batalkan pesanan minimal 3 menit setelah order dan selama OTP belum masuk. Saldo dikembalikan otomatis sekali. Cek field can_cancel dan cancel_available_at.

cURL
curl -X POST "https://nokoskilat.com/api/v1/orders/{id}/cancel" \
  -H "X-API-Key: $NOKOSKILAT_API_KEY"
Contoh respons
{ "ok": true, "data": { "id": "3f6c…", "status": "dibatalkan", "refund_amount": 3500, "currency": "IDR" } }

Servers (1–5)

GET
/api/v1/servers

Status tiap server dan jenis produk yang bisa dipesan. Selalu cek field online sebelum order — saat server sedang pemeliharaan, order ditolak tanpa memotong saldo dan otomatis aktif kembali tanpa integrasi ulang.

cURL
curl "https://nokoskilat.com/api/v1/servers" \
  -H "X-API-Key: $NOKOSKILAT_API_KEY"
Contoh respons
{ "ok": true, "data": [ { "server": 1, "online": true, "types": ["sms"] }, { "server": 5, "online": true, "types": ["sms", "email"] } ] }

Katalog Server 2–5

GET
/api/v1/servers/{n}/countries · /servers/{n}/services?country_id= · /servers/{n}/products

Negara, layanan, dan produk (harga jual NokosKilat + stok) untuk Server 2, 3, 4, atau 5. ID negara berbeda per server — selalu ambil dari /servers/{n}/countries. Server 2: products?country_id=&service_id= (angka). Server 3–5: products?country_id=&service= (kode, mis. wa).

Parameter · n = 2 | 3 | 4 | 5; country_id (wajib); service_id (Server 2) atau service (Server 3–5)

cURL
curl "https://nokoskilat.com/api/v1/servers/{n}/countries · /servers/{n}/services?country_id= · /servers/{n}/products" \
  -H "X-API-Key: $NOKOSKILAT_API_KEY"
Contoh respons
{ "ok": true, "data": [ { "id": 700, "name": "Jalur 1 · Hemat", "stock": 1223, "price": 4000, "currency": "IDR", "success_rate": null, "recommended": false } ] }

Create Order Server 2–5

POST
/api/v1/servers/{n}/orders

Membuat pesanan di server pilihan dengan aturan harga, stok, blokir jalur, potong saldo, dan refund yang sama persis dengan website. Nama negara/layanan diambil dari katalog, bukan dari body. Wajib Idempotency-Key. Respons menyertakan balance: snapshot saldo IDR setelah pembuatan pesanan (null bila belum dapat dibaca).

Parameter · Header: Idempotency-Key. Body: country_id, product_id, service_id (Server 2) atau service (Server 3–5). Field lain ditolak.

cURL
curl -X POST "https://nokoskilat.com/api/v1/servers/{n}/orders" \
  -H "X-API-Key: $NOKOSKILAT_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: 7b1e2c90-order-001" \
  -d '{ "country_id": 904, "service": "wa", "product_id": 700 }'
Contoh respons
{
  "ok": true,
  "data": {
    "id": "7a1c…",
    "server": 4,
    "type": "sms",
    "status": "menunggu",
    "phone": "+62812xxxx",
    "price": 4000,
    "currency": "IDR",
    "otp": [],
    "can_cancel": false,
    "cancel_available_at": "2026-10-29T03:10:00Z",
    "balance": 121000
  }
}

Email OTP · Offers

GET
/api/v1/email/offers?site=telegram.com

Pilih inbox dari domain, stok, dan harga yang tersedia untuk situs tujuan. site adalah situs tempat Anda menerima verifikasi, bukan domain inbox. Gmail hanya bisa dipilih bila gmail.com ada dalam penawaran berstok.

Parameter · site opsional: tanpa parameter memakai telegram.com; telegram dibaca sebagai telegram.com. Gunakan site yang sama saat membeli.

cURL
curl "https://nokoskilat.com/api/v1/email/offers?site=telegram.com" \
  -H "X-API-Key: $NOKOSKILAT_API_KEY"
Contoh respons
{ "ok": true, "data": [ { "domain": "gmail.com", "stock": 120, "products": [ { "id": 41, "name": "Jalur 1 · Termurah", "stock": 120, "price": 2500, "currency": "IDR" } ] } ] }

Email OTP · Create Order

POST
/api/v1/email/orders

Membeli alamat email untuk menerima kode. Status & kode dibaca lewat GET /orders/{id} atau /otp/{id} (field email). Batal sebelum pesan masuk → saldo kembali sekali. Respons menyertakan balance: snapshot saldo IDR setelah pembuatan pesanan (null bila belum dapat dibaca).

Parameter · Header: Idempotency-Key. Body: site, domain, product_id

cURL
curl -X POST "https://nokoskilat.com/api/v1/email/orders" \
  -H "X-API-Key: $NOKOSKILAT_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: 7b1e2c90-order-001" \
  -d '{ "site": "telegram.com", "domain": "gmail.com", "product_id": 41 }'
Contoh respons
{
  "ok": true,
  "data": {
    "id": "c2e9…",
    "server": 5,
    "type": "email",
    "status": "menunggu",
    "email": "abc@gmail.com",
    "phone": null,
    "price": 2500,
    "otp": [],
    "balance": 122500
  }
}

Finish Order (Server 2–5)

POST
/api/v1/orders/{id}/finish

Menyelesaikan pesanan Server 2–5 setelah kode diterima. GET /orders/{id}, GET /otp/{id} dan POST /orders/{id}/cancel otomatis mengenali server pesanan.

cURL
curl -X POST "https://nokoskilat.com/api/v1/orders/{id}/finish" \
  -H "X-API-Key: $NOKOSKILAT_API_KEY"
Contoh respons
{ "ok": true, "data": { "id": "7a1c…", "server": 4, "status": "selesai", "refund_amount": 0, "currency": "IDR" } }

Order History

GET
/api/v1/orders?limit=20

Riwayat pesanan akun Anda.

Parameter · limit (1–100), status (opsional)

cURL
curl "https://nokoskilat.com/api/v1/orders?limit=20" \
  -H "X-API-Key: $NOKOSKILAT_API_KEY"
Contoh respons
{ "ok": true, "data": [ { "id": "…", "status": "selesai", … } ] }

Integrasi

Contoh kode

Alur lengkap: order → polling OTP tiap 5–10 detik → batal minimal 3 menit setelah order bila OTP belum masuk (saldo kembali otomatis sekali). Respons pembuatan pesanan menyertakan data.balance, snapshot saldo IDR saat respons dibaca; jika null, cek kembali lewat GET /balance.

cURL
# 1) Buat pesanan
curl -X POST https://nokoskilat.com/api/v1/orders \
  -H "X-API-Key: $NOKOSKILAT_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: order-$(date +%s)" \
  -d '{"country_id":6,"service_id":1,"product_id":9912}'

# 2) Polling OTP tiap 5–10 detik
curl "https://nokoskilat.com/api/v1/otp/ORDER_ID" -H "X-API-Key: $NOKOSKILAT_API_KEY"

# 3) Tidak ada OTP? Batalkan minimal 3 menit (180 detik) setelah order,
#    selama OTP belum masuk — saldo kembali otomatis sekali.
sleep 180
curl -X POST "https://nokoskilat.com/api/v1/orders/ORDER_ID/cancel" -H "X-API-Key: $NOKOSKILAT_API_KEY"

Integrasi

Bot Telegram

Ingin notifikasi tanpa coding? Buka Developer Portal → Telegram, masukkan token BotFather dan Chat ID, lalu kirim pesan uji. Token disimpan terenkripsi.

Atau jalankan bot sendiri di server Anda dengan contoh di bawah: /beli, /email dan /batal.

bot.mjs
// npm i telegraf  —  BOT_TOKEN=.. NOKOSKILAT_API_KEY=.. node bot.mjs
// Versi lengkap (Server 1–5, Email, retry, /batal): unduh di Starter Kit.
import { Telegraf } from "telegraf";
import { randomUUID } from "node:crypto";
const BASE = "https://nokoskilat.com/api/v1";
const sleep = (ms) => new Promise((r) => setTimeout(r, ms));

// Timeout 15 dtk; retry hanya timeout/5xx/429 dengan Idempotency-Key yang SAMA.
async function api(path, { method = "GET", body, idem, tries = 3 } = {}) {
  for (let i = 1; ; i++) {
    try {
      const res = await fetch(BASE + path, { method, signal: AbortSignal.timeout(15_000),
        headers: { "X-API-Key": process.env.NOKOSKILAT_API_KEY, "Content-Type": "application/json",
                   ...(idem ? { "Idempotency-Key": idem } : {}) },
        body: body ? JSON.stringify(body) : undefined });
      const j = await res.json().catch(() => null);
      if (j?.ok) return j.data;
      if (!(res.status === 429 || res.status >= 500) || i >= tries) throw new Error(j?.error?.message ?? "HTTP " + res.status);
    } catch (e) { if (i >= tries || e.name !== "TimeoutError") throw e; }
    await sleep(1000 * 2 ** i);
  }
}

async function waitOtp(id) {                     // polling tiap 7 detik (5–10 dtk)
  for (let i = 0; i < 170; i++) {                // ±20 menit
    await sleep(7_000);
    const o = await api(`/otp/${id}`, { tries: 1 }).catch(() => null);
    if (o?.latest_code) return o.latest_code;
    if (o && ["selesai", "dibatalkan", "gagal", "kedaluwarsa"].includes(o.status)) return null;
  }
  return null;
}

const bot = new Telegraf(process.env.BOT_TOKEN);
const safe = (fn) => async (ctx) => { try { await fn(ctx); } catch (e) { ctx.reply("⚠️ " + e.message); } };

// /beli <server 1-5> <country_id> <service> <product_id>
// Server 1–2: service = service_id (angka) · Server 3–5: service = kode (mis. wa)
bot.command("beli", safe(async (ctx) => {
  const [, srv, country, service, product] = ctx.message.text.split(/\s+/);
  const s = Number(srv);
  const body = { country_id: Number(country), product_id: Number(product),
                 ...(s <= 2 ? { service_id: Number(service) } : { service }) };
  const o = await api(s === 1 ? "/orders" : `/servers/${s}/orders`, { method: "POST", body, idem: randomUUID() });
  ctx.reply(`Nomor: ${o.phone}\nMenunggu OTP…`);
  const code = await waitOtp(o.id);
  ctx.reply(code ? `Kode OTP: ${code}` : `Belum ada OTP. /batal ${o.id}`);
}));

// /email [site] : lihat stok; /email <site> <domain> <product_id> : beli
bot.command("email", safe(async (ctx) => {
  const [, target = "telegram.com", domain, product] = ctx.message.text.trim().split(/\s+/);
  const site = target.trim().toLowerCase();
  const offers = await api(`/email/offers?site=${encodeURIComponent(site)}`);
  if (!domain && !product) return ctx.reply(offers.flatMap((d) => d.products.filter((p) => p.stock > 0).map((p) => `${d.domain} · #${p.id} · Rp${p.price}\n/email ${site} ${d.domain} ${p.id}`)).join("\n") || "Stok email belum tersedia.");
  const selected = offers.find((d) => d.domain === domain)?.products.find((p) => p.id === Number(product) && p.stock > 0);
  if (!selected) return ctx.reply("Pilih domain dan produk berstok dari /email " + site);
  const o = await api("/email/orders", { method: "POST", body: { site, domain, product_id: selected.id }, idem: randomUUID() });
  ctx.reply(`Email: ${o.email}\nMenunggu kode…`);
  const code = await waitOtp(o.id);
  ctx.reply(code ? `Kode: ${code}` : `Belum ada pesan. /batal ${o.id}`);
}));

// Refund otomatis maksimal 1x oleh NokosKilat
bot.command("batal", safe(async (ctx) => {
  const id = ctx.message.text.split(/\s+/)[1];
  const r = await api(`/orders/${id}/cancel`, { method: "POST", idem: "cancel-" + id });
  ctx.reply("Status: " + r.status);
}));

bot.launch();

Integrasi

Webhook

Atur URL HTTPS dan event di Developer Portal. Tiap kiriman ditandatangani HMAC-SHA256 atas {timestamp}.{body}. Balas 2xx dalam 8 detik; bila gagal, kami kirim ulang otomatis.

Contoh kiriman
POST https://domainanda.com/webhook/nokoskilat
X-NokosKilat-Event: order.number_ready
X-NokosKilat-Timestamp: 1791459200
X-NokosKilat-Signature: sha256=9f2c…

{
  "id": "b8d1f0b2-…",
  "event": "order.number_ready",
  "created_at": "2026-10-08T09:12:44Z",
  "data": { "order_id": "3f6c…", "phone": "+62812xxxx" }
}
Verifikasi signature
// Node.js / Express — verifikasi signature
import crypto from "node:crypto";
app.post("/webhook/nokoskilat", express.raw({ type: "application/json" }), (req, res) => {
  const ts = req.header("X-NokosKilat-Timestamp");
  const sig = req.header("X-NokosKilat-Signature");          // "sha256=<hex>"
  const expected = "sha256=" + crypto.createHmac("sha256", process.env.NOKOSKILAT_WEBHOOK_SECRET)
    .update(`${ts}.${req.body}`).digest("hex");
  if (!sig || sig.length !== expected.length || !crypto.timingSafeEqual(Buffer.from(sig), Buffer.from(expected))) return res.sendStatus(401);
  if (Math.abs(Date.now() / 1000 - Number(ts)) > 300) return res.sendStatus(401); // anti-replay
  const event = JSON.parse(req.body);                          // proses idempoten via event.id
  res.sendStatus(200);
});
EventArtinya
order.createdPesanan dibuat dan saldo dipotong.
order.number_readyNomor siap dipakai.
order.otp_receivedServer 1–5 & Email: kode terdeteksi saat Anda memanggil GET /orders/{id} atau /otp/{id}; dikirim sekali per kode. data.code berisi kode.
order.completedPesanan selesai (terdeteksi saat Anda memanggil GET /orders/{id} atau /otp/{id}).
order.cancelledPesanan dibatalkan.
order.refundedSaldo pesanan sudah dikembalikan.
order.refund_failedPengembalian saldo perlu dicek admin.

Simpan id event dan lewati yang sudah diproses, karena kiriman bisa diulang.

Integrasi

Tips keamanan

API key disimpan sebagai hash dan bisa dicabut kapan saja.
Simpan key & secret webhook di server, bukan di frontend.
Pakai Idempotency-Key unik per pesanan agar retry selalu aman.
Cek signature & timestamp webhook sebelum diproses.

Bantuan

Tanya jawab

OTP tidak masuk-masuk?

Pastikan nomor sudah dimasukkan ke aplikasi tujuan. Tunggu minimal 3 menit, lalu panggil cancel — saldo kembali otomatis. Jika cancel ditolak (CANCEL_NOT_ALLOWED), coba lagi beberapa saat kemudian.

Order terpotong dua kali?

Tidak akan terjadi bila setiap order memakai Idempotency-Key unik. Retry dengan key yang sama selalu mengembalikan order yang sama.

Harga berbeda dengan /products?

Harga dikonfirmasi ulang saat POST /orders. Yang dipotong adalah harga di respons order (field price).

Kena 429?

Kurangi frekuensi polling (minimal 5 detik) dan gunakan webhook agar tidak perlu polling.

Email OTP & Sewa Nomor lewat API?

Email OTP tersedia lewat /email/offers dan /email/orders (Server 5). Sewa Nomor masih hanya lewat website.

Timeout saat POST order?

Jangan buat key baru. Kirim ulang dengan Idempotency-Key yang SAMA: Anda menerima pesanan yang sama (atau REQUEST_IN_PROGRESS 409 — tunggu 2–5 detik lalu ulangi). Saldo tidak terpotong dua kali.

Webhook untuk Server 2–5?

Ya, event yang sama untuk Server 1–5 & Email, terdeteksi saat Anda polling GET /otp/{id} tiap 5–10 detik. Tiap event dikirim sekali (simpan event.id), gagal kirim dicoba ulang otomatis 2–33 menit dengan event.id yang sama.

Rotasi secret webhook?

Setelah rotasi, selama 24 jam header X-NokosKilat-Signature-Previous ikut dikirim dengan secret lama. Terima bila salah satu valid, lalu ganti secret di server Anda.

Server sedang pemeliharaan?

Base URL, API key, format dan webhook secret tidak pernah berubah. Saat pemeliharaan /servers menampilkan online: false dan order ditolak tanpa potong saldo; begitu selesai server otomatis online lagi — tidak perlu integrasi ulang.

Pembaruan

Pembaruan

  1. v1.5.0

    Dokumentasi lengkap tersedia dalam format YAML & JSON, tampilan baru yang lebih nyaman dibaca.

  2. v1.4.0

    Panduan per produk untuk Server 1–5, Email OTP dan Sewa Nomor.

  3. v1.3.0

    Alur saldo & refund, tanya jawab, dan daftar isi di HP.

  4. v1.2.0

    Mulai cepat, tabel status pesanan, dan jalur otomatis.