Send templates
Templates are pre-approved message structures you use to start a conversation, send transactional notifications, or re-engage past customers — anything outside the 24-hour customer service window.
This page covers the simplest case: a body-only template with text parameters. For richer variants — header media, dynamic URL buttons, Flow buttons, named parameters — see the dedicated pages below.
Find your template
Section titled “Find your template”List templates already approved for your WhatsApp account:
curl https://api.kirimdev.com/v1/$PHONE_ID/templates \ -H "Authorization: Bearer $KIRIM_KEY"Each template returns its name, language, status (approved /
pending / rejected), and the parameterised body.
Name rules
Section titled “Name rules”template.name is a Meta identifier, not free text. It may contain only
lowercase letters, numbers, and underscores (^[a-z0-9_]+$).
Surrounding whitespace is trimmed for you, so a name pasted with a stray
trailing space still sends. Anything trimming cannot repair — interior
spaces, uppercase letters, dashes — is rejected up front with
400 invalid_request_error rather than being forwarded to Meta, which
answers malformed names with a generic “Something went wrong” that is
indistinguishable from a real upstream outage.
"name": "order_shipped" // ok"name": "order_shipped " // ok - trimmed"name": "order shipped" // 400"name": "Order_Shipped" // 400"name": "order-shipped" // 400Send a body-only template
Section titled “Send a body-only template”curl -X POST \ https://api.kirimdev.com/v1/$PHONE_ID/messages \ -H "Authorization: Bearer $KIRIM_KEY" \ -H "Content-Type: application/json" \ -d '{ "messaging_product": "whatsapp", "to": "+628123456789", "type": "template", "template": { "name": "order_shipped", "language": "id", "components": [ { "type": "body", "parameters": [ { "type": "text", "text": "Andi" }, { "type": "text", "text": "INV-4521" } ] } ] } }'import { Kirim } from '@kirimdev/sdk'
const kirim = new Kirim({ apiKey: process.env.KIRIM_KEY! })const phone = kirim.phoneNumbers(process.env.PHONE_ID!)
await phone.messages.send({ messaging_product: 'whatsapp', to: '+628123456789', type: 'template', template: { name: 'order_shipped', language: 'id', components: [ { type: 'body', parameters: [ { type: 'text', text: 'Andi' }, { type: 'text', text: 'INV-4521' }, ], }, ], },})Positional parameters fill the {{1}}, {{2}}, … placeholders in the
template body in declaration order.
Component shapes at a glance
Section titled “Component shapes at a glance”Templates support three component types. Each takes a parameters
array whose shape mirrors Meta’s
Cloud API reference
verbatim — Kirimdev does not re-shape it.
| Component | Purpose | Dedicated page |
|---|---|---|
header | Media or text shown above the body | Header media |
body | Parameterised text content | This page |
button (per index) | Dynamic URL, quick reply, copy code | Buttons |
button (sub_type: url) | OTP / verification code (AUTHENTICATION) | OTP |
button (sub_type: flow) | Trigger a Meta Flow | Flow buttons |
Parameters can be positional (default) or named — see Named parameters.
Media card carousels
Section titled “Media card carousels”To send an approved media card carousel,
add a carousel component whose cards array carries one entry per card,
keyed by card_index. Each card supplies its header asset (an uploaded
media id or a public link) and a parameter for every quick-reply
button (payload) and dynamic URL button (text):
{ "messaging_product": "whatsapp", "to": "+16505551234", "type": "template", "template": { "name": "rare_succulents_carousel", "language": { "code": "en_US" }, "components": [ { "type": "carousel", "cards": [ { "card_index": 0, "components": [ { "type": "header", "parameters": [{ "type": "image", "image": { "id": "1558081531584829" } }] }, { "type": "button", "sub_type": "quick_reply", "index": 0, "parameters": [{ "type": "payload", "payload": "more-aloes" }] } ] }, { "card_index": 1, "components": [ { "type": "header", "parameters": [{ "type": "image", "image": { "link": "https://cdn.example.com/echeveria.jpg" } }] }, { "type": "button", "sub_type": "quick_reply", "index": 0, "parameters": [{ "type": "payload", "payload": "more-echeverias" }] } ] } ] } ] }}You must send exactly the number of cards the template was approved
with. A card header accepts either an uploaded media id
(POST /{phone_number_id}/media) or a public link. If a card’s URL
button was created dynamic ({{1}} suffix), add a
{ "type": "button", "sub_type": "url", "index": N, "parameters": [{ "type": "text", "text": "<value>" }] }
for it. A static button (static URL / phone number) needs no send-time
parameter.
Language object form
Section titled “Language object form”Meta accepts language as either a bare string code ("id",
"en_US") or an object { code, policy? }. Kirimdev accepts both -
prefer the string form since policy was deprecated by Meta.