SMS verzenden
Deze gids behandelt het single-send-endpoint POST /v1/sms/messages. Bouw een JSON-payload met een ontvanger, afzender, berichttekst en categorie. Bird retourneert 202 Accepted met een bericht-ID en bezorgt asynchroon. Elk verzoek stuurt één bericht naar één ontvanger. Om veel berichten tegelijk te versturen, gebruik je batchverzending. Om een template te versturen in plaats van je eigen tekst, geef je een template-object mee in plaats van text, category en from.
Voordat je verzendt: schakel het bestemmingsland in
Je werkruimte heeft een default-deny-bestemmingslijst die begint met alleen het thuisland van je organisatie ingeschakeld. Bird weigert een verzending naar elk ander land met 422 SMSDestinationNotEnabled voordat er een afzender wordt bepaald. Schakel de landen die je bedient in onder SMS > Destinations in het dashboard.
Een minimale verzending
De kleinste geldige free-text-payload is een to-ontvanger, een from-afzender, een text-berichttekst en een 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"
}'Gebruik je regionale host (https://us1.platform.bird.com of https://eu1.platform.bird.com) met een bijpassende bk_{region}_...-sleutel. De respons is het geaccepteerde bericht:
Codevoorbeeld
{
"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 betekent dat Bird het bericht heeft en het verwerkt; cost is null omdat prijsbepaling tijdens de verwerking plaatsvindt. Wat er daarna gebeurt wordt behandeld in het asynchrone model.
De payload opbouwen
Ontvanger
to is één ontvanger in E.164-formaat: een + vooraan, landcode en abonneenummer, zoals +31612345678. Eén bericht gaat naar één ontvanger, zonder cc, bcc of een ontvangerarray. Om veel mensen te bereiken, verstuur je een batch.
Afzender
from is verplicht bij een free-text-verzending en is de afzender die de ontvanger ziet. Het heeft twee mogelijke vormen, en welke werken hangt af van het bestemmingsland:
- Een alfanumeriek afzender-ID: 3 tot 11 letters, cijfers, spaties, streepjes, underscores of punten, met minstens één letter en geen scheidingsteken aan het begin of einde, zoals Bird of Acme-Co. Het moet een letter bevatten, dus een cijferreeks met leestekens zoals 555 555 wordt geweigerd. Sommige landen vereisen registratie, en andere, waaronder de VS, ondersteunen geen alfanumerieke afzenders. Ontvangers kunnen er niet op antwoorden.
- Een nummer dat je werkruimte bezit, in E.164 of als kale cijfers. Elke from die alleen uit cijfers bestaat wordt als numeriek gelezen en opgezocht in je afzenders, dus een willekeurig nummer dat je niet bezit wordt geweigerd. Of het als long code, gratis nummer of shortcode werkt, volgt uit het nummer zelf, niet uit hoeveel cijfers je hebt geschreven. Een from van 6 cijfers is geen shortcode omdat het 6 cijfers heeft; het is een shortcode als het nummer dat je bezit er een is.
Een afzender die niet geldig is voor de bestemming wordt geweigerd met een 422 die de reden vermeldt (bijvoorbeeld SMSAlphaNotSupported waar alfanumerieke afzenders niet beschikbaar zijn). Bij een templateverzending wordt from niet geaccepteerd: Bird selecteert een afzender op basis van de bestemming en categorie.
Een afzender-ID claimen, lezen wat elk land ervoor vereist, en het per land registreren wordt behandeld in SMS-afzender-ID's.
Berichttekst en categorie
text is de berichttekst, minimaal één teken. Het wordt gefactureerd en bezorgd in segmenten; een verzending is begrensd op 12 segmenten (ongeveer 1.836 GSM-7-tekens, of 804 als de tekst de uitgebreide UCS-2-codering gebruikt). Een tekst boven de limiet wordt geweigerd met een 422 in plaats van afgekapt.
category is verplicht bij een free-text-verzending en classificeert het bericht als transactional, marketing, authentication of service. Het vertelt Bird en carriers waarom je verzendt. Een eenmalige verificatiecode gebruikt authentication; een promotie gebruikt marketing. Kies de categorie die bij het doel van het bericht past.
Tags en metadata
Beide koppelen je eigen data aan een verzending, maar ze dienen verschillende doelen:
- tags zijn gestructureerde {name, value}-paren (max 20 per verzending; naam 1 tot 32 tekens, waarde 1 tot 64, alleen ASCII [A-Za-z0-9_-], hoofdlettergevoelig, namen uniek binnen een verzending). Ze zijn eersteklas filterdimensies: filter de berichtenlijst op tag. Gebruik ze voor labels met weinig variaties, zoals campaign of experiment_variant.
- metadata is een willekeurig JSON-object (max 2 KB geserialiseerd). Het wordt opgeslagen, geretourneerd bij API-reads en meegestuurd bij elk webhook-event, maar het is geen filterdimensie. Gebruik het voor round-trip-context: interne ID's, foreign keys, alles wat je bij elk event teruggestuurd wilt krijgen.
Codevoorbeeld
{
"tags": [{ "name": "campaign", "value": "spring-2026" }],
"metadata": { "user_id": "usr_12345", "order_id": "ord_98765" }
}Veldreferentie
| Veld | Type | Verplicht | Limieten / opmerkingen |
|---|---|---|---|
| to | string (E.164) | ja | Eén ontvanger per bericht |
| from | string | ja* | E.164-nummer in je bezit, alfanumeriek afzender-ID (3–11 tekens, minimaal één letter) of shortcode (5–6 cijfers) |
| text | string | ja* | Minimaal 1 teken; begrensd op 12 segmenten |
| category | string | ja* | transactional, marketing, authentication of service |
| tags | {name, value}[] | nee | Max 20; naam 1–32 tekens, waarde 1–64 tekens; alleen [A-Za-z0-9_-] |
| metadata | object | nee | Willekeurig JSON, max 2 KB geserialiseerd |
| options | object | nee | Verwerkingsinstellingen per bericht. smart_encoding is de enige beschikbare; zie segmenten en codering |
* Verplicht bij een free-text-verzending. Een templateverzending levert de berichttekst, categorie en afzender vanuit het template, en weigert deze drie velden.
Verzenden met een template
In plaats van text samen te stellen, stel je het template-object van de verzending in om te verwijzen naar een van de ingebouwde templates van Bird. Het template levert de berichttekst, de categorie en de afzender, dus text, category, from en media_urls worden er niet naast geaccepteerd. De catalogus, de variabelen van elk template en het volledige template-send-contract staan in SMS-templates.
Segmenten en codering
SMS wordt per segment gefactureerd. Een bericht dat in GSM-7-codering past krijgt 160 tekens per enkel segment; UCS-2 (getriggerd door emoji, CJK of andere niet-GSM-tekens) daalt naar 70. Langere berichten worden opgesplitst in multipart-segmenten met iets lagere limieten per segment. Elke respons rapporteert de bepaalde segments: het factureerbare count, de encoding en het aantal tekens. Segmenten zijn de eenheid waarop je gefactureerd wordt; zie kosten.
Wanneer typografische tekens de enige reden zijn dat een berichttekst buiten GSM-7 valt, kan slimme codering het aantal segmenten verlagen. Stel options.smart_encoding in op true en Bird vervangt gekrulde aanhalingstekens, streepjes, beletseltekens en vergelijkbare tekens door GSM-7-equivalenten voordat het bericht wordt verstuurd. Het staat standaard uit omdat het de berichttekst die je hebt opgesteld wijzigt.
Zie Tekenlimieten voor de volledige tekenset, extensietabel-tekens die twee posities kosten, emoji-afmetingen, wat slimme codering vervangt en de segmentberekening.
Batchverzending
POST /v1/sms/batches verstuurt tot 100 onafhankelijke berichten in één request. Batchrequests gebruiken het sms_batch-beleid voor beperking van het aantal verzoeken, apart van het sms_send-beleid voor enkele verzendingen. De body is een JSON-object waarvan de messages-array de berichtobjecten uit De payload opbouwen bevat:
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"
}
]
}'Validatie is alles-of-niets: als een bericht in de batch ongeldig is, wordt het hele request afgewezen met een 422 en wordt er niets verstuurd, dus een batch wordt nooit gedeeltelijk toegepast. Bij succes bevat het 202-antwoord elk geaccepteerd bericht in inzendvolgorde onder data, plus een summary met de accepted_count. Elk bericht is vanaf daar onafhankelijk: een fout bij één ontvanger heeft nooit invloed op de andere.
Het asynchrone model: wat 202 betekent
Een geslaagde verzending retourneert 202 Accepted met een bericht-ID en status: accepted. Requestfouten worden direct geretourneerd: een ongeldig veld, een body boven de segmentlimiet, een bestemmingsland dat je niet hebt ingeschakeld, of een ongeldige afzender retourneert een 422. Een werkruimte zonder walletsaldo ontvangt een 402.
Bezorging verloopt asynchroon. Het bericht gaat naar sent wanneer Bird het aan de carrier overdraagt. Een bezorgbevestiging stelt vervolgens delivered, undelivered, failed of expired in via events en webhooks en de read-endpoints. Dit ontwerp heeft drie gevolgen:
- Kosten worden na acceptatie berekend. De cost van een bericht is null op het moment van acceptatie en wordt ingevuld zodra Bird de verzending tijdens verwerking beprijst. Lees het bericht terug, of wacht op het bezorgevent, om de tot dan toe berekende kosten te zien; kosten en facturering behandelt de componenten en wanneer er een onbeprijsd blijft.
- Een bericht kan na de 202 worden afgewezen. Als de afschrijving tijdens verwerking mislukt, eindigt het bericht op rejected met een sms.rejected-webhook en word je niet gefactureerd; een uitgeput walletsaldo verschijnt als last_error.code: insufficient_balance.
- Reads kunnen kort achter de 202 aanlopen. Het bericht wordt kort na de 202 zichtbaar op de read-endpoints, dus een 404 direct na een verzending lost zichzelf binnen enkele ogenblikken op.
Gereserveerde velden
Bird wijst de volgende requestvelden af met 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
Neem deze velden niet op in een verzending.
Veilig opnieuw proberen
Stuur de Idempotency-Key-header mee met een unieke waarde per logische verzending. Als een request slaagt zonder een antwoord te retourneren, herhaal dan hetzelfde request met dezelfde key. Bird retourneert het oorspronkelijke resultaat in plaats van een dubbel bericht te versturen. Zie idempotency voor het keyformaat en de bewaartermijn.
Kosten en facturering
Uitgaande SMS wordt per segment gefactureerd. Wat je betaalt hangt af van het bestemmingsland en de carrier; sommige routes rekenen een toeslag van derden, zoals US 10DLC-carrierkosten.
De cost van een bericht splitst de kosten in benoemde componenten. transaction_amount is wat Bird in rekening bracht om het bericht te transporteren, passthrough_amount is een eventueel doorberekende toeslag van derden, en amount is de som van de beprijsde componenten, uitgedrukt in currency_code. Een component die niet beprijsd is, is null in plaats van "0.00000", dus een bericht waarvan de toeslag nooit is bepaald rapporteert amount als alleen de transportkosten. De berichtreferentie documenteert elk veld.
De toeslag wordt op best-effortbasis bepaald. Bird bepaalt deze tijdens het vastleggen van de bezorgbevestiging, binnen een begrensd tijdvenster. Als de toeslag niet binnen dat venster wordt bepaald, blijft passthrough_amount permanent null: Bird probeert het niet opnieuw, en amount blijft de transportkosten.
Inkomende SMS wordt op twee regels gefactureerd: het inkomende tarief per segment en een inkomende carriertoeslag waar die van toepassing is. Beide worden gerapporteerd in de eigen cost van het ontvangen bericht: het tarief als transaction_amount, de toeslag als passthrough_amount. Anders dan bij uitgaande berichten wordt de inkomende toeslag beprijsd bij acceptatie in plaats van bij bezorging, dus deze wordt nooit later ingevuld.
Bekijk kosten en segmenten per bericht in het SMS-log.
Volgende stappen
- SMS-templates: verstuur een ingebouwde template en laat Bird de afzender kiezen.
- SMS-log: zoek een bericht op en bekijk de levenscyclus, segmenten en kosten.
- Events: ontvang bezorgevents in je systemen.
- SMS-metrics: monitor bezorgpercentage, foutpercentage en geaccepteerd volume.
- Idempotency: probeer veilig opnieuw met de Idempotency-Key-header.
- Uw eerste SMS verzenden: een video die dezelfde configuratie in het dashboard doorloopt
Gerelateerde bronnen
Ga verder met de documentatie, gidsen en voorbeelden voor dit onderwerp. De bronnen zijn in het Engels.
Bekijk de gidsSMS shipping notificationsBegrijp het conceptWhat does SMS mean?Ontdek de mogelijkheidSMSVolg het leerpadBuild your first integration
Probeer de oefening en ontvang een implementatieoverzicht