Dokumentasi API SMS untuk mengirim dari kode Anda sendiri

API REST kecil pada akun, harga, dan saldo yang sama seperti ruang kerja: kirim pesan atau batch hingga 5,000 nomor, perkirakan biaya terlebih dahulu, ikuti setiap pesan dan dapatkan event pengiriman di URL webhook Anda.

URL Dasar: https://sendsmsonline.cc/api/v1

Mulai cepat

  1. 1. Buat kunci. Di workspace, buka API dan webhooks. Kunci akan terbuka setelah top-up pertama Anda; setiap kunci hanya ditampilkan sekali, jadi salin atau simpan sebagai file teks.
  2. 2. Periksa biaya. POST body yang sama ke /costs untuk melihat penerima, segmen, dan total tanpa mengirim.
  3. 3. Kirim. POST ke /sends. Jawaban berisi id pengiriman; pesan akan dikirim segera atau pada send_at.
curl https://sendsmsonline.cc/api/v1/sends \
  -H "Authorization: Bearer $SSO_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "recipients": [ { "to": "+447700900461", "fields": { "first_name": "Tom" } }, { "to": "+12015550142", "fields": { "first_name": "Ava" } } ], "text": "Hi {{first_name}}, your table is ready at 7:30.", "name": "Friday bookings", "client_ref": "bookings-1107" }'

Autentikasi

Kirim kunci Anda di header Authorization: Authorization: Bearer sso_live_.... Kunci terdiri dari 49 karakter dan dimulai dengan sso_live_. Maksimal 5 kunci per akun; cabut satu di workspace dan kunci akan berhenti bekerja segera. Daftar harga bersifat publik dan tidak memerlukan kunci.

Kesalahan

Kesalahan menggunakan kode status HTTP dan body JSON dengan kode stabil dan kalimat yang dapat ditunjukkan kepada seseorang. Tidak ada biaya yang dikenakan saat permintaan gagal.

HTTP/1.1 402 Payment Required
{ "error": { "code": "insufficient_credit", "message": "Short by $3.20. Add funds to send.", "total": "8.62480", "credit": "5.42000" } }
KolomArti
400Permintaan perlu diubah.
401Kunci hilang, salah, atau dicabut.
402Saldo tidak cukup untuk total biaya.
404Tidak ada pengiriman, pesan, negara, atau endpoint seperti itu.
409Pengiriman sudah dimulai.
429Lebih dari 240 permintaan dalam satu menit.

Batasan

  • 240 permintaan per menit per kunci, ditampilkan di X-RateLimit-Limit, X-RateLimit-Remaining, dan X-RateLimit-Reset (detik unix).
  • 5,000 nomor per permintaan, 2,000 karakter per teks, 10 segmen per pesan.
  • Pesan dikirim hingga 300 per menit per akun.
  • send_at dari 10 menit hingga 30 hari ke depan.

Harga

GET/api/v1/prices

GET/api/v1/prices/{country}

Harga per pesan (satu segmen) untuk setiap negara, dalam USD dengan 5 desimal. Tidak perlu kunci.

{ "price": { "country": "GB", "name": "United Kingdom", "dial_code": "+44", "price_usd": "0.00868" }, "updated": "2026-11-07" }

Saldo akun

GET/api/v1/account

{ "account": "SO8K2M4Q7X9TBA", "credit_usd": "41.27660", "currency": "USD" }

Perkirakan biaya

POST/api/v1/costs

Mengambil body yang sama seperti pengiriman dan mengembalikan biayanya, tanpa mengirim atau menagih. Teks gabungan setiap penerima menentukan segmennya, sehingga totalnya akurat.

{
  "recipients": 2, "segments_min": 1, "segments_max": 1, "encoding": "gsm7", "messages_billed": 2,
  "total_usd": "0.01426", "credit_usd": "41.27660", "enough_credit": true,
  "countries": [ { "country": "GB", "recipients": 1, "price_usd": "0.00868", "subtotal_usd": "0.00868" },
                 { "country": "US", "recipients": 1, "price_usd": "0.00558", "subtotal_usd": "0.00558" } ],
  "dropped": [], "too_long": null
}

Buat pengiriman

POST/api/v1/sends

Satu teks ke satu atau banyak nomor. Saldo untuk seluruh pengiriman diambil saat diterima; pesan yang gagal dikembalikan satu per satu.

KolomArti
toNomor dalam format internasional (+447700900461). Gunakan ini atau penerima.
recipientsObjek dengan to dan fields, untuk merge fields: { "to": "+1...", "fields": { "first_name": "Ava" } }.
textPesan, hingga 2,000 karakter. {{field}} diganti per penerima; nilai yang hilang menjadi kosong.
send_atWaktu ISO 8601 opsional dengan offset atau Z. Tanpanya, pengiriman dimulai segera.
nameLabel opsional yang ditampilkan di workspace (80 karakter).
client_refReferensi opsional yang dikembalikan di webhooks (64 karakter).
opt_outMenambahkan baris opt-out yang disimpan di Pengaturan ke akhir teks.
default_countryKode ISO digunakan untuk nomor yang ditulis tanpa kode negara.
HTTP/1.1 201 Created
{
  "send": { "id": "CA7Q29XMAB4DFK", "status": "queued", "source": "api", "recipients": 2, "segments_max": 1,
            "encoding": "gsm7", "cost_usd": "0.01426", "refunded_usd": "0.00000", "client_ref": "bookings-1107",
            "send_at": null, "created_at": "2026-11-07T10:12:03.120Z", "started_at": null, "finished_at": null },
  "dropped": [ { "value": "+4412", "code": "too_short", "message": "Too short" } ]
}

