---
title: "Kirim SMS via API: Contoh Python, Node.js, PHP, dan cURL"
description: "Kirim SMS dengan API di Python, Node.js, PHP, dan cURL: pengiriman tunggal dan massal, Unicode dan Arab, hitung segmen, webhook status, dan penanganan error."
canonical: "https://omnichannels.ai/id/blog/send-sms-api-examples/"
language: "id"
updated: "2026-10-16"
publisher: "BroadNet Technologies"
brand: "OmniChannels.ai"
category: "integration"
primaryQuery: "kirim sms api python"
keywords: ["kirim sms python", "contoh sms api node.js", "sms api php", "sms api curl", "sms api unicode arab", "webhook laporan pengiriman sms", "contoh api sms blast"]
published: "2026-10-16"
author: "OmniChannels.ai Editorial Team"
reviewer: "BroadNet Messaging Solutions Team"
readingMinutes: 10
answer: "Untuk mengirim SMS dengan API OmniChannels.ai, lakukan POST terautentikasi ke https://api.broadnet.me/sms/sendSms dengan body JSON berisi senderId, destinationNumber, message, dan messageType. Gunakan TEXT untuk teks GSM-7 dan UNICODE untuk bahasa Arab atau emoji. Respons 200 mengembalikan ID pesan sebagai teks biasa, dan status pengiriman akhir tiba kemudian di webhook Anda."
takeaways: ["POST /sms/sendSms membutuhkan empat field: senderId, destinationNumber, message, dan messageType; body respons berupa ID pesan sebagai teks biasa, bukan JSON.", "Atur messageType ke UNICODE untuk bahasa Arab, emoji, atau karakter apa pun di luar GSM-7; satu karakter seperti itu membuat seluruh pesan menjadi Unicode dan memperpendek setiap segmen.", "POST /sms/identify menghitung karakter dan segmen sebelum Anda mengirim, sehingga Anda dapat memprediksi berapa segmen yang dipakai sebuah pesan.", "Pengiriman bersifat asinkron: 200 berarti diterima, dan DELIVERED, FAILED, atau REJECTED tiba kemudian di webhook Anda.", "API tidak memiliki idempotency key, jadi catat setiap pengiriman sebelum Anda melakukannya dan periksa status setelah timeout alih-alih mengirim ulang."]
faq: 
  - q: "Bagaimana cara mengirim SMS dengan Python?"
    a: "Gunakan library requests untuk POST JSON ke https://api.broadnet.me/sms/sendSms dengan header Authorization: Bearer dan field senderId, destinationNumber, message, serta messageType. Baca token dari environment variable. Body respons 200 adalah ID pesan sebagai teks biasa, jadi gunakan r.text, bukan r.json()."
  - q: "Format nomor telepon apa yang diharapkan SMS API?"
    a: "Kode negara ditambah nomor nasional, hanya angka, tanpa tanda plus, awalan 00, spasi, atau nol di depan. Misalnya, 447700900123 valid, sedangkan +44 7700 900123 dan 07700900123 tidak. Simpan nomor dalam format E.164 di database Anda sendiri dan hapus tanda plus saat menyusun request."
  - q: "Bagaimana cara mengirim SMS berbahasa Arab melalui API?"
    a: "Atur messageType ke UNICODE dan kirim teks Arab di field message sebagai UTF-8. Pesan Unicode memuat 70 karakter dalam satu segmen dan 67 per segmen saat dipecah, dibanding 160 dan 153 untuk GSM-7. Uji pada handset sungguhan, dan panggil /sms/identify untuk melihat jumlah segmen terlebih dahulu."
  - q: "Bagaimana cara mendapatkan laporan pengiriman?"
    a: "Status dikirim (push) ke URL webhook yang dikonfigurasi di akun Anda. Pesan bergerak melalui SUBMITTED dan SENT menuju DELIVERED, FAILED, atau REJECTED. Endpoint Anda sebaiknya menyimpan event mentah, menjawab 2xx dengan cepat, dan memproses secara asinkron. Jika ada event yang terlewat, POST /sms/resendDlr dapat mengirim ulang laporan pengiriman untuk rentang tanggal tertentu."
  - q: "Bagaimana cara mengirim SMS ke banyak nomor sekaligus?"
    a: "Gunakan POST /sms/sendbulk, request multipart dengan destinationNumberFile (CSV atau TXT) dan string JSON bulkRequest yang berisi senderId, message, dan messageType. Respons melaporkan berapa banyak nomor yang valid, tidak valid, atau duplikat, dan mengembalikan bulkSessionId yang dapat Anda simpan bersama kampanye."
  - q: "Apakah saya perlu mendaftarkan Sender ID?"
    a: "Di banyak negara, ya. Sebagian mewajibkan Sender ID alfanumerik yang disetujui, dan yang lain membutuhkan pengenal regulator atau template, yang diterima API pada field opsional seperti peId dan templateId. Persyaratannya berbeda per negara, jadi periksa halaman Sender ID untuk tujuan Anda, dan tim kami dapat menangani registrasinya bersama Anda."
