Invio di SMS
Questa guida copre l'endpoint di invio singolo, POST /v1/sms/messages. Costruisci un payload JSON con destinatario, mittente, corpo del messaggio e categoria. Bird restituisce 202 Accepted con un ID messaggio e consegna in modo asincrono. Ogni richiesta invia un messaggio a un destinatario. Per inviare più messaggi contemporaneamente, usa l'invio batch. Per inviare un template invece di un testo personalizzato, fornisci un oggetto template al posto di text, category e from.
Prima di inviare: abilita il paese di destinazione
Il tuo spazio di lavoro ha una allowlist di destinazioni deny-by-default che inizia con il solo paese di origine della tua organizzazione abilitato. Bird rifiuta un invio verso qualsiasi altro paese con 422 SMSDestinationNotEnabled prima di risolvere un mittente. Abilita i paesi che servi in SMS > Destinations nella dashboard.
Un invio minimale
Il payload free-text valido più piccolo è un destinatario to, un mittente from, un corpo text e una 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"
}'Usa il tuo host regionale (https://us1.platform.bird.com o https://eu1.platform.bird.com) con una chiave bk_{region}_... corrispondente. La risposta è il messaggio accettato:
Esempio di codice
{
"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 significa che Bird ha il messaggio e lo sta elaborando; cost è null perché la tariffazione avviene durante l'elaborazione. Cosa succede dopo è descritto nel modello asincrono.
Costruire il payload
Destinatario
to è un destinatario in formato E.164: un + iniziale, prefisso internazionale e numero dell'abbonato, ad esempio +31612345678. Un messaggio va a un solo destinatario, senza cc, bcc o array di destinatari. Per raggiungere più persone, invia un batch.
Mittente
from è obbligatorio in un invio free-text ed è il mittente che il destinatario vede. Può assumere una di due forme, e quali funzionano dipende dal paese di destinazione:
- Un sender ID alfanumerico: da 3 a 11 tra lettere, cifre, spazi, trattini, trattini bassi o punti, con almeno una lettera e nessun separatore alle estremità, ad esempio Bird o Acme-Co. Deve contenere una lettera, quindi una stringa di sole cifre con punteggiatura come 555 555 viene rifiutata. Alcuni paesi richiedono la registrazione e altri, inclusi gli Stati Uniti, non supportano i sender alfanumerici. I destinatari non possono rispondere.
- Un numero di proprietà del tuo spazio di lavoro, in E.164 o come cifre semplici. Qualsiasi from composto di sole cifre viene letto come numerico e cercato tra i tuoi mittenti, quindi un numero arbitrario che non possiedi viene rifiutato. Se funziona come long code, numero toll-free o short code dipende dal numero stesso, non da quante cifre hai scritto. Un from di 6 cifre non è uno short code perché ha 6 cifre; è uno short code se il numero che possiedi lo è.
Un mittente non valido per la destinazione viene rifiutato con un 422 che indica il motivo (ad esempio SMSAlphaNotSupported dove i sender alfanumerici non sono disponibili). In un invio con template, from non è accettato: Bird seleziona un mittente per la destinazione e la categoria.
Richiedere un sender ID, leggere i requisiti di ogni paese e registrarlo per paese sono argomenti trattati in sender ID SMS.
Corpo e categoria
text è il corpo del messaggio, almeno un carattere. Viene fatturato e consegnato in segmenti; un invio è limitato a 12 segmenti (circa 1.836 caratteri GSM-7, o 804 se il corpo usa la codifica estesa UCS-2). Un corpo che supera il limite viene rifiutato con un 422 anziché troncato.
category è obbligatorio in un invio free-text e classifica il messaggio come transactional, marketing, authentication o service. Comunica a Bird e agli operatori il motivo dell'invio. Un codice di verifica monouso usa authentication; una promozione usa marketing. Scegli la categoria corrispondente allo scopo del messaggio.
Tag e metadati
Entrambi collegano i tuoi dati a un invio, ma hanno funzioni diverse:
- I tags sono coppie {name, value} strutturate (max 20 per invio; nome da 1 a 32 caratteri, valore da 1 a 64, solo ASCII [A-Za-z0-9_-], case-sensitive, nomi univoci per invio). Sono dimensioni di filtro di prima classe: filtra l'elenco messaggi per tag. Usali per etichette a bassa cardinalità come campaign o experiment_variant.
- metadata è un oggetto JSON arbitrario (max 2 KB serializzato). Viene memorizzato, restituito nelle letture API e riportato in ogni evento webhook, ma non è una dimensione di filtro. Usalo per il contesto di andata e ritorno: ID interni, chiavi esterne, qualsiasi dato che vuoi ricevere indietro con ogni evento.
Esempio di codice
{
"tags": [{ "name": "campaign", "value": "spring-2026" }],
"metadata": { "user_id": "usr_12345", "order_id": "ord_98765" }
}Riferimento campi
| Campo | Tipo | Obbligatorio | Limiti / note |
|---|---|---|---|
| to | string (E.164) | sì | Un destinatario per messaggio |
| from | string | sì* | Numero E.164 di proprietà, sender ID alfanumerico (3–11 caratteri, almeno una lettera) o short code (5–6 cifre) |
| text | string | sì* | Almeno 1 carattere; massimo 12 segmenti |
| category | string | sì* | transactional, marketing, authentication o service |
| tags | {name, value}[] | no | Max 20; nome 1–32 caratteri, valore 1–64 caratteri; solo [A-Za-z0-9_-] |
| metadata | object | no | JSON arbitrario, max 2 KB serializzato |
| options | object | no | Impostazioni di elaborazione per messaggio. smart_encoding è l'unica disponibile; vedi segmenti e codifica |
* Obbligatorio in un invio free-text. Un invio con template fornisce corpo, categoria e mittente dal template, e rifiuta questi tre campi.
Invio con template
Invece di comporre text, imposta l'oggetto template dell'invio per fare riferimento a uno dei template integrati di Bird. Il template fornisce il corpo, la categoria e il mittente, quindi text, category, from e media_urls non sono accettati insieme ad esso. Il catalogo, le variabili di ogni template e il contratto completo dell'invio con template si trovano in template SMS.
Segmenti e codifica
SMS viene fatturato per segmento. Un messaggio che rientra nella codifica GSM-7 ottiene 160 caratteri per segmento singolo; UCS-2 (attivata da emoji, CJK o altri caratteri non GSM) scende a 70. I messaggi più lunghi vengono suddivisi in segmenti multipart con limiti per segmento leggermente inferiori. Ogni risposta riporta i segments risolti: i count fatturabili, la encoding e il conteggio caratteri. I segmenti sono l'unità di fatturazione; vedi costi.
Quando i caratteri tipografici sono l'unico motivo per cui un corpo esce dalla codifica GSM-7, la codifica intelligente può ridurre il numero di segmenti. Imposta options.smart_encoding su true e Bird sostituisce virgolette curve, trattini, puntini di sospensione e caratteri simili con equivalenti GSM-7 prima dell'invio. È disattivata per impostazione predefinita perché modifica il corpo che hai composto.
Per il set completo di caratteri, i caratteri della tabella di estensione che occupano due slot, il dimensionamento degli emoji, le sostituzioni della codifica intelligente e l'aritmetica dei segmenti, vedi Limiti di caratteri.
Invio batch
POST /v1/sms/batches invia fino a 100 messaggi indipendenti in un'unica richiesta. Le richieste batch usano la policy di limitazione delle richieste sms_batch, separata dalla policy sms_send per gli invii singoli. Il corpo è un oggetto JSON il cui array messages contiene gli oggetti messaggio descritti in Costruire il 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"
}
]
}'La validazione è tutto-o-niente: se un qualsiasi messaggio nel batch non è valido, l'intera richiesta viene rifiutata con un 422 e nulla viene inviato, quindi un batch non viene mai applicato parzialmente. In caso di successo la risposta 202 riporta ogni messaggio accettato nell'ordine di invio sotto data, più un summary con il accepted_count. Da quel punto ogni messaggio è indipendente: il fallimento di un destinatario non influisce sugli altri.
Il modello asincrono: cosa significa 202
Un invio riuscito restituisce 202 Accepted con un ID messaggio e status: accepted. Gli errori di richiesta vengono restituiti immediatamente: un campo non valido, un corpo oltre il limite di segmenti, un paese di destinazione non abilitato o un mittente non valido restituiscono un 422. Uno spazio di lavoro senza saldo nel wallet riceve un 402.
La consegna avviene in modo asincrono. Il messaggio passa a sent quando Bird lo consegna all'operatore. Una ricevuta di consegna imposta quindi delivered, undelivered, failed o expired tramite eventi e webhook e gli endpoint di lettura. Questo design ha tre conseguenze:
- Il costo viene calcolato dopo l'accettazione. Il cost di un messaggio è null al momento dell'accettazione e viene popolato quando Bird determina il prezzo dell'invio durante l'elaborazione. Rileggi il messaggio, o attendi l'evento di consegna, per vedere l'addebito calcolato fino a quel momento; costo e fatturazione descrive i componenti e quando uno resta senza prezzo.
- Un messaggio può essere rifiutato dopo il 202. Se l'addebito fallisce durante l'elaborazione, il messaggio termina con rejected con un webhook sms.rejected e non ti viene addebitato nulla; un wallet esaurito viene segnalato come last_error.code: insufficient_balance.
- Le letture possono seguire brevemente il 202. Il messaggio diventa visibile sugli endpoint di lettura poco dopo il 202, quindi un 404 subito dopo un invio si risolve in pochi istanti.
Campi riservati
Bird rifiuta attualmente i seguenti campi della richiesta con 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
Non includere questi campi in un invio.
Riprovare in sicurezza
Invia l'header Idempotency-Key con un valore univoco per ogni invio logico. Se una richiesta riesce senza restituire una risposta, ripeti la stessa richiesta con la stessa chiave. Bird restituisce il risultato originale anziché inviare un messaggio duplicato. Consulta idempotency per il formato della chiave e la durata di conservazione.
Costo e fatturazione
Gli SMS in uscita sono fatturati per segmento. Quanto paghi dipende dal paese e dall'operatore di destinazione; alcune rotte aggiungono un sovrapprezzo di terze parti, come le tariffe per operatore US 10DLC.
Il cost di un messaggio suddivide l'addebito in componenti con nome. transaction_amount è quanto Bird ha addebitato per trasportare il messaggio, passthrough_amount è l'eventuale commissione di terze parti trasferita, e amount è la somma dei componenti che hanno ricevuto un prezzo, denominata in currency_code. Un componente che non ha ancora ricevuto un prezzo è null anziché "0.00000", quindi un messaggio il cui sovrapprezzo non è mai stato risolto riporta amount come solo costo di trasporto. Il riferimento del messaggio documenta ogni campo.
Il sovrapprezzo è best effort. Bird lo risolve durante la registrazione della ricevuta di consegna, entro un intervallo limitato. Se non viene risolto in quell'intervallo, passthrough_amount resta null in modo permanente: Bird non riprova, e amount rimane il costo di trasporto.
Gli SMS in entrata sono fatturati su due voci: la tariffa in entrata per segmento e un sovrapprezzo dell'operatore in entrata dove applicabile. Entrambi sono riportati nel cost del messaggio ricevuto: la tariffa come transaction_amount, il sovrapprezzo come passthrough_amount. A differenza della controparte in uscita, il sovrapprezzo in entrata viene calcolato al momento dell'accettazione del messaggio anziché alla consegna, quindi non viene mai compilato successivamente.
Verifica costo e segmenti per messaggio nel log SMS.
Prossimi passi
- Template SMS: invia un template predefinito e lascia che Bird scelga il mittente.
- Log SMS: trova un messaggio e ispeziona il suo ciclo di vita, i segmenti e il costo.
- Eventi: ricevi gli eventi di consegna nei tuoi sistemi.
- Metriche SMS: monitora il tasso di consegna, il tasso di errore e il volume accettato.
- Idempotency: riprova in sicurezza con l'header Idempotency-Key.
- Inviare il tuo primo SMS: un video che illustra la stessa configurazione nella dashboard
Risorse correlate
Prosegui con la documentazione, le guide e gli esempi per questo argomento. Le risorse sono in inglese.
Guarda la guidaSMS shipping notificationsComprendi il concettoWhat does SMS mean?Esplora la funzionalitàSMSSegui il percorso di apprendimentoBuild your first integration
Prova l'esercitazione e ottieni un brief di implementazione