What it does
Creates a new WhatsApp message template and submits it to Meta for approval. A newly created template’s status is usuallyPENDING.
Endpoint
Headers
string
required
Secret key in
Bearer sk_... format. See Secret Key authentication.string
required
Always
application/json.Path parameters
string
required
Application ID. Must belong to the organization (otherwise
404).Request Body
Top-level fields
string
required
Template name (max 512 chars). Pattern:
^[a-z][a-z0-9_]*$ (must start with a lowercase letter; lowercase letters, digits, and underscores only). Must be unique.string
required
Language code, e.g.
tr, en, en_US. This is a closed list, not free-form BCP-47 — see Template Language. An unsupported code returns 422.string
required
One of
UTILITY, MARKETING, or AUTHENTICATION. Determines the component rules — see the Category rules section below, and Template Category for what each one is for.object | null
Header component. See the header object below.
object
required
Body component. See the body object below.
Footer component. See the footer object below.
array | null
List of buttons (max 10). See the buttons object below. Not allowed together with
carousel — carousel buttons belong to each card.array | null
Turns the template into a carousel: a body bubble followed by 2–10 swipeable cards, each with its own media header, body, and buttons.
MARKETING only. See the carousel card object and Carousel rules sections below.boolean | null
If
true, Meta may automatically re-classify the template’s category.integer | null
Message time-to-live.
UTILITY: 30–43200, MARKETING: 43200–2592000, AUTHENTICATION: 30–900 (or -1).object | null
Turns the template into a limited-time offer — a
MARKETING-only banner that WhatsApp renders above the body, optionally with a live expiration countdown. See the limitedTimeOffer object and Limited-time offer rules sections below.header object
string
One of
NONE (default), TEXT, IMAGE, VIDEO, DOCUMENT, LOCATION. See Header Format.string
Only for
TEXT headers (max 60 chars). Cannot start or end with a variable.string | string[]
Variable example for a
TEXT header; for media headers, the uploaded media handle.body object
string
Body text (max 1024 chars); supports
{{1}}, {{2}} variables. Cannot start or end with a variable. Required for UTILITY/MARKETING.string[]
Example values for the variables (order matters). The count must equal the number of variables.
boolean
AUTHENTICATION only; adds the security recommendation text.footer object
string
Footer text (max 60 chars). Cannot be used in
AUTHENTICATION.integer
AUTHENTICATION only (1–90); the code validity duration.buttons object
Each item in thebuttons array:
string
One of
QUICK_REPLY, URL, PHONE_NUMBER, COPY_CODE, OTP. See Button Type.string
Button text (2–25 chars). Required for
URL / PHONE_NUMBER / QUICK_REPLY.string
URL type target link (https://...); can be dynamic using {{1}}.string
PHONE_NUMBER type phone in E.164 format.string[]
Dynamic URL example, or the
COPY_CODE coupon code (required for COPY_CODE).string
ONE_TAP / ZERO_TAP autofill text (max 25 chars).string
ONE_TAP / ZERO_TAP Android package name.string
ONE_TAP / ZERO_TAP signature hash.boolean
ZERO_TAP terms acceptance.carousel card object
Each item in thecarousel array is one card. Every card must be structurally identical to the others (same header format, same button types in the same order).
object
required
The card’s media header.
format must be IMAGE or VIDEO — no TEXT, DOCUMENT, or LOCATION — and examples must carry the media handle from Upload Media.object
required
The card’s body.
text is required and limited to 160 chars (shorter than the 1024 of the template body). Variables and examples follow the same rules as the template body.array
required
1–2 buttons for this card. Only
QUICK_REPLY, URL, and PHONE_NUMBER are allowed — no COPY_CODE or OTP.limitedTimeOffer object
string
required
The offer text shown on the banner (1–16 chars), e.g.
"Expiring offer!".boolean
Defaults to
false. When true, WhatsApp renders an expiration countdown on the offer; the expiration timestamp itself is supplied per message when the template is sent, not here.Category rules
AUTHENTICATION — no
header; no body.text (only addSecurityRecommendation); no footer.text (only codeExpirationMinutes); buttons may only be OTP.UTILITY / MARKETING —
body.text is required; addSecurityRecommendation and codeExpirationMinutes cannot be used; OTP buttons are not allowed; COPY_CODE is allowed in MARKETING only.The body/header cannot start or end with a variable, and the number of
examples must equal the number of variables.Carousel rules
Sendingcarousel puts the template into carousel mode: the top-level template keeps only its body bubble, and every other component moves into the cards. All of the rules below are enforced locally and fail with 422 before the request reaches Meta.
Carousel is create-only. Update Template does not accept a
carousel field, so an existing carousel template cannot have its cards edited through this API — create a new template instead.Limited-time offer rules
SendinglimitedTimeOffer puts the template into limited-time offer mode, which narrows what the other components may contain. All of the rules below are enforced locally and fail with 422 before the request reaches Meta; omitting limitedTimeOffer leaves every other rule on this page unchanged.
hasExpiration only controls whether the countdown is rendered. The offer’s expiration timestamp is not part of the template; it is provided per message at send time, so the same approved template can be reused for different deadlines.Response
The envelope is{ "data": {...}, "isSuccess": true } (HTTP 200). The data is a lean creation response:
boolean
true when the template was created and submitted.object
The create response does not return
components, qualityScore, rejectedReason, parameterFormat, or the DB id — use Get Template Detail or Get Templates for those.Examples
Demo 1 — UTILITY (lean)
Demo 1 — UTILITY (lean)
Demo 3 — MARKETING (coupon / COPY_CODE)
Demo 3 — MARKETING (coupon / COPY_CODE)
Demo 4 — MARKETING (limited-time offer)
Demo 4 — MARKETING (limited-time offer)
footer is sent and there are exactly two buttons — both are requirements for a limited-time offer. The image header handle comes from Upload Media.Demo 6 — MARKETING (carousel)
Demo 6 — MARKETING (carousel)
Upload one media file per card first, then send the handles in the cards. Note the empty top level: only Both cards use
body is present, and no header/footer/buttons.IMAGE headers and a single URL button — the structure must match across every card.Demo 8 — AUTHENTICATION (OTP)
Demo 8 — AUTHENTICATION (OTP)
Demo 9 — error: same name+language already exists → 409
Demo 9 — error: same name+language already exists → 409
Errors
object
Error details with
code, group, and description; isSuccess is false.Auth / tenant
Request validation (before reaching Meta)
Every rule below is checked locally and returns422 with group VALIDATION; the request never reaches Meta.
Button rules
Header rules
Body rules
Category rules
Name rule
Field-level constraints (
about-style max lengths, limit ranges, unknown enum values, a missing required field) are reported by FastAPI as VAL_* validation errors instead.
Carousel validation (before reaching Meta)
Returned only whencarousel is present. Each row maps to a rule in the Carousel rules section above.
Limited-time offer validation (before reaching Meta)
Returned only whenlimitedTimeOffer is present. Each row maps to a rule in the Limited-time offer rules section above.