sources: 
  - title: "3GPP TS 23.040: Technical realization of the Short Message Service (SMS)"
    url: "https://www.3gpp.org/dynareport?code=23040"
  - title: "ITU-T E.164: The international public telecommunication numbering plan"
    url: "https://www.itu.int/rec/T-REC-E.164"
  - title: "RFC 9110: HTTP Semantics"
    url: "https://www.rfc-editor.org/rfc/rfc9110"
---

# Kirim SMS via API: Contoh Python, Node.js, PHP, dan cURL

Canonical: https://omnichannels.ai/id/blog/send-sms-api-examples/
Language: id
Publisher: OmniChannels.ai by BroadNet Technologies

Panduan ini ditujukan bagi developer yang perlu mengirim SMS dari aplikasi dan menginginkan kode yang berfungsi dalam Python, Node.js, PHP, atau cURL. Panduan ini mencakup pengiriman tunggal, Unicode dan Arab, penghitungan segmen, unggah massal, webhook status pengiriman, dan penanganan error, hanya memakai endpoint dan field dari [referensi SMS API](/developers/sms/) dan spesifikasi OpenAPI kami.

## Bagaimana cara mengirim SMS dengan API?

Lakukan `POST` terautentikasi ke `/sms/sendSms` dengan body JSON. Responsnya `200 OK` dengan ID pesan sebagai teks biasa.

| Item | Nilai |
|---|---|
| Base URL | `https://api.broadnet.me` (tanpa awalan `/v1`) |
| Endpoint | `POST /sms/sendSms` |
| Autentikasi | `Authorization: Bearer $BROADNET_TOKEN` |
| Content type | `application/json` |
| Field wajib | `senderId`, `destinationNumber`, `message`, `messageType` |

Kredensial uji diterbitkan setelah permintaan akses singkat, dan pengiriman uji dikirim ke nomor terverifikasi milik Anda sendiri. Tidak ada pendaftaran self-serve instan. Lihat [quickstart](/developers/quickstart/).

```bash
curl -X POST https://api.broadnet.me/sms/sendSms \
  -H "Authorization: Bearer $BROADNET_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "senderId": "OmniDemo",
    "destinationNumber": "447700900123",
    "message": "Your OmniDemo code is 482913",
    "messageType": "TEXT"
  }'
```

```js
// Node.js 18+ (fetch bawaan)
const res = await fetch("https://api.broadnet.me/sms/sendSms", {
  method: "POST",
  headers: {
    Authorization: `Bearer ${process.env.BROADNET_TOKEN}`,
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    senderId: "OmniDemo",
    destinationNumber: "447700900123",
    message: "Your OmniDemo code is 482913",
    messageType: "TEXT",
  }),
});
if (!res.ok) throw new Error(`${res.status} ${await res.text()}`);
const messageId = await res.text(); // ID pesan berupa teks biasa
```

