Skip to main content

Outbound templates

A template is a saved message body you write once and reuse in campaigns, one-off sends, and drip sequences. Instead of re-typing the same confirmation or promo for every send, you author it in Outbound → Templates, let it clear any channel approval it needs, and pick it from the message step of the campaign-create wizard. Templates live side by side with campaigns under the Outbound hub (an entry point under Messages → Templates reaches the same library — same rows, either door).
Voice is not a template channel. The template library covers text channels: SMS, WhatsApp, RCS, email, Viber, Telegram, LINE, Messenger, Instagram, push, fax, and Apple Messages for Business. A voice call flow (Jambonz/speech IVR) is authored in Agents/Studio instead. (Template authoring itself is feature-free and does not interact with outbound routing invariants.)

What a template is

A template record carries a channel, a name, a language, and the message content — the body text (or, for rich channels, a body plus optional media). Two placeholder systems personalize that content at send time:
  • Variables — merge tokens written in the body as double-curly placeholders, for example {{first_name}} or {{order_id}}. At send time the campaign (or the single-message composer) substitutes per-recipient data from the contact record or the send payload.
  • Conditional blocks — depending on the channel, richer structures such as WhatsApp’s header/footer/buttons or RCS rich cards are built in a dedicated editor, but the body itself stays a single text block (plus media for MMS-style messages).
For most channels the library is flat: each row is one channel’s variant, authored directly. A second tab, Content Templates, offers a cross-channel author layer: one logical content id grouping per-channel variants with a fallback order (Twilio Content API parity). Use it when the same copy must serve several channels under one definition.

Channel-specific rules

What you can author, and what happens after you save it, depends on the channel:
  • WhatsApp — templates must clear Meta’s model approval. Until the approved status is in, the template can’t be used from a campaign or a test send. Author the copy, pick a category (marketing, utility, or authentication — a WhatsApp-only taxonomy), submit it, and wait for Meta’s review. A rejection reason (if any) is visible in the template row.
  • RCS — rich cards and carousels are reviewed per carrier; editing a template re-enters the pending state and old sends keep using the prior approved version.
  • SMS / email / Viber / Telegram / LINE / Messenger / Instagram / push / fax / Apple Messages — no carrier approval queue; a saved template becomes active immediately and is sendable. Email bodies fit MJML-style HTML in the content body if you paste rendered HTML, but plain text works too (the composer handles raw bodies).
  • SMS unresolved variables — SMS has no server-side merge on the composer send path: if a template body still contains {{name}} tokens when you open the composer, the UI flags the unresolved variables so you replace them before sending, instead of shipping literal {{...}} to the customer.
Two WhatsApp-specific helpers live in the hub toolbar: WhatsApp Starter Library (pre-built, policy-compliant Meta templates you can clone in) and Sync from Meta (pull template status/category/quality from your connected WABA to repair drifted rows).

Create a template

  1. Open Outbound → Templates.
  2. Click Create template and pick the channel.
  3. For WhatsApp: pick the WABA (the picker appears only when your tenant has more than one connected) and choose a category.
  4. Fill the body with your copy; insert {{variable}} placeholders where personalization is needed.
  5. Save. Approval-required channels (WhatsApp, RCS) move to pending; platform-only channels land directly at active.
Template management — creating, editing, archiving, and deleting — is restricted to the owner, admin, and developer roles.

Worked examples over the API

Every step below is a copy-pasteable call against https://api.orbit.devotel.io/api/v1. Sign with a test key (dv_test_sk_…) to run in sandbox, or a live key (dv_live_sk_…) for production. Template mutations require the templates:write scope (plus an owner/admin/developer dashboard role); reads accept templates:read or templates:write. Keep it simple — a full key listing every scope works for all of these.

List templates

GET /api/v1/messages/templates returns a cursor-paginated page, newest first, with optional channel, status, search, waba_id, and purpose filters:
Each row carries the id, channel, name, language, status, and the content body — the same fields the hub shows in its two-line preview.

Create a template

POST /api/v1/messages/templates with a channel, name, language, and the body. Placeholders go in as double-curly tokens you fill at send time:
Platform-only channels (sms, email, mms, viber, telegram, line, messenger, instagram, push, fax, apple_messages) come back active and sendable immediately. Approval-required channels (whatsapp, rcs, kakao, zalo) come back draft — move them to pending with a PATCH .../templates/:id of { "status": "pending" }, or hand them to the carrier-submit dialog in the hub. For WhatsApp you can also pass a category (marketing | utility | authentication) and, for the rich component shape (header/footer/buttons), a components array instead of a plain body.

