Skip to Content
Templates

Templates

Returns all approved WhatsApp message templates linked to a given phone number. Each template includes an expected_variables field that tells you exactly which values to pass when sending.

Create templates in the Bahasha Dashboard  if you haven’t already.

List templates for a phone number

GET /v1/whatsapp/phone_numbers/:phone_number_id/templates

The :phone_number_id is the id field returned by the Phone Numbers endpoint.

The phone_number_id used in all requests is the id field returned by the Phone Numbers endpoint. This is different from the actual phone number itself.

curl https://api.bahasha.app/v1/whatsapp/phone_numbers/123456789/templates \ -H "Authorization: Bearer bh_live_xxxxxxxxxxxx"

Response

[ { "id": "6643c2a1f4e3b12d5c9a0001", "name": "order_confirmation", "language": "en_US", "category": "UTILITY", "status": "APPROVED", "components": [ { "type": "BODY", "text": "Hi {{customer_name}}, your order {{order_id}} is confirmed." }, { "type": "BUTTONS", "buttons": [ { "type": "URL", "text": "Track order", "url": "https://shop.com/track/{{1}}", "example": ["https://shop.com/track/TRK-98765"] } ] } ], "expected_variables": { "header": [], "body": [ { "param_name": "customer_name", "example": "John Doe" }, { "param_name": "order_id", "example": "ORD-12345" } ], "buttons": [{ "param_name": 1, "example": "TRK-98765" }] } } ]

Key fields

FieldDescription
idUse this as templateId in all media endpoints.
nameTemplate name — use this as template_name when sending
languageLanguage code — use this as language_code when sending
expected_variablesObject with header, body, and buttons arrays. Each entry has a param_name (key to use when sending) and an example value. Carousel templates add a cards object — see Carousel card variables.

Get a specific template by name

GET /v1/whatsapp/phone_numbers/:phone_number_id/templates/:templateName

Fetches a single template by its name. Use this when you already know the template name and want its expected_variables without fetching the full list. Template names can be found in the Bahasha dashboard.

curl https://api.bahasha.app/v1/whatsapp/phone_numbers/123456789/templates/order_confirmation \ -H "Authorization: Bearer bh_live_xxxxxxxxxxxx"

Response

{ "id": "6643c2a1f4e3b12d5c9a0001", "name": "order_confirmation", "language": "en_US", "category": "UTILITY", "status": "APPROVED", "components": [ { "type": "BODY", "text": "Hi {{customer_name}}, your order {{order_id}} is confirmed." }, { "type": "BUTTONS", "buttons": [ { "type": "URL", "text": "Track order", "url": "https://shop.com/track/{{1}}", "example": ["https://shop.com/track/TRK-98765"] } ] } ], "expected_variables": { "header": [], "body": [ { "param_name": "customer_name", "example": "John Doe" }, { "param_name": "order_id", "example": "ORD-12345" } ], "buttons": [{ "param_name": 1, "example": "TRK-98765" }] } }

Returns 404 if the template name does not exist or is not accessible for the given phone number.


Understanding expected_variables

The expected_variables object tells you what to pass in the variables field when sending. There are three variable styles:

Styleparam_name typeExample key in variables
No variablesOmit variables entirely
NamedString, e.g. "customer_name"variables.body.customer_name
PositionalNumber, e.g. 1variables.body["1"]

Authentication templates always have a single body variable with param_name: 1 — this is the OTP code.

Button (URL) variables

A URL button can end with a single dynamic value, e.g. https://shop.com/track/{{1}}. Button variables are always positional — even for named templates, WhatsApp only treats a positional {{1}} in a button URL as dynamic. When present, the button appears in expected_variables.buttons with a numeric param_name (its position) and an example. Pass the value under variables.buttons keyed by that param_name when sending — Bahasha appends it to the end of the button’s link. Buttons without a variable do not appear in expected_variables.buttons.

Carousel templates have a variable set per card, reported under an extra cards key. It is keyed by the card’s position in the message, starting at "1", and each card holds the same body and buttons arrays as the top level:

"expected_variables": { "header": [], "body": [{ "param_name": "name", "example": "Pablo" }], "buttons": [], "cards": { "1": { "body": [{ "param_name": 1, "example": "Aloe" }], "buttons": [{ "param_name": 1, "example": "aloe" }] }, "2": { "body": [{ "param_name": 1, "example": "Cactus" }], "buttons": [{ "param_name": 1, "example": "cactus" }] } } }

A card’s body placeholders are always positional, even when the rest of the template uses named variables — WhatsApp does not allow named parameters inside a card. Card buttons follow the same rule as top-level URL buttons: only a URL button with a variable at the end of its link appears, with its position as param_name.

Every approved card is listed, even one with no variables of its own — so the keys of cards are the card count. Templates without a carousel have no cards key at all.

When sending, variables.cards uses the same positions: whatever you read under cards["1"] you fill in at cards["1"]. See Carousels for the full mapping and Product Carousels for catalog-backed cards.

A product carousel reports only the card positions it was approved with, usually "1" and "2". WhatsApp requires every card to be structurally identical, so those positions describe all 2–10 cards you can actually send.

See Template Variables for full examples.