Templates
Write, submit and send the pre-approved WhatsApp messages that reach customers outside the 24-hour window.
A template is a message written in advance, reviewed by Meta, and then sent with the changeable parts filled in. It is the only way to reach a customer outside the 24-hour window — which, for anything your own systems trigger, is nearly always.
Almost every template is one you write. The exception is described under Amomic-AI templates below.
Meta requires approval because templates are how a business can message someone who is not currently talking to it. Review is the control on that. It is not a formality: a template that reads like unsolicited promotion in a category that claims otherwise gets rejected, and templates that provoke blocks pull down the number's quality rating.
Who can do it. Anyone who can open Channels → WhatsApp can write, submit and sync templates. Uploading header images and videos, and deleting templates, need the owner or admin role.
Where templates live #
Open Channels → WhatsApp, select a number, and open its Templates tab. Templates belong to the WhatsApp Business Account, so every number on the same account shows the same list.
| Part | What it shows |
|---|---|
| Sync | Pulls the current state of every template from Meta, including ones created in WhatsApp Manager. The console confirms how many it synced. |
| New template | Opens the composer. See Writing one. |
| Approved / Pending / Rejected | How many templates are in each state. |
| The table | Name, Language, Category and Status for each template. Under the name: the number of variables, Meta's rejection reason, or "Needs a header image before it can be sent". Click a row to open it; the bin icon deletes it. |
| Amomic-AI templates | Below your own templates. See Amomic-AI templates. |
With no templates yet, the tab says "No templates yet" with New template and Open WhatsApp Manager. If the number has no WhatsApp Business Account ID, the tab shows "WhatsApp Business Account required" instead: reconnect the number through Meta. See Reconnect a sender.
Anatomy #
A template has one required part and three optional ones.
| Component | Required | Limit | Notes |
|---|---|---|---|
| Header | No | 60 characters for text | A short bold line, one image, or one video. |
| Body | Yes | 1024 characters | The message. Where variables normally live. |
| Footer | No | 60 characters | Small print. No variables allowed here. |
| Buttons | No | 10 | Quick replies, links, or a call button. |
Plus two identifiers that are not shown to customers: a name (lowercase letters, numbers and underscores, up to 128 characters) and a language code.
Your order is on the way
Hi Asha, your order AM-4821 has shipped and arrives by 6 PM today. Track it any time with the button below.
Reply STOP to opt out
Rendered with the same rules WhatsApp applies — what you see is what your customer gets.
Image headers #
In the composer, set Header to Image. Drop a file on "Drop an image here, or click to choose", or click to pick one.
- JPEG or PNG only, under 5 MB. WhatsApp doesn't accept WEBP, GIF or other formats in a header. Anything else is refused with "Use a JPEG or PNG — WhatsApp won't accept other formats in a header."
- You choose the crop. WhatsApp shows a header as a wide strip (1.91:1) and crops the middle to get it. The console opens Crop the header image first: drag to choose what stays, zoom with the slider or scroll, then Use image. The crop you confirm is what Meta reviews and what customers see.
- Adjust crop, Replace and the bin icon change or remove the image before you submit. If a crop comes out over 5 MB, zoom out or start from a smaller image.
Video headers #
Set Header to Video and drop a file on the video zone. The video must be MP4 (H.264 video, AAC audio), under 16 MB. There's no crop step: WhatsApp fits a header video inside the bubble rather than cropping it.
The console checks the file type and size. It can't check the codecs, so a video in another codec is refused by Meta when it's sent.
Switching the header between Text, Image and Video keeps what you'd entered in each, so you can look at another option and come back. Only the format selected when you submit is sent.
Every send uses the attached file #
An approved image or video template needs its file every time it's sent. Amomic-AI attaches the file stored with the template automatically, whether the send comes from the API, an agent, a campaign or the console. You never pass the file yourself.
Change the picture on an approved template #
Meta approves that a picture goes above the message, not which picture. So you can swap it without a new review.
Open the template from the list. The Header image (or Header video) section shows the current file: "Swap it any time — Meta approved the layout, not the file, so a new image needs no review." Choose Replace and pick a new file. The console confirms "Image updated. It goes out with the next message — no new review needed."
This is how this month's offer runs through a template approved last month.
Templates created in WhatsApp Manager #
A template with an image or video header that you created in WhatsApp Manager arrives through Sync without its file, because Meta doesn't hand the file back. It's approved, but it can't be sent until you add one here.
The list marks it "Needs a header image before it can be sent". Open it, and the dialog says "This template shows an image, but none is attached here". Choose Upload image (or Upload video). No new review is needed.
Until then a campaign using it is blocked with template_media_missing, an agent picks another template, and an API send fails with 412 failed_precondition.
The console can't preview or compose templates with a document header. A synced one says so in its dialog.
Categories #
There are exactly three. Pick the one that describes what the message actually does — misclassifying is a common rejection reason, and marketing costs more than utility.
| Value | Label | Use it for |
|---|---|---|
UTILITY |
Utility | Follows up on something the customer did — an order, a booking, an account change. |
MARKETING |
Marketing | Promotions and announcements. Costs more and needs clearer opt-in. |
AUTHENTICATION |
Authentication | One-time passcodes only. |
Create AUTHENTICATION templates in WhatsApp Manager
The authentication category has rules of its own at Meta — fixed body structure, code-expiry handling, autofill behaviour — and the console composer does not implement them. If you need one-time-passcode templates, create them in WhatsApp Manager, then press Sync to pull them into the console so they can be sent. Everything on this page about sending applies to them normally; only authoring is elsewhere.
Status #
Templates carry Meta's verdict as a raw lowercase string. Three values matter:
| Status | Meaning |
|---|---|
pending |
With Meta for review — usually minutes, sometimes a day. The status updates itself; you do not need to poll. |
approved |
Ready to send. |
rejected |
Meta won't deliver this. Meta's reason, such as INCORRECT_CATEGORY, shows under the name in the list and in full under Why Meta rejected it in the template's dialog. |
Template pickers elsewhere in the console show pending as In review, with a note that it can't be sent until Meta approves it.
Only approved templates can be sent. Naming a pending or rejected one returns 404 not_found with details.reason of "template_not_found" — the name exists in your workspace, but not as something sendable.
Statuses you did not expect
Meta occasionally reports states beyond these three, and they pass through lowercased rather than being forced into a bucket we would have to guess at. Treat anything that is not the literal string approved as not sendable.
Variables #
Variables are numbered placeholders: {{1}}, {{2}}, {{3}}. You write them into the body when you author the template, and supply the values at send time.
Hi {{1}}, your order {{2}} has shipped and arrives by {{3}}.
Meta reviews the template with sample values filled in, so the composer asks for one sample per placeholder. Use realistic values — Priya and AM-10428, not xxx and 123. A reviewer reading Hi xxx, your order 123 has shipped is being shown something that looks like spam.
Rules the composer enforces before it will submit, because Meta rejects on all of them:
- A body cannot start or end on a placeholder. "The message can't start or end on a
{{n}}— put words around it." - Two placeholders cannot be adjacent. "Two
{{n}}next to each other reads as blank to a reviewer — separate them with words." - Numbering must be contiguous from 1. "Numbers must run 1, 2, 3… —
{{5}}appears without{{2}}." - Every placeholder needs a sample.
- Footers cannot contain placeholders.
Supplying values at send time #
Values are matched to placeholders by position. Two shapes are accepted:
{ "variables": ["Asha", "AM-4821", "6 PM today"] }
{ "variables": { "1": "Asha", "2": "AM-4821", "3": "6 PM today" } }
They mean the same thing. The array is less error-prone in code you will read again in six months; the object survives refactoring better when a template gains a placeholder.
Header and button variables are supplied separately, with header_variables and button_variables, using the same two shapes.
Passing the wrong number of values returns 400 invalid_argument with details.reason of "template_variables". Values are stripped of newlines and tabs and truncated at 1024 characters before they reach Meta — WhatsApp does not allow a placeholder to inject line breaks into a reviewed layout.
Buttons #
Three button types exist. Nothing else.
| Value | Console label | What it does |
|---|---|---|
QUICK_REPLY |
Quick reply | Sends its own label back to you as a message from the customer, which also opens the 24-hour window. |
URL |
Visit website | Opens a link. The link may end in a single {{1}} so you can point at a specific order or booking. |
PHONE_NUMBER |
Call phone number | Dials a number you specify, in full international form. |
Limits, all enforced before submission:
- 10 buttons maximum on a template.
- WhatsApp shows three. With four or more, it shows the first two and hides the rest behind See all options. The composer's preview shows exactly that. Treat three as the practical design limit and 10 as the ceiling.
- At most 2
URLbuttons. - At most 1
PHONE_NUMBERbutton. - Labels up to 25 characters, no duplicates, no placeholders in labels.
- Quick replies must be grouped together — Meta rejects them mixed in between link and call buttons.
- A
URLbutton's link must start withhttp://orhttps://, may end in one{{1}}and nothing else, and needs an example of the full link with the value filled in.
Languages #
A template is identified by name and language together, not by an id. That pair is what Meta matches on when you send.
The console offers: en, en_US, en_GB, hi, mr, gu, ta, te, bn, kn, ml, pa.
At send time you may omit language, or name one that has no exact match. Resolution then tries, in order: an exact match, then the same base language (en_US falls back to en), then any en* variant, then the first approved template with that name. This means a send does not fail merely because you asked for en_GB and only en was approved.
To offer a template in a second language, duplicate it, keep the name, and change the language. Same name plus same language is rejected as a duplicate.
Writing one #
- 1
Open the composer
On the number's Templates tab, choose New template. The composer opens as New message template, with the form on the left and a live preview on the right.
- 2
Describe the message, or write it yourself
Type what the message is for under Describe the message and choose Generate, or click a starter: Order shipped, Appointment reminder, Payment receipt or Feedback request. The draft follows Meta's rules: placeholder placement, sample values, category and buttons.
The draft is written from the knowledge base of the agent assigned to this number. The console says which happened: "Written from this agent's knowledge base — edit anything before submitting.", or "Written without a knowledge base, so it's generic." A note under Category explains the category it chose, because category decides what Meta charges. Notes under Message say what it drew on.
Whatever it produces is a starting point. Regenerate writes another. Read every line before submitting; you're accountable for what Meta reviews.
- 3
Name it for the system that will send it
service_visit_confirmed,amc_renewal_reminder,payment_receipt. Name is lowercased, and spaces become underscores as you type. Customers never see it; your code does, and so does whoever debugs it. - 4
Fill in the rest
Pick the Language and Category, an optional Header, the Message, a Sample values entry for each
{{n}}, an optional Footer and up to 10 Buttons. Counters show how close you are to each limit. - 5
Check the preview
The preview has two views. Samples shows what the customer receives. As submitted shows what Meta's reviewer reads, with the placeholders visible. Read the reviewer view; most rejections are obvious from it.
- 6
Submit for review
Choose Submit for review. If anything breaks Meta's rules, the composer names it and doesn't submit. Otherwise it confirms "Submitted to Meta. Review usually takes a few minutes to a day." and the template appears as
pending.If it says "Submitted to Meta. It isn't in the list yet — press Sync in a moment to pull it in.", Meta has it, and Sync brings it into the list.
Reading a template #
Click any row to open the template. Nothing in the dialog edits it, except the header file.
| Section | What it shows |
|---|---|
| Status line | The status, category and language, and what the status means. |
| Why Meta rejected it | On a rejected template, Meta's reason in full. |
| Header image / Header video | The attached file, with Replace. See Image headers. |
| Sending it | The Name and Language to send it by, each with a copy button, and Variables (n) with the sample Meta reviewed for each. |
| Identifiers | Meta id, which WhatsApp Manager uses, and the console's own id. Send by name and language, not by either id. |
| Created, Last updated | When it was submitted or synced, and last changed. |
The footer has Open WhatsApp Manager, Delete and Duplicate as new.
Templates cannot be edited #
There is deliberately no edit control. An approved template is a thing Meta reviewed; changing its text would mean sending customers something that was never reviewed.
To change one, open it and choose Duplicate as new:
- Change the name to create a separate template. Both exist; you switch your code over when the new one is approved, then delete the old one.
- Keep the name and change the language to add a language variant.
This is also why deploying a template change is a two-step release: get the new template approved first, then point your code at it. Doing it in the other order means an outage between the code deploy and the approval.
Deleting removes every language variant
Meta deletes templates by name, not by id. Deleting order_shipped removes the English, Hindi and Marathi versions together, and anything still sending that name starts failing with template_not_found immediately. There is no undo and no grace period.
Sending one #
curl -X POST https://services.amomic.in/api/v1/messages \-H "Authorization: Bearer $AMOMIC_API_KEY" \-H "Content-Type: application/json" \-H "Idempotency-Key: order-4821-shipped" \-d '{"to": "+919876543210","template": {"name": "order_shipped","language": "en","variables": ["Asha", "AM-4821", "6 PM today"],"button_variables": ["AM-4821"]}}'
{"message_id": "wamid.HBgMOTE5ODc2NTQzMjEwFQIAERgSMkI5RUE4...","channel": "whatsapp","to": "+919876543210","status": "sent"}
status: "sent" means we accepted it and Meta took it. It is an acceptance acknowledgement, not a delivery receipt — delivery and read state arrive later on the message.status webhook.
Send the Idempotency-Key. A network timeout on a template send is exactly the case where a naive retry messages a customer twice. See Idempotency.
Errors you will actually hit #
not_foundtemplate_not_foundNo approved template with that name. Either the name is wrong, or the template is still `pending` or was `rejected`.invalid_argumenttemplate_variablesWrong number or shape of variables for that template's placeholders.permission_deniedsuppressedThe recipient has opted out. Templates do not bypass suppression.failed_preconditionchannel_not_connectedNo WhatsApp sender is connected to this workspace.failed_preconditiontemplate_media_missingThe template has an image or video header and no file is attached in this workspace. Upload one on the template's dialog. See Image headers.Note what is not in that list: there is no window error on a template send. Templates work whether the window is open or closed — that is their entire purpose.
Amomic-AI templates #
A few features of ours have to reach a customer outside the window, so they need a template of their own. They sit on the Templates tab, in the Amomic-AI templates card below your own templates, and carry the reserved amomic_ name prefix.
Today there is one. amomic_ticket_update is what lets a support reply reach someone who last messaged you more than 24 hours ago: they get the notification, tap View update, and the reply that was waiting is delivered. Without it, a ticket reply can't reach a customer whose window has closed. Check the reply's delivery state on the ticket rather than assuming it will go out when they next write.
We do not submit it without asking. Meta reviews it against your WhatsApp Business Account and records any rejection there, not with us, so the card asks: "Send this template to Meta for approval?", with Send for approval and Skip for now. Review is free, and nothing is sent to any customer until you reply to one.
Skip for now is a real answer. Replies inside the 24-hour window are unaffected, and the offer comes back wherever a missing template is actually holding a reply up. You can also send it later from the card.
Each Amomic-AI template carries a badge: Approved, Using yours, In review, Rejected or Not sent for approval. Recheck asks Meta again.
The wording and variable shape are fixed, because the code that sends it relies on both. What you can do instead is nominate one of your own approved templates in its place: choose Use one of your own templates, pick it under Send one of your own templates instead, and choose Use this template. It has to be approved, accept the same three variables in the same order (customer name, ticket reference, ticket subject), and carry a tappable quick-reply button. Go back to ours undoes it. Sending for approval, skipping and nominating need the owner or admin role.
A link button cannot replace a quick reply here
Tapping a URL button opens a browser and sends nothing back to us, so it never re-opens the 24-hour window — the customer would tap, see a page, and still never receive the reply. A substitute with only a link button is refused when you nominate it, rather than failing silently on a customer's phone.
Practical guidance #
One template per system event, named after the event
order_shipped, order_delivered, payment_received. Resist the general-purpose template with six placeholders that any system can fill — it reviews badly, reads badly, and the day one caller passes the wrong argument order you have shipped nonsense to real customers.
- Get templates approved before you write the integration. Review time is not under your control. Building first means your launch date is Meta's decision.
- Put a
QUICK_REPLYon anything you want a response to. A tapped quick reply is an inbound message, so it opens the 24-hour window and your agent can take the conversation from there in free-form text. - Keep the body under 1024 characters and well under it in practice. Long templates read as promotional regardless of category.
- Do not put an opt-out line in the footer of a utility template unless you want it there; the opt-out keywords work whether or not you advertise them.
Reply STOP to opt outis standard on marketing and unnecessary noise on a delivery notification. - Watch the quality rating on the sender after you start sending at volume. Red quality means recipients are blocking or reporting you, and Meta reduces messaging limits if it stays that way.
Next #
The 24-hour window
Why templates exist and when a free-form send is legal instead.
POST /messages
The complete send contract, including sender selection and metadata.
Order-shipped update
End to end — template, idempotent send, and the webhook that confirms delivery.
Tools & actions
Let the agent send a template itself, restricted to the ones you allow.