SMS versturen
Deze handleiding behandelt het endpoint voor afzonderlijke verzending, POST /v1/sms/messages. Stel een JSON-payload op met een ontvanger, afzender, berichttekst en categorie. Bird retourneert 202 Accepted met een bericht-ID en levert het bericht asynchroon af. Elk verzoek verstuurt één bericht naar één ontvanger. Wil je veel berichten tegelijk versturen, gebruik dan batchverzending. Wil je een sjabloon versturen in plaats van je eigen tekst, geef dan een template-object op in plaats van text en category. Ingebouwde sjablonen weigeren from; werkruimtesjablonen vereisen het.
Voordat je verstuurt: schakel het land van bestemming in
Je werkruimte verstuurt SMS alleen naar de landen op de toegestane lijst van bestemmingen. Het thuisland van je organisatie is het land van het registratieadres in het bedrijfsprofiel, of van het factuuradres als het registratieadres geen land heeft. Je werkruimte begint met een lege lijst. Telkens wanneer het thuisland wordt ingesteld of gewijzigd, voegt Bird dat land toe aan de lijst. Bird weigert een verzending naar een land dat niet op de lijst staat met 422 SMSDestinationNotEnabled, nog voordat er een afzender wordt bepaald. Schakel de landen die je bedient in via SMS > Destinations in het dashboard.
Op dezelfde pagina kun je per land een dagelijkse uitgavenlimiet instellen, in de valuta van je wallet. Om een limiet in te stellen heb je een organisatiewallet nodig en leestoegang daartoe; om er een te verwijderen niet. Een limiet geldt ongeacht of het land is ingeschakeld. Zodra de uitgaven van vandaag aan dat land de limiet bereiken, weigert Bird daar nieuwe berichten met 422 SMSDestinationDailySpendExceeded tot middernacht UTC. Ook verificatieberichten worden dan geweigerd. Uitgaven tellen mee op het moment dat een bericht in rekening wordt gebracht, dus berichten die al zijn geaccepteerd kunnen de limiet met hun kosten overschrijden. Een gewijzigde limiet heeft tot een minuut nodig voordat die geldt voor verzendingen.
Een minimale verzending
De kleinste geldige payload met vrije tekst bestaat uit 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 bijbehorende bk_{region}_...-sleutel. Het antwoord is het geaccepteerde bericht:
{
"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 ontvangen en verwerkt; cost is null omdat de prijs tijdens de verwerking wordt bepaald. Wat er daarna gebeurt, lees je in het asynchrone model.
De payload opbouwen
Ontvanger
to is één ontvanger in E.164-formaat: een + vooraan, de landcode en het abonneenummer, zoals +31612345678. Eén bericht gaat naar één ontvanger, zonder cc, bcc of array met ontvangers. Wil je veel mensen bereiken, verstuur dan een batch.
Afzender
from is de afzender die de ontvanger ziet. Bij een verzending met vrije tekst is dit veld verplicht, tenzij messaging_profile_id een berichtenprofiel noemt met een afzender voor het bestemmingsland of een standaardafzender. Het veld heeft een van twee vormen, en welke werken hangt af van het bestemmingsland:
- Een alfanumerieke afzender-ID: 3 tot 11 letters, cijfers, spaties, streepjes, underscores of punten, met minstens één letter en geen scheidingsteken aan het begin of eind, zoals
BirdofAcme-Co. De ID moet een letter bevatten, dus een cijferreeks met leestekens zoals555 555wordt 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 losse cijfers. Elke
fromdie alleen uit cijfers bestaat, wordt als numeriek gelezen en opgezocht tussen je afzenders, dus een willekeurig nummer dat je niet bezit wordt geweigerd. Of het als long code, gratis nummer of short code werkt, volgt uit het nummer zelf en niet uit het aantal cijfers dat je schreef. Eenfromvan 6 cijfers is geen short code omdat het 6 cijfers heeft; het is een short code 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 noemt (bijvoorbeeld SMSAlphaNotSupported waar alfanumerieke afzenders niet beschikbaar zijn). Bij een verzending met een ingebouwde template wordt from niet geaccepteerd: Bird kiest een afzender voor de bestemming en categorie. Een werkruimtetemplate vereist je eigen from-afzender, of een berichtenprofiel dat er een levert.
Hoe je een afzender-ID claimt, wat elk land ervan eist en hoe je hem per land registreert, lees je in SMS-afzender-ID's.
Wil je de afzenders en standaardwaarden van één programma op één plek bewaren, maak dan een berichtenprofiel en noem het in messaging_profile_id. Laat je from weg, dan verstuurt Bird vanaf de afzender van het profiel voor het bestemmingsland, of vanaf de standaardafzender ervan. Laat je category weg, dan geldt de standaardcategorie van het profiel, en options.smart_encoding, cost_center, validity_period en options.callback_url nemen de instellingen van het profiel over. Waarden die je op het bericht instelt, hebben voorrang.
Berichttekst en categorie
text is de berichttekst, minstens één teken. Die wordt gefactureerd en afgeleverd in segmenten; een verzending is beperkt tot 12 segmenten (ongeveer 1.836 GSM-7-tekens, of 804 als de tekst de uitgebreide UCS-2-codering gebruikt). Een tekst boven die grens wordt geweigerd met een 422 in plaats van afgekapt.
category is verplicht bij een verzending met vrije tekst, tenzij het berichtenprofiel in messaging_profile_id een standaardcategorie instelt. Het veld deelt het bericht in als transactional, marketing, authentication of service, en vertelt Bird en providers zo waarom je verstuurt. Een eenmalige verificatiecode gebruikt authentication; een promotie gebruikt marketing. Kies de categorie die past bij het doel van het bericht.
Tags en metadata
Hiermee koppel je je eigen gegevens aan een verzending, maar ze dienen verschillende doelen:
tagszijn gestructureerde{name, value}-paren (maximaal 20 per verzending; naam 1 tot 32 tekens, waarde 1 tot 64, alleen ASCII[A-Za-z0-9_-], hoofdlettergevoelig, namen uniek binnen een verzending). Het zijn volwaardige filterdimensies: je filtert de berichtenlijst op tag. Gebruik ze voor labels met weinig verschillende waarden, zoalscampaignofexperiment_variant.metadatais een willekeurig JSON-object (maximaal 2 kB geserialiseerd). Het wordt opgeslagen, teruggegeven bij API-leesverzoeken en meegestuurd met elk webhookevent, maar het is geen filterdimensie. Gebruik het voor context die je terug wilt krijgen: interne ID's, foreign keys en alles wat je bij elk event terug wilt ontvangen.referenceis één string van 1 tot 255 tekens waarmee je het bericht wilt terugvinden, zoals een order- of ticketnummer.?reference=op de berichtenlijst zoekt er exact en hoofdlettergevoelig op, en meerdere berichten kunnen dezelfde waarde hebben. Het wordt teruggegeven bij leesverzoeken en meegestuurd met elk webhookevent. Stel het alleen in als je erop moet zoeken, en zet alle andere gegevens inmetadata.
{
"tags": [{ "name": "campaign", "value": "spring-2026" }],
"metadata": { "user_id": "usr_12345", "order_id": "ord_98765" },
"reference": "ord_98765"
}Veldenoverzicht
| Veld | Type | Verplicht | Limieten / opmerkingen |
|---|---|---|---|
to | string (E.164) | ja | Eén ontvanger per bericht |
from | string | ja* | Eigen E.164-nummer, alfanumerieke afzender-ID (3–11 tekens, minimaal één letter) of shortcode (5–6 cijfers) |
text | string | ja* | Minimaal 1 teken; maximaal 12 segmenten |
category | string | ja* | transactional, marketing, authentication of service |
template | object | ja* | {slug, parameters?, language?} voor een ingebouwde template of werkruimtetemplate |
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 |
reference | string | nee | 1–255 tekens; exacte overeenkomst voor ?reference= in de berichtenlijst |
messaging_profile_id | string | nee | Een berichtenprofiel dat de afzender en standaardwaarden levert; waarden op het bericht hebben voorrang |
validity_period | integer | nee | 60–172.800 seconden vanaf acceptatie; laat weg om de waarde van het berichtenprofiel of de eigen regels van de provider te gebruiken |
options | object | nee | Verwerkingsinstellingen per bericht, zoals smart_encoding (zie segmenten en codering) en callback_url (zie callback-URL's) |
* Verzendingen met vrije tekst vereisen from, text en category, behalve dat een berichtenprofiel from en category kan leveren. Verzendingen met een template vereisen template in plaats van text en category (en weigeren beide). Ingebouwde templates weigeren from; werkruimtetemplates vereisen het.
Verzenden met een template
Stel template in om een ingebouwde template of een gepubliceerde werkruimtetemplate te verzenden. Het opstellen van werkruimtetemplates is beschikbaar als API-preview. De catalogus, variabelen en afzenderregels vind je in SMS-templates.
Segmenten en codering
SMS wordt per segment gefactureerd. Een bericht dat in de GSM-7-codering past, krijgt 160 tekens in één segment; met UCS-2 (nodig bij emoji, CJK-tekens of andere tekens buiten GSM) daalt dat naar 70. Langere berichten worden opgesplitst in meerdelige segmenten met iets lagere limieten per segment. Elk antwoord meldt de toegepaste segments: de factureerbare count, de encoding en het aantal tekens. Je wordt per segment gefactureerd; zie kosten.
Als typografische tekens de enige reden zijn dat een berichttekst buiten GSM-7 valt, kan smart encoding het aantal segmenten verlagen. Stel options.smart_encoding in op true, dan vervangt Bird vóór verzending gekrulde aanhalingstekens, streepjes, beletseltekens en vergelijkbare tekens door equivalenten in GSM-7. Deze optie staat standaard uit, omdat ze de tekst wijzigt die je hebt opgesteld.
Zie Character limits voor de volledige tekenset, de tekens uit de extensietabel die twee posities kosten, de grootte van emoji, wat smart encoding vervangt en de rekensom voor segmenten.
Batchverzending
POST /v1/sms/batches verstuurt tot 100 onafhankelijke berichten in één verzoek, volgens het bulkpatroon van SMS waarbij één API-aanroep veel ontvangers bereikt. Batchverzoeken vallen onder het rate-limitbeleid sms_batch, los van het beleid sms_send voor losse verzendingen. De body is een JSON-object waarvan de array messages 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"
}
]
}'De validatie is alles-of-niets: als één bericht in de batch ongeldig is, wordt het hele verzoek afgewezen met een 422 en wordt er niets verstuurd. Een batch wordt dus nooit gedeeltelijk uitgevoerd. Bij succes bevat het antwoord 202 elk geaccepteerd bericht in de volgorde van indienen onder data, plus een summary met de accepted_count. Vanaf dat moment is elk bericht onafhankelijk: als het bij één ontvanger misgaat, heeft dat nooit gevolgen voor de andere.
Het asynchrone model: wat 202 betekent
Een geslaagde verzending geeft 202 Accepted terug met een bericht-ID en status: accepted. Fouten in het verzoek komen direct terug: een ongeldig veld, een body boven de segmentlimiet, een bestemmingsland dat je niet hebt ingeschakeld of een ongeldige afzender levert een 422 op. Een werkruimte zonder walletsaldo krijgt een 402.
De aflevering verloopt asynchroon. Het bericht gaat naar sent wanneer Bird het aan de provider overdraagt. Een afleverbevestiging zet daarna delivered, undelivered, failed of expired, zichtbaar via events en webhooks en de lees-endpoints. Dit ontwerp heeft drie gevolgen:
- De kosten worden na acceptatie berekend. De
costvan een bericht isnullop het moment van acceptatie en wordt gevuld zodra Bird de prijs tijdens de verwerking berekent. Lees het bericht opnieuw op of wacht op het afleverevent om de tot dan toe berekende kosten te zien. Kosten en facturering beschrijft de onderdelen en wanneer een onderdeel zonder prijs blijft. - Een bericht kan na de 202 alsnog worden afgewezen. Als de afschrijving tijdens de verwerking mislukt, eindigt het bericht als
rejectedmet eensms.rejected-webhook en betaal je niets. Een lege wallet verschijnt alslast_error.code: insufficient_balance. - Leesacties kunnen kort achterlopen op de 202. Het bericht verschijnt kort na de
202op de lees-endpoints, dus een404direct na een verzending lost zich binnen enkele ogenblikken vanzelf op.
Gereserveerde velden
Bird wijst de volgende velden in een verzoek af met 422 SMSUnsupportedFeature:
scheduled_at, media_urls, broadcast_id, campaign_id, audience_id, contact_id, topic_id, personalization, options.max_price_per_segment, options.track_clicks (als true)
Neem deze velden niet op in een verzending.
Veilig opnieuw proberen
Stuur de header Idempotency-Key mee met een unieke waarde per logische verzending. Slaagt een verzoek zonder dat je een antwoord ontvangt, verstuur dan hetzelfde verzoek opnieuw met dezelfde sleutel. Bird geeft dan het oorspronkelijke resultaat terug in plaats van een dubbel bericht te versturen. Zie idempotentie voor de sleutelindeling en de bewaartermijn.
Kosten en facturering
Uitgaande SMS wordt per segment gefactureerd. Wat je betaalt, hangt af van het land van bestemming en de provider. Sommige routes rekenen een toeslag van derden, zoals de providerkosten voor US 10DLC.
De cost van een bericht splitst de kosten op in benoemde onderdelen. transaction_amount is wat Bird rekent voor het transport van het bericht, passthrough_amount is een doorberekende vergoeding van derden, en amount is de som van de onderdelen waarvan de prijs al bepaald is, uitgedrukt in currency_code. Een onderdeel zonder bepaalde prijs is null in plaats van "0.00000". Een bericht waarvan de toeslag nooit is bepaald, rapporteert amount dus als alleen de transportkosten. De berichtreferentie beschrijft elk veld.
De toeslag wordt naar beste vermogen bepaald. Bird bepaalt die bij het vastleggen van het afleverbewijs, binnen een begrensde periode. Lukt dat niet binnen die periode, dan blijft passthrough_amount permanent null: Bird probeert het niet opnieuw, en amount blijft gelijk aan de transportkosten.
Inkomende SMS wordt op twee regels gefactureerd: het inkomende tarief per segment en, waar van toepassing, een inkomende providertoeslag. Beide staan 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 bepaald zodra het bericht wordt geaccepteerd, niet bij aflevering. Die wordt dus nooit later ingevuld.
Bekijk de kosten en segmenten per bericht in het SMS-logboek.
Volgende stappen
- SMS-sjablonen: verstuur een ingebouwd sjabloon en laat Bird de afzender kiezen.
- SMS-log: zoek een bericht op en bekijk de levenscyclus, segmenten en kosten ervan.
- Events: ontvang leveringsevents in je eigen systemen.
- SMS-callback-URL's: stuur de events van één bericht of één profiel naar een eigen HTTPS-endpoint.
- SMS-metrics: volg het leveringspercentage, het foutpercentage en het geaccepteerde volume.
- Idempotentie: probeer veilig opnieuw met de header
Idempotency-Key. - Uw eerste SMS verzenden: een video die dezelfde configuratie stap voor stap in het dashboard laat zien
Gerelateerde bronnen
Ga verder met de documentatie, handleidingen en voorbeelden voor dit onderwerp.