Documentation
Sign inGet started

SMS templates

A template is a pre-registered message body you send by reference instead of inlining the text on every call. It carries its own category and typed variable slots, so a send supplies only values that change, such as a one-time passcode or order number. The catalog contains Bird's built-in system templates for common authentication and transactional messages. Workspace template authoring is unavailable.
Compared with a free-text send, a template send fixes the category and sender. The template's category determines the per-country compliance classification. Bird selects the sender for the destination, so you don't pass from.

Browsing templates in the dashboard

The Templates page under SMS lists every template available to your workspace. Search by name or filter by status and category.
The SMS Templates tab: a search box with Status and Category filters above a table of templates, each row showing a name, an Active status, a category, an EN language chip, and a System scope, across Name, Status, Category, Language, Scope, and Updated columns.
Each row shows the fields you need to pick and send a template:
  • Name: the template's display name and its slug (for example bird_order_confirmation). The slug is the handle you pass when sending; it's fixed at creation.
  • Status: the template's lifecycle state, rolled up across its languages. Active means at least one language is live, so the template can be sent, which is what every built-in system template reads. Draft has never had content go live, Pending is awaiting review, Rejected was reviewed and refused, and Inactive has nothing live and nothing in review.
  • Category: the content classification (transactional, marketing, authentication, or service) applied to every message sent from the template.
  • Language: the languages the template is stocked in, as BCP 47 tags. The first few are shown as chips with a +N overflow when a template is localized into many languages.
  • Scope: System for Bird's built-in templates. Workspace is reserved for workspace-owned templates, which cannot currently be authored.
  • Updated: when the template last changed. Built-in templates show no date.

What's in a template

Alongside its name, category, and languages, each template defines the variables it fills at send time. A variable has a key, type, required flag, and a human-readable constraint. A sensitive variable keeps its value out of storage. Supply every required variable and no undeclared keys.
A template is stocked in one or more languages, and its default_language is what a send gets when it names none. Ask for a language the template isn't stocked in and Bird falls back: first to a broader form of the same language, then to the default language, because SMS templates default on_missing_language to fallback. A template can instead require every send to name a language explicitly, with language_source_required.

Listing templates from the API

GET /v1/sms/templates returns the catalog in full; it is small and not paginated. Reading templates needs an API key with the sms_management scope, which is separate from the sms scope a send uses. Filter by scope, category, or language to narrow it:
const { data } = await bird.smsTemplates.list({ scope: "system" });
for (const tpl of data) console.log(tpl.id, tpl.slug);
Each template contains its slug, scope, category, status, language configuration, expected variables, and a default-language body preview. The language configuration includes default_language, available_languages, languages, on_missing_language, and language_source_required. A built-in template's live_version_id is null because it ships ready to send rather than as a version. Fetch one by slug or ID with GET /v1/sms/templates/{template_ref} to read its variables before a send.

Sending with a template

Set the send's template object instead of text. Because the template decides the message and its sender, text, category, from, and media_urls are not accepted alongside it:
await bird.sms.send({
  to: "+14155550100",
  template: { slug: "bird_otp_verification", parameters: { code: "123456" } },
});
slug is the template's handle from the catalog (you can identify a template by its id instead). language selects the localized body; omit it for the template's default language. parameters supplies a value for each of the template's variables, keyed by variable name. A missing required variable, an undeclared key, a value that doesn't match its variable's constraint, or a parameters object over 16 KB serialized is rejected with a 422.
The 202 response shows what the template resolved to: the rendered body in text, the template's category, and the sender Bird selected in from:
Code example
{
  "id": "sms_01ky7qc2nmf1s8fe22xd4qdvre",
  "direction": "outbound",
  "status": "accepted",
  "to": "+15551234567",
  "from": "Authifly",
  "text": "123456 is your verification code. Do not share it.",
  "category": "authentication",
  "segments": { "count": 1, "encoding": "GSM_7BIT", "characters": 50 },
  "cost": null,
  "carrier": null,
  "mcc_mnc": null,
  "sent_at": null,
  "delivered_at": null,
  "created_at": "2026-07-23T14:51:45.716Z"
}
Everything else about the send (the recipient, tags, metadata, the destination allowlist, and the async 202 model) works exactly as it does for a free-text send.

Next steps

  • Sending SMS: add the template field to a send payload.
  • SMS log: find a sent message and follow its lifecycle.
  • Events: receive each message's delivery events.