```python
import os
import requests

r = requests.post(
    "https://api.broadnet.me/sms/sendSms",
    headers={"Authorization": f"Bearer {os.environ['BROADNET_TOKEN']}"},
    json={
        "senderId": "OmniDemo",
        "destinationNumber": "447700900123",
        "message": "Your OmniDemo code is 482913",
        "messageType": "TEXT",
    },
    timeout=15,
)
r.raise_for_status()
message_id = r.text  # ID pesan berupa teks biasa, bukan JSON
```

```php
<?php
$payload = json_encode([
    "senderId" => "OmniDemo",
    "destinationNumber" => "447700900123",
    "message" => "Your OmniDemo code is 482913",
    "messageType" => "TEXT",
]);

$ch = curl_init("https://api.broadnet.me/sms/sendSms");
curl_setopt_array($ch, [
    CURLOPT_POST => true,
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_TIMEOUT => 15,
    CURLOPT_HTTPHEADER => [
        "Authorization: Bearer " . getenv("BROADNET_TOKEN"),
        "Content-Type: application/json",
    ],
    CURLOPT_POSTFIELDS => $payload,
]);
$messageId = curl_exec($ch);
$status = curl_getinfo($ch, CURLINFO_RESPONSE_CODE);
curl_close($ch);
echo $status . " " . $messageId . PHP_EOL;
```

Body respons yang berhasil tampak seperti ini:

```text
2603121407537573731
```

Simpan ID itu bersama catatan Anda sendiri, seperti pesanan atau percobaan login. ID itulah yang dipakai untuk mencocokkan status pengiriman nanti.

## Bagaimana memformat nomor telepon?

Gunakan kode negara ditambah nomor nasional, hanya angka. Formatnya mengikuti rencana penomoran internasional dalam ITU-T E.164, tanpa tanda plus.

| Input | Valid? | Alasan |
|---|---|---|
| `447700900123` | Ya | Kode negara 44 ditambah nomor nasional |
| `+44 7700 900123` | Tidak | Hapus tanda plus dan spasi |
| `07700900123` | Tidak | Ganti angka 0 di depan dengan kode negara |

Simpan nomor dalam format E.164 (`+447700900123`) di database Anda dan hapus `+` saat menyusun request. Phone number formatter gratis kami membantu pemeriksaan cepat.

## Bagaimana mengirim teks Arab, emoji, atau Unicode lainnya?

Atur `messageType` ke `UNICODE`. Karakter apa pun di luar alfabet GSM-7, seperti huruf Arab, emoji, tanda kutip lengkung, atau em dash, mengubah seluruh pesan menjadi Unicode.

```python
r = requests.post(
    "https://api.broadnet.me/sms/sendSms",
    headers={"Authorization": f"Bearer {os.environ['BROADNET_TOKEN']}"},
    json={
        "senderId": "OmniDemo",
        "destinationNumber": "971500000000",
        "message": "رمز التحقق الخاص بك هو 482913",
        "messageType": "UNICODE",
        "campaignName": "login-otp",
    },
    timeout=15,
)
```

Di PHP, gunakan `JSON_UNESCAPED_UNICODE` saat memanggil `json_encode`. Encoding menentukan ukuran segmen, seperti didefinisikan untuk SMS dalam 3GPP TS 23.040:

| `messageType` | SMS tunggal | Per segmen saat dipecah | Dipakai untuk |
|---|---|---|---|
| `TEXT` | 160 karakter | 153 karakter | Teks yang hanya memakai alfabet GSM-7 |
| `UNICODE` | 70 karakter | 67 karakter | Arab, Sirilik, Mandarin, emoji |

Sebagian besar operator menagih per segmen, sehingga pesan Arab yang panjang lebih mahal daripada pesan dengan panjang sama dalam aksara Latin. Baca [panduan SMS Unicode dan Arab](/id/blog/sms-character-limits-unicode-arabic/) kami dan coba penghitung karakter SMS.

## Bagaimana menghitung segmen sebelum mengirim?

Panggil `POST /sms/identify` dengan pesan Anda. Endpoint ini mengembalikan encoding yang terdeteksi, jumlah karakter, jumlah segmen, dan batas per segmen.

