Create Template

Submit a WhatsApp message template for Meta review. Sendiee runs strict validation locally before forwarding the request to Meta — you will get a structured 422 TEMPLATE_VALIDATION_FAILED for any preventable issue (sequential variables, missing examples, oversized headers, invalid button mix, etc.). This protects your WhatsApp Business Account quality score, which Meta degrades when templates are repeatedly rejected.

POST/v2.0/templates

Authentication

Bearer token + brandNumber. Your WABA must be in APPROVED review status — otherwise we return 409 WABA_NOT_REVIEWED without contacting Meta.

Request Parameters

Body Parameters — Common

ParameterTypeDescription
brandNumberstringYour WhatsApp Business phone number registered in Sendiee
namestringLowercase, max 512 chars, /^[a-z][a-z0-9_]*$/
languagestringLocale code (e.g. en_US, en_GB, hi, pt_BR)
categorystringMARKETING | UTILITY | AUTHENTICATION
ParameterTypeDescription
header.formatstringNONE | TEXT | IMAGE | VIDEO | DOCUMENT (default NONE)
header.textstringRequired for format=TEXT. Max 60 chars, no emoji, max 1 variable {{1}}
header.exampleVariablesstring[]Required when header.text contains {{1}}. Length must equal 1
header.mediaUrlstringFor IMAGE/VIDEO/DOCUMENT — public http(s) URL we download and resumable-upload to Meta on your behalf
header.mediaHandlestringAlternative to mediaUrl: a header_handle obtained from Meta's resumable upload API yourself
header.filenamestringRequired for format=DOCUMENT (e.g. invoice.pdf)

body (MARKETING / UTILITY only)

body

ParameterTypeDescription
body.textstringUp to 1024 chars. Variables must be sequential ({{1}}, {{2}} …) with no gaps
body.exampleVariablesstring[]One example per body variable (required when body has variables)
ParameterTypeDescription
footer.textstringMax 60 chars. No variables allowed

buttons (MARKETING / UTILITY, optional)

buttons[]

ParameterTypeDescription
buttons[].typestringQUICK_REPLY | URL | PHONE_NUMBER | COPY_CODE | WHATSAPP_CALL
buttons[].textstringMax 25 chars. Required for QUICK_REPLY / URL / PHONE_NUMBER / WHATSAPP_CALL
buttons[].urlstringRequired for type=URL. May contain {{1}} for dynamic suffix
buttons[].exampleUrlSuffixstringRequired when URL has a variable
buttons[].phone_numberstringE.164 international phone number, required for type=PHONE_NUMBER
buttons[].examplestringPromo code, required for type=COPY_CODE

auth (AUTHENTICATION only)

auth

ParameterTypeDescription
auth.otp_typestringCOPY_CODE | ONE_TAP | ZERO_TAP
auth.add_security_recommendationbooleanAppend the standard security tip line to the body
auth.code_expiration_minutesnumber1–90 minutes. Adds a code-expiry footer
auth.supported_appsobject[]Required for ONE_TAP / ZERO_TAP. Each entry: { package_name, signature_hash }
auth.zero_tap_terms_acceptedbooleanMust be true for ZERO_TAP

Code Examples

Marketing template with header media + body variables

curl -X POST https://api.sendiee.com/v2.0/templates \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "brandNumber": "917012345678",
    "name": "diwali_sale_2026",
    "language": "en_US",
    "category": "MARKETING",
    "header": {
      "format": "IMAGE",
      "mediaUrl": "https://cdn.acme.com/diwali-banner.png"
    },
    "body": {
      "text": "Hi {{1}}, get a flat 25% off on your favourite range. Use code {{2}} at checkout.",
      "exampleVariables": ["Surya", "DIWALI25"]
    },
    "footer": { "text": "Reply STOP to opt out" },
    "buttons": [
      { "type": "URL", "text": "Shop now", "url": "https://acme.com/sale" },
      { "type": "QUICK_REPLY", "text": "Talk to us" }
    ]
  }'

Authentication (OTP) template

cURL
curl -X POST https://api.sendiee.com/v2.0/templates \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "brandNumber": "917012345678",
    "name": "login_otp",
    "language": "en_US",
    "category": "AUTHENTICATION",
    "auth": {
      "otp_type": "COPY_CODE",
      "add_security_recommendation": true,
      "code_expiration_minutes": 10
    }
  }'

Response

{
  "success": true,
  "message": "Template submitted to Meta for review",
  "data": {
    "templateDbId": "664a...",
    "templateId": 1234567890,
    "name": "diwali_sale_2026",
    "language": "en_US",
    "category": "MARKETING",
    "status": "PENDING"
  }
}

Local validation failure (422)

{
  "error": true,
  "code": "TEMPLATE_VALIDATION_FAILED",
  "message": "One or more template fields failed validation",
  "details": [
    {
      "path": "name",
      "code": "NAME_INVALID",
      "message": "Name must start with a lowercase letter and contain only [a-z0-9_], max 512 chars"
    },
    {
      "path": "body.exampleVariables",
      "code": "BODY_EXAMPLES_MISSING",
      "message": "body.exampleVariables must contain exactly 2 entries (one per body variable)"
    }
  ]
}

Meta rejection (502)

{
  "error": true,
  "code": "META_REJECTED",
  "message": "Template name already exists",
  "details": {
    "metaErrorCode": 100,
    "metaErrorSubcode": 2388023,
    "metaMessage": "Invalid parameter",
    "metaUserTitle": "Template name already exists",
    "metaUserMsg": "A template with this name and language already exists.",
    "metaTraceId": "Aabcdef…"
  }
}

Try It

Try it — API Playground