Mengirim SMS
Panduan ini membahas endpoint pengiriman tunggal, POST /v1/sms/messages. Buat payload JSON dengan penerima, pengirim, isi pesan, dan kategori. Bird mengembalikan 202 Accepted dengan ID pesan dan mengirim secara asinkron. Setiap permintaan mengirim satu pesan ke satu penerima. Untuk mengirim banyak pesan sekaligus, gunakan pengiriman batch. Untuk mengirim template alih-alih teks Anda sendiri, sertakan objek template sebagai pengganti text, category, dan from.
Sebelum mengirim: aktifkan negara tujuan
Workspace Anda memiliki daftar izin tujuan default-deny yang awalnya hanya mengaktifkan negara asal organisasi Anda. Bird menolak pengiriman ke negara lain dengan 422 SMSDestinationNotEnabled sebelum menentukan pengirim. Aktifkan negara yang Anda layani di SMS > Destinations pada dashboard.
Pengiriman minimal
Payload free-text terkecil yang valid terdiri dari penerima to, pengirim from, isi pesan text, dan category.
const msg = await bird.sms.send({
from: "+15557654321",
to: "+14155550100",
text: "Your verification code is 123456.",
category: "authentication",
});
console.log(msg.id, msg.status);msg = client.sms.send(
from_="+15557654321",
to="+15551234567",
text="Your verification code is 123456.",
category="authentication",
)
print(msg.id, msg.status)msg, err := client.Sms.Send(context.Background(), bird.SmsSendParams{
From: "+15557654321",
To: "+15551234567",
Text: "Your verification code is 123456.",
Category: bird.SMSCategoryAuthentication,
})
if err != nil {
log.Fatal(err)
}
fmt.Println(msg.Id, *msg.Status)$message = $bird->sms->send(
from: '+15557654321',
to: '+15551234567',
text: 'Your verification code is 123456.',
category: 'authentication',
);
echo $message->getId(), ' ', $message->getStatus();bird sms send --body-file - <<'JSON'
{
"to": "+14155550100",
"from": "+15557654321",
"text": "Your verification code is 123456.",
"category": "authentication",
"options": {
"smart_encoding": true
},
"tags": [
{
"name": "campaign",
"value": "signup"
}
],
"metadata": {
"user_id": "usr_12345"
}
}
JSONcurl -X POST https://eu1.platform.bird.com/v1/sms/messages \
-H "Authorization: Bearer bk_eu1_..." \
-H "Content-Type: application/json" \
-d '{
"to": "+31612345678",
"from": "Bird",
"text": "Your Bird verification code is 481920. It expires in 10 minutes.",
"category": "authentication"
}'Gunakan host regional Anda (https://us1.platform.bird.com atau https://eu1.platform.bird.com) dengan kunci bk_{region}_... yang sesuai. Responsnya adalah pesan yang diterima:
Contoh kode
{
"id": "sms_01ky7qmwgpfkybj9ecrnwjx714",
"direction": "outbound",
"status": "accepted",
"to": "+31612345678",
"from": "Bird",
"text": "Your Bird verification code is 481920. It expires in 10 minutes.",
"category": "authentication",
"segments": { "count": 1, "encoding": "GSM_7BIT", "characters": 64 },
"cost": null,
"carrier": null,
"mcc_mnc": null,
"sent_at": null,
"delivered_at": null,
"created_at": "2026-07-23T14:56:34.326Z"
}status: accepted berarti Bird sudah menerima pesan dan sedang memprosesnya; cost bernilai null karena penetapan harga terjadi saat pemrosesan. Proses selanjutnya dibahas di model asinkron.
Menyusun payload
Penerima
to adalah satu penerima dalam format E.164: diawali +, kode negara, dan nomor pelanggan, misalnya +31612345678. Satu pesan dikirim ke satu penerima, tanpa cc, bcc, atau array penerima. Untuk menjangkau banyak orang, kirim batch.
Pengirim
from wajib pada pengiriman free-text dan merupakan pengirim yang dilihat penerima. Field ini menerima salah satu dari dua bentuk, dan mana yang berfungsi bergantung pada negara tujuan:
- ID pengirim alfanumerik: 3 hingga 11 huruf, angka, spasi, tanda hubung, garis bawah, atau titik, dengan minimal satu huruf dan tanpa pemisah di awal maupun akhir, seperti Bird atau Acme-Co. Harus mengandung huruf, jadi string angka dengan tanda baca seperti 555 555 akan ditolak. Beberapa negara mewajibkan pendaftaran, dan negara lain, termasuk AS, tidak mendukung pengirim alfanumerik. Penerima tidak dapat membalas pesan dari pengirim ini.
- Nomor milik workspace Anda, dalam format E.164 atau sebagai digit mentah. Setiap from yang seluruhnya digit dibaca sebagai numerik dan dicari di antara sender Anda, sehingga nomor acak yang bukan milik Anda akan ditolak. Apakah nomor tersebut berfungsi sebagai long code, nomor toll-free, atau short code ditentukan oleh nomor itu sendiri, bukan oleh jumlah digit yang Anda tulis. from 6 digit bukan short code karena memiliki 6 digit; ia adalah short code jika nomor yang Anda miliki memang short code.
Sender yang tidak valid untuk tujuan ditolak dengan 422 yang menyebutkan alasannya (misalnya SMSAlphaNotSupported di negara yang tidak mendukung sender alfanumerik). Pada pengiriman template, from tidak diterima: Bird memilih sender untuk tujuan dan kategori.
Mengklaim sender ID, membaca persyaratan tiap negara, dan mendaftarkannya per negara dibahas di sender ID SMS.
Isi pesan dan kategori
text adalah isi pesan, minimal satu karakter. Penagihan dan pengiriman dihitung per segmen; satu pengiriman dibatasi maksimal 12 segmen (sekitar 1.836 karakter GSM-7, atau 804 jika isi pesan menggunakan encoding UCS-2 yang diperluas). Isi pesan yang melebihi batas ditolak dengan 422, bukan dipotong.
category wajib pada pengiriman free-text dan mengklasifikasikan pesan sebagai transactional, marketing, authentication, atau service. Field ini memberi tahu Bird dan operator mengapa Anda mengirim pesan. Kode verifikasi sekali pakai menggunakan authentication; promosi menggunakan marketing. Pilih kategori yang sesuai dengan tujuan pesan.
Tag dan metadata
Keduanya melampirkan data Anda sendiri ke pengiriman, tetapi memiliki fungsi berbeda:
- tags adalah pasangan {name, value} terstruktur (maks 20 per pengiriman; nama 1 hingga 32 karakter, nilai 1 hingga 64, hanya ASCII [A-Za-z0-9_-], peka huruf besar-kecil, nama unik dalam satu pengiriman). Tag merupakan dimensi filter utama: filter daftar pesan berdasarkan tag. Gunakan untuk label dengan kardinalitas rendah seperti campaign atau experiment_variant.
- metadata adalah objek JSON arbitrer (maks 2 KB setelah diserialisasi). Data ini disimpan, dikembalikan saat pembacaan API, dan disertakan di setiap event webhook, tetapi bukan dimensi filter. Gunakan untuk konteks bolak-balik: ID internal, foreign key, atau apa pun yang ingin Anda terima kembali bersama setiap event.
Contoh kode
{
"tags": [{ "name": "campaign", "value": "spring-2026" }],
"metadata": { "user_id": "usr_12345", "order_id": "ord_98765" }
}Referensi field
| Field | Tipe | Wajib | Batas / catatan |
|---|---|---|---|
| to | string (E.164) | ya | Satu penerima per pesan |
| from | string | ya* | Nomor E.164 milik Anda, sender ID alfanumerik (3–11 karakter, minimal satu huruf), atau short code (5–6 digit) |
| text | string | ya* | Minimal 1 karakter; dibatasi 12 segmen |
| category | string | ya* | transactional, marketing, authentication, atau service |
| tags | {name, value}[] | tidak | Maks 20; nama 1–32 karakter, nilai 1–64 karakter; hanya [A-Za-z0-9_-] |
| metadata | object | tidak | JSON arbitrer, maks 2 KB setelah diserialisasi |
| options | object | tidak | Pengaturan pemrosesan per pesan. smart_encoding adalah satu-satunya yang tersedia; lihat segmen dan encoding |
* Wajib pada pengiriman free-text. Pengiriman template menyediakan isi pesan, kategori, dan pengirim dari template, dan menolak ketiga field ini.
Mengirim dengan template
Alih-alih menyusun text, atur objek template pada pengiriman untuk merujuk salah satu template bawaan Bird. Template menyediakan isi pesan, kategori, dan pengirim, sehingga text, category, from, dan media_urls tidak diterima bersamanya. Katalog, variabel setiap template, dan kontrak lengkap pengiriman template tersedia di template SMS.
Segmen dan encoding
SMS ditagih per segmen. Pesan yang sesuai dengan encoding GSM-7 mendapat 160 karakter per segmen tunggal; UCS-2 (dipicu oleh emoji, CJK, atau karakter non-GSM lainnya) turun menjadi 70. Pesan yang lebih panjang dipecah menjadi segmen multipart dengan batas per segmen yang sedikit lebih rendah. Setiap respons melaporkan segments yang ditentukan: jumlah count yang ditagihkan, encoding, dan jumlah karakter. Segmen adalah satuan penagihan Anda; lihat biaya.
Ketika karakter tipografis menjadi satu-satunya alasan isi pesan tidak masuk GSM-7, pengodean cerdas dapat mengurangi jumlah segmennya. Atur options.smart_encoding ke true dan Bird mengganti tanda kutip lengkung, tanda hubung, elipsis, dan karakter serupa dengan padanan GSM-7 sebelum mengirim. Fitur ini nonaktif secara default karena mengubah isi pesan yang Anda tulis.
Untuk rangkaian karakter lengkap, karakter tabel ekstensi yang menempati dua slot, ukuran emoji, apa yang diganti pengodean cerdas, dan aritmetika segmen, lihat Batas karakter.
Pengiriman batch
POST /v1/sms/batches mengirim hingga 100 pesan independen dalam satu permintaan. Permintaan batch menggunakan kebijakan pembatasan laju permintaan sms_batch, terpisah dari kebijakan sms_send untuk pengiriman tunggal. Body-nya adalah objek JSON yang array messages-nya berisi objek pesan dari Menyusun payload:
const result = await bird.sms.sendBatch({
messages: [
{
from: "+15557654321",
to: "+15551111111",
text: "Hi Alice!",
category: "marketing",
},
{
from: "+15557654321",
to: "+15552222222",
text: "Hi Bob!",
category: "marketing",
},
],
});batch = client.sms.send_batch(
messages=[
{
"from_": "+15557654321",
"to": "+15551111111",
"text": "Hi Alice!",
"category": "marketing",
},
{
"from_": "+15557654321",
"to": "+15552222222",
"text": "Hi Bob!",
"category": "marketing",
},
]
)
for msg in batch.data:
print(msg.id, msg.status)batch, err := client.Sms.SendBatch(context.Background(), bird.SmsSendBatchParams{
Messages: []bird.SmsSendParams{
{
From: "+15557654321", To: "+15551111111",
Text: "Hi Alice!", Category: bird.SMSCategoryMarketing,
},
{
From: "+15557654321", To: "+15552222222",
Text: "Hi Bob!", Category: bird.SMSCategoryMarketing,
},
},
})
if err != nil {
log.Fatal(err)
}
for _, msg := range batch.Data {
fmt.Println(msg.Id, *msg.Status)
}$batch = $bird->sms->sendBatch(messages: [
(new SMSMessageSendRequest())
->setFrom('+15557654321')
->setTo('+15551111111')
->setText('Hi Alice!')
->setCategory('marketing'),
(new SMSMessageSendRequest())
->setFrom('+15557654321')
->setTo('+15552222222')
->setText('Hi Bob!')
->setCategory('marketing'),
]);
foreach ($batch->getData() ?? [] as $item) {
echo $item->getId(), ' ', $item->getStatus(), "\n";
}curl -X POST "https://{region}.platform.bird.com/v1/sms/batches" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"messages": [
{
"to": "+15551111111",
"from": "+15557654321",
"text": "Hi Alice!",
"category": "marketing"
},
{
"to": "+15552222222",
"from": "+15557654321",
"text": "Hi Bob!",
"category": "marketing"
}
]
}'Validasi bersifat semua-atau-tidak-sama-sekali: jika ada pesan dalam batch yang tidak valid, seluruh permintaan ditolak dengan 422 dan tidak ada yang terkirim, sehingga batch tidak pernah diterapkan sebagian. Jika berhasil, respons 202 membawa setiap pesan yang diterima sesuai urutan pengiriman di bawah data, ditambah summary dengan accepted_count. Setiap pesan bersifat independen sejak saat itu: kegagalan satu penerima tidak memengaruhi penerima lainnya.
Model async: arti 202
Pengiriman yang berhasil mengembalikan 202 Accepted dengan message ID dan status: accepted. Kegagalan permintaan langsung dikembalikan: field tidak valid, body melebihi batas segmen, negara tujuan yang belum Anda aktifkan, atau sender tidak valid mengembalikan 422. Workspace tanpa saldo wallet menerima 402.
Pengiriman terjadi secara asinkron. Pesan berpindah ke sent saat Bird menyerahkannya ke carrier. Tanda terima pengiriman kemudian menetapkan delivered, undelivered, failed, atau expired melalui event dan webhook dan endpoint baca. Desain ini memiliki tiga konsekuensi:
- Biaya dihitung setelah penerimaan. cost pada pesan bernilai null saat diterima dan diisi setelah Bird menentukan harga pengiriman selama pemrosesan. Baca kembali pesan tersebut, atau tunggu event pengiriman, untuk melihat biaya yang sudah dihitung sejauh ini; biaya dan penagihan membahas komponen dan kapan suatu komponen tetap belum dihitung.
- Pesan dapat ditolak setelah 202. Jika penagihan gagal selama pemrosesan, pesan berakhir rejected dengan webhook sms.rejected dan Anda tidak ditagih; wallet yang habis muncul sebagai last_error.code: insufficient_balance.
- Pembacaan dapat sedikit tertinggal dari 202. Pesan menjadi terlihat di endpoint baca sesaat setelah 202, sehingga 404 segera setelah pengiriman akan terselesaikan dalam beberapa saat.
Field yang dicadangkan
Bird saat ini menolak field permintaan berikut dengan 422 SMSUnsupportedFeature:
scheduled_at, validity_period, media_urls, messaging_profile_id, broadcast_id, campaign_id, audience_id, contact_id, topic_id, personalization, options.max_price_per_segment, options.track_clicks
Jangan sertakan field ini dalam pengiriman.
Mencoba ulang dengan aman
Kirim header Idempotency-Key dengan nilai unik per pengiriman logis. Jika permintaan berhasil tanpa mengembalikan respons, kirim ulang permintaan dan key yang sama. Bird mengembalikan hasil asli alih-alih mengirim pesan duplikat. Lihat idempotensi untuk format key dan retensi.
Biaya dan penagihan
SMS keluar ditagih per segmen. Jumlah yang Anda bayar bergantung pada negara tujuan dan carrier; beberapa rute menambahkan surcharge pihak ketiga, seperti biaya carrier US 10DLC.
cost pada pesan memecah biaya menjadi komponen bernama. transaction_amount adalah biaya yang dikenakan Bird untuk mengirim pesan, passthrough_amount adalah biaya pihak ketiga yang diteruskan, dan amount adalah jumlah komponen yang sudah dihitung, dalam mata uang currency_code. Komponen yang belum dihitung bernilai null bukan "0.00000", sehingga pesan yang surcharge-nya tidak pernah terselesaikan melaporkan amount sebagai biaya pengiriman saja. Referensi pesan mendokumentasikan setiap field.
Surcharge bersifat best effort. Bird menyelesaikannya saat mencatat tanda terima pengiriman, dalam jendela waktu terbatas. Jika tidak terselesaikan dalam jendela waktu tersebut, passthrough_amount tetap null secara permanen: Bird tidak mencoba ulang, dan amount tetap berupa biaya pengiriman.
SMS masuk ditagih dalam dua baris: tarif masuk per segmen, dan surcharge carrier masuk jika berlaku. Keduanya dilaporkan pada cost pesan yang diterima: tarif sebagai transaction_amount, surcharge sebagai passthrough_amount. Berbeda dengan pasangan keluarnya, surcharge masuk dihitung saat pesan diterima, bukan saat pengiriman, sehingga tidak pernah diisi belakangan.
Tinjau biaya dan segmen per pesan di log SMS.
Langkah selanjutnya
- Template SMS: kirim template bawaan dan biarkan Bird memilih sender.
- Log SMS: temukan pesan dan periksa siklus hidupnya, segmen, dan biayanya.
- Event: terima event pengiriman di sistem Anda.
- Metrik SMS: pantau tingkat pengiriman, tingkat kegagalan, dan volume yang diterima.
- Idempotensi: coba ulang dengan aman menggunakan header Idempotency-Key.
- Mengirim SMS pertama Anda: video yang memandu langkah-langkah pengaturan yang sama di dashboard
Sumber daya terkait
Lanjutkan dengan dokumentasi, panduan, dan contoh untuk topik ini. Sumber daya tersedia dalam bahasa Inggris.
Tonton panduannyaSMS shipping notificationsPahami konsepnyaWhat does SMS mean?Jelajahi kemampuannyaSMSIkuti jalur pembelajaranBuild your first integration
Coba praktiknya dan dapatkan ringkasan implementasi