```bash
curl -X POST https://api.broadnet.me/sms/identify \
  -H "Authorization: Bearer $BROADNET_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{ "message": "Your OmniDemo code is 482913" }'
```

```json
{
  "message": "Your OmniDemo code is 482913",
  "messageType": "TEXT",
  "smscount": 1,
  "charCount": 28,
  "charLimit": 160
}
```

Anda dapat meneruskan `smsParts` (dari `smscount`), `charCount`, dan `charLimit` ke request pengiriman. Teks GSM-7 mungkin diberi label `GSM-7` dalam respons; kirim sebagai `TEXT`.

## Bagaimana mengirim ke banyak nomor?

Gunakan `POST /sms/sendbulk`, request `multipart/form-data` dengan file penerima dan string JSON berisi pengaturan.

```bash
curl -X POST https://api.broadnet.me/sms/sendbulk \
  -H "Authorization: Bearer $BROADNET_TOKEN" \
  -F destinationNumberFile=@recipients.csv \
  -F 'bulkRequest={"senderId":"OmniDemo","message":"Your statement is ready in the app.","messageType":"TEXT","campaignName":"oct-statements","allowDuplicate":false}'
```

```python
import json
import os
import requests

bulk_request = {
    "senderId": "OmniDemo",
    "message": "Your statement is ready in the app.",
    "messageType": "TEXT",
    "campaignName": "oct-statements",
    "allowDuplicate": False,
}

with open("recipients.csv", "rb") as f:
    r = requests.post(
        "https://api.broadnet.me/sms/sendbulk",
        headers={"Authorization": f"Bearer {os.environ['BROADNET_TOKEN']}"},
        files={"destinationNumberFile": ("recipients.csv", f, "text/csv")},
        data={"bulkRequest": json.dumps(bulk_request)},
        timeout=60,
    )
print(r.json())
```

Respons memuat `bulkSessionId` dan objek `bulkListInfo` dengan `total`, `validCount`, `invalidCount`, dan `duplicate`. Simpan `bulkSessionId` bersama kampanye. Job dapat didaftar, dijeda, dilanjutkan, dan dibatalkan dengan endpoint dalam referensi. Anda juga dapat memeriksa nomor sebelum pengiriman besar dengan `POST /sms/lookup`; lihat [panduan HLR lookup](/id/blog/hlr-lookup-number-validation/) kami.

## Bagaimana menerima status pengiriman?

Status pengiriman dikirim (push) ke URL webhook yang dikonfigurasi di akun Anda. Sebuah pesan bergerak melalui `SUBMITTED` dan `SENT` menuju `DELIVERED`, atau berakhir sebagai `FAILED` atau `REJECTED`. Anda memberikan URL HTTPS publik kepada tim kami, dan reseller dapat memiliki satu webhook per sub-akun.

Field payload bervariasi menurut kanal, dan spesifikasi API tidak mendefinisikan satu skema webhook tunggal, jadi catat body mentah terlebih dahulu dan petakan field dari event nyata di akun Anda. Penerima minimal menyimpan event dan menjawab dengan cepat:

```js
import express from "express";

const app = express();

app.post("/webhooks/omnichannels", express.json(), async (req, res) => {
  await saveStatusEvent(req.body); // penyimpanan Anda; proses secara asinkron
  res.sendStatus(200);             // jawab dengan cepat
});

app.listen(3000);
```

Buat pemrosesan idempoten, karena status yang sama bisa tiba dua kali, dan jangan biarkan `SENT` yang terlambat menimpa `DELIVERED` yang sudah tersimpan. Jika endpoint Anda sempat mati, `POST /sms/resendDlr` mengirim ulang laporan untuk rentang tanggal:

```bash
curl -X POST https://api.broadnet.me/sms/resendDlr \
  -H "Authorization: Bearer $BROADNET_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "startDate": "2026-10-09",
    "endDate": "2026-10-10",
    "senderId": "OmniDemo",
    "messageStatus": "DELIVERED"
  }'
```

Baca selengkapnya di [panduan webhook](/developers/webhooks/) dan di status pengiriman pesan dijelaskan.