Send with the template

Reference the template by name at send time and pass the per-recipient merge values in template_params. The example sends one SMS and substitutes {{first_name}}:
Include the resolved text in body (the composer does this automatically) so the send is still well-formed if the lookup misses a template. For WhatsApp the shape is channel-specific: pass template: { "name": "order_shipped", "language": { "code": "en" } } plus the same template_params map on POST /messages/whatsapp.

Track the approval status

Channel lifecycle states: draft → pending → approved / rejected for WhatsApp and RCS; active right away for platform-only channels; paused and archived are operator-set at any stage. Editing a WhatsApp or RCS template re-submits it, so a previously approved row drops back to pending while the old approved version keeps serving sends. Patch an approved WhatsApp body and the response shows the re-review state:
RCS behaves the same way through the per-carrier review queue. Poll GET /api/v1/messages/templates/:id for approval state, or use the hub’s Sync from Meta button to pull WhatsApp status for every row at once.

Group channels with Content Templates

The second tab, Content Templates, is the cross-channel layer (Twilio Content API parity): one logical content id grouping per-channel variants with a fallback order. Author once, and the same copy serves WhatsApp with an SMS fallback under one definition:
Use it when one definition must serve several channels; per-channel approval state still applies to the WhatsApp variant.

Test send in sandbox

Anything signed with a dv_test_sk_… key runs in sandbox — simulated delivery, no credits burned, no real message dispatched. That makes the send above a test send as-is. To test-deliver a template to yourself, send it to your own number with the test key and confirm the simulated receipt marked "test_mode": true in meta. On WhatsApp, only approved templates test-send (the hub enforces the same rule); on SMS the composer flags unresolved {{...}} tokens so you replace them before the send goes out — the same check applies to API sends.

Governance: scopes and roles

Writes require the templates:write scope; a key holding only messages:write gets a 403:
Dashboard sessions gate mutations to the owner, admin, and developer roles, so viewers and members can pick templates into campaigns without being able to mutate the library.

Manage versions and lifecycle

Opening the library shows a row per template with status, category (WhatsApp only), language, and a two-line body preview.
  • Edit — patch the body/name/category/language. Editing a WhatsApp or RCS template re-submits for review; an old approved version stays usable while the new one is pending.
  • Clone — duplicates the row with a _copy name as a new variant. This is the canonical A/B mechanism, because per-template metrics live on the template id — two clones are two measurable variants.
  • Localize — the Languages action opens a per-locale tracker listing every language variant and its approval status, and can auto-translate into more locales.
  • Archive — soft-delete; the row leaves compose pickers and test-send lists, and stays restorable from the archive view.
  • Delete — permanent, after a confirmation dialog.
  • Test send — fire one to yourself (WhatsApp only after approval; SMS opens the in-place composer; other channels deep-link to the channel’s compose dialog with the template pre-selected, and the recipient is marked as a test contact so one-off test sessions do not pollute your contacts list).

Use a template in a campaign

  1. Open Outbound → Campaigns → Create.
  2. In the message step, pick Use a template and select the template from your library. The wizard pre-fills the body for you to review and adjust (for WhatsApp, only approved templates show; for SMS/email/etc., any active template shows).
  3. Drip sequences treat the campaign’s message_template as the step-0 welcome message; every step can carry its own template or inline body.
  4. A/B testing across template versions: create two clones (as above), then run both variants against the same audience — each variant accumulates its own metrics.

Read template analytics

After a campaign sends, Outbound → Templates → row Analytics action opens the cross-campaign rollup: sent → delivered → opened → clicked, consolidated across every campaign that reused that template. See Template analytics for the rollup’s exact semantics — the terminal-as-denominator convention, the degraded flag on transient fallbacks, and the per-channel breakdown.

Governance: naming and edit roles

Keep the library trustworthy with two conventions:
  • Naming: adopt a <purpose>_<variant>_<locale> convention (e.g. order_confirm_v2_en, promo_blast_a_es) so the body preview plus the name together identify what a row is without opening it.
  • Who can edit: restrict template create/edit/delete/archive to the owner/admin/developer roles (enforced by the hub’s role guard). A larger team can view and pick templates in campaigns without being able to mutate the library.