Skip to content
API PlatformDevelopers
PUT/v1/templates/{template_id}beta

Edit a WhatsApp template

Needs
Send WhatsApp messages; manage templates, quick messages and WhatsApp short links (messaging:write)
Plan
Any plan with API access
Limits
60 a minute per key
Dry run
Yes — every check runs with ?dry_run=true, nothing changes
Confirm
Header Api-Confirm: submit
Undo
Edit it again with the old content (it is reviewed again).

Replaces a template's content (header, body, footer, buttons) and resubmits it to WhatsApp for review: it goes back to PENDING and cannot be sent until approved again, so it needs Api-Confirm: submit.

  • name and language must stay the same as the template's; to change them, create a new template.
  • Only APPROVED, REJECTED or PAUSED templates can be edited (409, reason: not_editable, otherwise). WhatsApp limits how often an approved template can be edited, and never lets its category change.
  • A draft that breaks a rule is refused with 400 (reason: template_rules).

Try it with ?dry_run=true: the template is read and the draft checked, nothing is submitted.

Try it

Path

The template id.

Body
template *

The new content. `name` and `language` must match the template's.

Template name: lowercase letters, digits, underscores (e.g. order_shipped_v2).

Meta language code, e.g. en, en_US, ar, hi, pt_BR.

MARKETING | UTILITY | AUTHENTICATION.

header

Optional header.

TEXT | IMAGE | VIDEO | DOCUMENT | LOCATION.

TEXT header: ≤ 60 chars, at most one {{1}}.

TEXT header with {{1}}: its sample value.

IMAGE/VIDEO/DOCUMENT header: the Meta upload handle used as the sample (`POST /v1/templates/samples`).

body

Body.

Body text (≤ 1024 chars) with {{1}}, {{2}} … variables. Omit for AUTHENTICATION (Meta fixes it).

One sample per body variable, in order ({{1}} first).

AUTHENTICATION only: append "For your security, do not share this code."

footer

Optional footer.

Buttons in display order (≤ 10).

limited_time_offer

Limited-time offer (MARKETING; needs a COPY_CODE button).

Offer text shown on the chip (≤ 16 chars).

Show a countdown (the expiry is set when sending).

carousel

Media carousel (MARKETING): the body is the message above the cards; no top-level header, footer or buttons.

Protects against doing it twice if you retry: a retry with the same key gets the first answer back instead of running again.

Test mode (dry run): nothing will change
Turns test mode off for this page only. It switches back when you leave the page.

Code and response

curl -X PUT 'https://mcp.wa-api.cloud/v1/templates/9120?dry_run=true' \
  -H "Authorization: Bearer $API_KEY" \
  -H 'Content-Type: application/json' \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{
  "template": {
    "name": "order_shipped",
    "language": "en_US",
    "category": "UTILITY",
    "body": {
      "text": "Hi {{1}}, good news: your order {{2}} has shipped.",
      "examples": [
        "Jane",
        "#1001"
      ]
    }
  }
}'

The code reads your key from $API_KEY.

Parameters

Parameters
FieldTypeWhat it is
template_idrequiredstring | integer · pathThe template id.Signed in? Pick one from your data with “My data”.

Body