Nomor yang tidak dapat dikirim dicantumkan di dropped dan tidak pernah ditagih. Kode: no_country_code, too_short, too_long, not_a_number, wrong_length, not_covered, duplicate dan suppressed (pada daftar do-not-send Anda).

Dapatkan atau daftar pengiriman

GET/api/v1/sends/{id}

GET/api/v1/sends?limit=25&before={id}

Satu pengiriman mencakup counts per status pesan. Daftar diurutkan dari yang terbaru; lewati next_before sebagai before untuk halaman berikutnya. Pengiriman dari workspace juga muncul di sini, dengan source: "web".

Pesan

GET/api/v1/sends/{id}/messages?status=failed&limit=100

GET/api/v1/messages/{id}

{ "message": { "id": "MS3D8RW0K2QJ7N", "send_id": "CA7Q29XMAB4DFK", "to": "+447700900461", "country": "GB",
  "segments": 1, "price_usd": "0.00868", "status": "delivered", "reason": null, "reason_text": null,
  "created_at": "2026-11-07T10:12:03.120Z", "sent_at": "2026-11-07T10:12:04.010Z", "done_at": "2026-11-07T10:12:09.400Z" } }

Batalkan pengiriman

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

Hanya pengiriman terjadwal yang belum dimulai yang dapat dibatalkan. Biaya penuh dikembalikan ke saldo Anda dan jawabannya mencakup refunded_usd.

Webhooks

Atur URL https di workspace (API dan webhooks). Kami POST sebuah event saat pesan terkirim atau gagal, untuk pengiriman dari API dan workspace. Jawab dengan status 2xx apa pun dalam 10 detik. Pengiriman yang gagal dicoba lagi hingga 7 kali: segera, kemudian setelah 1 menit, 5 menit, 30 menit, 1 jam, 2 jam, dan 3 jam. Workspace menampilkan setiap percobaan dengan status dan jawabannya.

POST https://your-server.example/sms-events
X-SSO-Event: message.delivered
X-SSO-Delivery: evt_5a0c9e31d2b7f4a68c
X-SSO-Timestamp: 1794132729
X-SSO-Signature: sha256=8f1c...e42a

{ "id": "evt_5a0c9e31d2b7f4a68c", "event": "message.delivered", "created": "2026-11-07T10:12:09.000Z",
  "data": { "message": { "id": "MS3D8RW0K2QJ7N", "send_id": "CA7Q29XMAB4DFK", "to": "+447700900461", "country": "GB",
  "segments": 1, "price_usd": "0.00868", "status": "delivered", "reason": null, "reason_text": null,
  "client_ref": "bookings-1107", "created_at": "...", "sent_at": "...", "done_at": "..." } } }

Tanda tangan adalah HMAC-SHA256 dari timestamp + "." + raw body dengan rahasia tanda tangan Anda (dimulai dengan sso_whk_). Periksa pada raw body sebelum parsing, tolak timestamp yang lebih lama dari 5 menit, dan gunakan delivery id untuk mengabaikan pengulangan.

import crypto from "node:crypto";

// rawBody: the request body exactly as received (a string), before JSON.parse
export function verify(rawBody, headers, secret) {
  const ts = headers["x-sso-timestamp"];
  const sig = headers["x-sso-signature"] || "";
  const want = "sha256=" + crypto.createHmac("sha256", secret).update(`${ts}.${rawBody}`).digest("hex");
  const fresh = Math.abs(Date.now() / 1000 - Number(ts)) < 300;
  return fresh && sig.length === want.length && crypto.timingSafeEqual(Buffer.from(sig), Buffer.from(want));
}

Event: message.delivered, message.failed, dan test dari tombol Kirim test event.

Status dan alasan

KolomArti
queuedMenunggu untuk meninggalkan antrian kami.
sentTelah dikirim ke jaringan, menunggu laporan pengiriman. Sebagian besar laporan tiba dalam beberapa menit; beberapa jaringan membutuhkan waktu hingga 24 jam.
deliveredJaringan mengonfirmasi bahwa ponsel telah menerimanya.
failedTidak terkirim. Harga telah dikembalikan ke saldo Anda.
canceledTidak dikirim karena Anda membatalkan. Dana telah dikembalikan.

Alasan kegagalan (kolom reason):

KolomArti
network_errorKesalahan jaringan
absentPonsel mati atau di luar jangkauan
not_in_serviceNomor tidak aktif
blockedDiblokir oleh jaringan atau penerima
landlineNomor telepon rumah atau nomor yang tidak dapat menerima SMS
content_filterDitolak oleh filter konten jaringan
expiredKedaluwarsa: tidak ada laporan sebelum batas waktu jaringan
canceledDibatalkan sebelum dikirim
unknownRespon jaringan tidak diketahui

Pemeriksaan layanan ada di halaman status dan perubahan API di changelog.

Dapatkan kunci API Anda

Buat akun, tambahkan dana sekali dan buka API serta webhook di workspace. Kunci yang sama berlaku untuk setiap negara.

Buat akun gratis
Dokumentasi API SMS: Kirim SMS Massal dari Kode Anda | SendSMSOnline