## Bagaimana menangani error dan menghindari duplikasi?

Tangani status HTTP terlebih dahulu, lalu body error. Ulangi hanya untuk error jaringan, `429`, dan `5xx`.

| Kode | Arti | Tindakan |
|---|---|---|
| `200` | Diterima | Simpan ID |
| `400` | Error validasi atau field hilang | Perbaiki request |
| `401` / `403` | Token salah atau operasi tidak diizinkan | Perbaiki; jangan diulang |
| `429` | Batas laju terlampaui | Tunggu `Retry-After` |
| `500`, `503`, `504` | Masalah server atau upstream | Ulangi dengan backoff dan jitter |

Error yang dimunculkan API memakai body JSON lima field dengan `status`, `error`, `message`, `errorCode`, dan `requestUri`. Batas REST yang terdokumentasi secara default adalah 200 request per detik secara berkelanjutan; batas akun Anda dikonfirmasi bersama kredensial Anda.

API tidak menerima idempotency key. Sebuah request bisa berhasil sementara responsnya hilang, dan pengulangan buta kemudian mengirim dua kali. Tulis baris pending dengan kunci ID operasi Anda sendiri sebelum memanggil, simpan ID pesan yang dikembalikan, dan setelah timeout periksa status webhook sebelum mengirim lagi. Untuk pengiriman massal, atur `allowDuplicate` ke `false`. Rinciannya ada di [Error dan batas](/developers/errors-and-limits/).

## Contoh kasus: kode login untuk aplikasi regional

"Souq Rafiq" (fiktif), pengecer di UEA, mengirim kode login lewat SMS.

1. Layanan autentikasi membuat kode enam digit, menyimpan hash dengan masa berlaku lima menit, dan menulis baris pengiriman `pending`.
2. Layanan memanggil `/sms/sendSms` dengan `messageType=UNICODE` untuk pengguna Arab dan `TEXT` untuk pengguna Inggris.
3. Pada `200`, layanan menyimpan ID pesan.
4. Handler webhook menandai baris sebagai `DELIVERED`, `FAILED`, atau `REJECTED`.
5. Jika statusnya bukan `DELIVERED` setelah jeda singkat, aplikasi menawarkan kirim ulang dan, jika dikonfigurasi, kanal lain. Lihat fallback kanal.
6. Batas laju pada permintaan kode per nomor dan per IP melindungi dari penyalahgunaan; lihat [pencegahan SMS pumping](/id/blog/sms-pumping-fraud-prevention/).

## Apa saja kesalahan umum?

- **Memanggil `r.json()` pada respons pengiriman.** Responsnya teks biasa.
- **Nama field yang salah.** Gunakan `senderId`, `destinationNumber`, dan `message`; field seperti `to`, `from`, atau `text` bukan bagian dari endpoint ini.
- **Tanda plus dan nol di depan** pada nomor.
- **Lupa `UNICODE`** untuk bahasa Arab, yang membuat teks menjadi acak.
- **Sender ID yang tidak terdaftar.** Beberapa negara memblokir atau menggantinya; periksa aturan Sender ID untuk tujuan Anda, dan minta kami menangani registrasinya.
- **Menganggap `200` sebagai terkirim.**
- **Token di aplikasi seluler atau browser,** tempat siapa pun dapat mengambilnya.
- **Batasan:** panduan ini menunjukkan request yang umum. Field opsional seperti format penjadwalan sebaiknya dikonfirmasi dengan tim kami.

## Bagaimana OmniChannels.ai membantu

OmniChannels.ai mengirim A2P SMS melalui konektivitas operator langsung milik BroadNet, dengan SMS dua arah, Sender ID, Unicode dan Arab, HLR lookup, dan SMPP 3.4 untuk volume tinggi. REST API di `https://api.broadnet.me` memakai Bearer token dan juga mencakup WhatsApp, RCS, dan kanal lain, dengan status pengiriman yang dinormalisasi ke satu format webhook. Tim kami menyiapkan registrasi Sender ID bersama Anda. Lihat [referensi SMS API](/developers/sms/) atau kanal SMS.