Body fields
FieldTypeWhat it is
templaterequiredobjectThe new content. name and language must match the template's.
namerequiredstringTemplate name: lowercase letters, digits, underscores (e.g. order_shipped_v2).0–1000 characters
languagerequiredstringMeta language code, e.g. en, en_US, ar, hi, pt_BR.0–20 characters
categoryrequiredstringMARKETING | UTILITY | AUTHENTICATION.0–40 characters
headerobjectOptional header.
formatrequiredstringTEXT | IMAGE | VIDEO | DOCUMENT | LOCATION.one of: TEXT, IMAGE, VIDEO, DOCUMENT, LOCATION
textstringTEXT header: ≤ 60 chars, at most one {{1}}.0–1000 characters
examplestringTEXT header with {{1}}: its sample value.0–1000 characters
media_handlestringIMAGE/VIDEO/DOCUMENT header: the Meta upload handle used as the sample (POST /v1/templates/samples).0–4000 characters
bodyobjectBody.default {}
textstringBody text (≤ 1024 chars) with {{1}}, {{2}} … variables. Omit for AUTHENTICATION (Meta fixes it).0–5000 characters
examplesarray of stringOne sample per body variable, in order ({{1}} first).0–100 items
add_security_recommendationbooleanAUTHENTICATION only: append "For your security, do not share this code."
footerobjectOptional footer.
textstringFooter text (≤ 60 chars, no variables).0–1000 characters
code_expiration_minutesintegerAUTHENTICATION only: code expiry shown in the footer (1-90).-9007199254740991–9007199254740991
buttonsarray of objectButtons in display order (≤ 10).0–30 items
typerequiredstringQUICK_REPLY | URL | PHONE_NUMBER | COPY_CODE | FLOW | VOICE_CALL | OTP.one of: QUICK_REPLY, URL, PHONE_NUMBER, COPY_CODE, FLOW, VOICE_CALL, OTP
textstringButton label (≤ 25 chars). Not used for COPY_CODE.0–200 characters
urlstringURL buttons: https URL; for a dynamic URL end it with {{1}} (e.g. https://shop.example/track/{{1}}).0–4000 characters
url_examplestringDynamic URL buttons: a full example URL with the variable filled in.0–4000 characters
phone_numberstringPHONE_NUMBER buttons: E.164 number, e.g. +971501234567.0–64 characters
coupon_codestringCOPY_CODE buttons: the coupon code to copy (≤ 20 chars).0–64 characters
flow_idstringFLOW buttons: the WhatsApp flow id.0–64 characters
flow_actionstringFLOW buttons: NAVIGATE (default) or DATA_EXCHANGE for endpoint flows.one of: NAVIGATE, DATA_EXCHANGE
navigate_screenstringFLOW buttons with NAVIGATE: the first screen id.0–200 characters
otp_typestringOTP buttons: COPY_CODE (default), ONE_TAP or ZERO_TAP.one of: COPY_CODE, ONE_TAP, ZERO_TAP
supported_appsarray of objectONE_TAP / ZERO_TAP OTP buttons: your Android app(s).0–5 items
package_namerequiredstringAndroid package name.0–255 characters
signature_hashrequiredstringApp signing key hash.0–64 characters
limited_time_offerobjectLimited-time offer (MARKETING; needs a COPY_CODE button).
textrequiredstringOffer text shown on the chip (≤ 16 chars).0–200 characters
has_expirationbooleanShow a countdown (the expiry is set when sending).
carouselobjectMedia carousel (MARKETING): the body is the message above the cards; no top-level header, footer or buttons.
cardsrequiredarray of object2-10 cards.0–20 items
header_formatrequiredstringCard media type (the same on every card).one of: IMAGE, VIDEO
media_handlerequiredstringMeta upload handle for the card media (POST /v1/templates/samples).0–4000 characters
bodyobjectCard text.
buttonsrequiredarray of object1-2 buttons (QUICK_REPLY, URL, PHONE_NUMBER), the same layout on every card.0–5 items

Headers

Headers
FieldTypeWhat it is
AuthorizationrequiredheaderBearer $API_KEY — your API key.
Api-VersionheaderThe API version to use, e.g. 2026-10-01. Default: the version your key is pinned to.one of: 2026-10-01 · pattern ^\d{4}-\d{2}-\d{2}$
Idempotency-KeyheaderAny unique string (8–128 characters). A retry with the same key returns the first answer instead of running twice. Kept 24 hours.pattern ^[A-Za-z0-9._:-]+$ · 8–128 characters
Api-ConfirmrequiredheaderType the operation's verb (e.g. delete, submit) to confirm a change that cannot be undone or that WhatsApp or your customers see. Not needed with dry_run=true.

Response 200

Resubmitted for review.

Response fields
FieldTypeWhat it is
idrequiredstring
namerequiredstring
statusrequiredstring
lintrequiredobject
validrequiredbooleantrue when there are no errors (warnings may remain).
errorsrequirednumber
warningsrequirednumber
issuesrequiredarray of object
rulerequiredstring
severityrequiredstringone of: error, warning, info
pathrequiredstring
messagerequiredstring
fixrequiredstring
variablesrequiredobject
headerrequirednumber
bodyrequirednumber
previewrequiredstring or nullBody with samples filled in.
dry_runbooleantrue when this was a dry run: every check ran and nothing changed.

Errors

Errors are application/problem+json. Branch on code.

StatusCodeWhen
400invalid_input

A field is missing or has the wrong format. errors[] points at each field. The draft breaks a template rule (reason: template_rules), or its name, language or approved category differs from the template's.

401unauthenticated

The Authorization header is missing, the key is unknown, expired or revoked.

403entitlement_required

The workspace's plan does not include API access (api_access).

403insufficient_scope

The key does not have the permission this operation needs.

404not_found

No template with this id.

409conflict

The template is under review or otherwise not editable (reason: not_editable). Also returned while a request with the same Idempotency-Key is still running.

428confirm_required

Send the header Api-Confirm: submit to confirm. Not needed with dry_run=true.

429rate_limited

The key or workspace went over its rate limit. Wait for Retry-After seconds.

502upstream_error

WhatsApp refused the edit.

503upstream_unavailable

A service behind the API is briefly unavailable. Safe to retry with backoff.

504timeout

The change did not finish in time. Retry with the same Idempotency-Key: it never runs twice.

Examples

Change the body wording

Request body

{
  "template": {
    "name": "order_shipped",
    "language": "en_US",
    "category": "UTILITY",
    "body": {
      "text": "Hi {{1}}, good news: your order {{2}} has shipped.",
      "examples": [
        "Jane",
        "#1001"
      ]
    }
  }
}

Response 200

{
  "id": "9120",
  "name": "order_shipped",
  "status": "PENDING",
  "lint": {
    "valid": true,
    "errors": 0,
    "warnings": 0,
    "issues": [],
    "variables": {
      "header": 0,
      "body": 2
    },
    "preview": null
  }
}

Operation path

The same operation is also at POST /v1/ops/messaging_update_template, with every field in the JSON body.