Browse documentation

Messaging

Sending template messages

Send an existing approved WhatsApp template, including required language and parameter values.

DevelopersAdvancedAvailable

What this guide covers

  • Select an approved template available to the connected Sender.
  • Match the template language and component parameters exactly.
  • Use templates to initiate conversations outside the customer service window.

When to use a template

Use an approved template to initiate or resume a Live Mode conversation when no active Customer Service Window is known. Templates are also appropriate for consistent notifications that already have approved business content.

Yanola sends only templates already approved for the selected Sender. Template creation, editing, and approval remain outside the public v1 API.

Find an approved template

List the Sender's catalog before building a request. Use the exact name, languageCode, and component shape returned for an approved entry.

List approved templates
ts
import { WhatsAppClient } from "@yanola/whatsapp"

const apiKey = process.env.YANOLA_API_KEY

if (!apiKey) {
  throw new Error("Missing YANOLA_API_KEY")
}

const yanola = new WhatsAppClient({ apiKey })

const { data: templates } = await yanola.templates.list({
  from: "+15557654321",
})

const template = templates.find(
  (item) =>
    item.name === "order_update" &&
    item.languageCode === "en_US" &&
    item.status === "approved"
)

if (!template) {
  throw new Error("Approved order_update template was not found")
}

Send template parameters

Provide one component for each dynamic header, body, or button declared by the approved template. Parameter order, count, type, and—when used—parameter names must match the catalog.

Template send
ts
import { WhatsAppClient } from "@yanola/whatsapp"

const apiKey = process.env.YANOLA_API_KEY

if (!apiKey) {
  throw new Error("Missing YANOLA_API_KEY")
}

const yanola = new WhatsAppClient({ apiKey })

const accepted = await yanola.messages.sendTemplate({
  from: "+15557654321",
  to: "+15551234567",
  name: "order_update",
  languageCode: "en_US",
  components: [
    {
      type: "body",
      parameters: [
        {
          type: "text",
          text: "A123",
        },
      ],
    },
  ],
})

console.log(accepted.id)

Template request contract

Template message fields
FieldContract
from / toSender and recipient in E.164 format.
nameExact approved template name, from 1 to 512 characters.
languageCodeExact approved language such as en_US, from 2 to 16 characters.
componentsOptional only when the approved template has no dynamic values.
headerText parameters or one image, video, or document mediaUrl as declared.
bodyText, currency, or date_time parameters matching approved placeholders.
buttonRequires subType, zero-based index, and the expected URL text or quick-reply payload.

Templates and the Customer Service Window

Approved template sends do not require an active Customer Service Window. That is why service_window_required instructs you to use a template.

Template approval does not remove Sender, scope, subscription, balance, rate-limit, or request-validation checks. Test Mode validates the cached approved template without calling the provider or consuming Yanola Balance.

Template validation errors

Template business-state errors
CodeMeaningAction
template_not_approvedNo approved template matches the Sender, name, and language.Sync or select an approved template.
template_language_not_approvedThe name is approved, but not in the requested language.Choose one of the available approved languages.
template_components_invalidParameters do not match the approved component structure.Use the returned issues to fix count, type, name, or button index.
template_catalog_unavailableThe approved catalog cannot currently be read or refreshed.Retry only when the error says retryable.
sender_reconnect_requiredYanola cannot refresh or use the Sender connection.Reconnect the Sender in the dashboard.

Asynchronous acceptance

Every send method returns a queued response after Yanola accepts the operation. A 202 response is not proof of provider delivery.

Live message IDs start with msg_; Test Mode IDs start with msg_test_. Keep the returned ID and request ID so you can correlate message retrieval, webhook events, logs, failures, and support requests.

Accepted message
json
{
  "id": "msg_...",
  "environment": "live",
  "status": "queued",
  "from": "+15557654321",
  "to": "+15551234567",
  "requestId": "req_...",
  "createdAt": "2026-07-29T10:00:00.000Z"
}

Safe retries and idempotency

The SDK generates a unique Idempotency-Key for every send call and preserves it across automatic transport retries. If your job system owns retry identity, pass a stable idempotencyKey as the second argument.

The same key and request body return the original accepted response. Reusing the key with a different body returns 409 idempotency_key_reused. Yanola retains send idempotency records for at least 24 hours.

Application-owned idempotency
ts
const accepted = await yanola.messages.sendTemplate(
  {
    from: "+15557654321",
    to: "+15551234567",
    name: "order_update",
    languageCode: "en_US",
    components: [
      {
        type: "body",
        parameters: [{ type: "text", text: "A123" }],
      },
    ],
  },
  {
    idempotencyKey: "order-123-template-update",
  }
)