PluginBench
Skill
Pass
Audit score 90

waba-template-author

sentdm/sent-plugin

Author, validate, and submit WhatsApp templates against Sent v3 contract with policy review.

What is waba-template-author?

Writes and validates WhatsApp message templates using Sent's v3 template definition format. Use this when building utility, marketing, authentication, or OTP templates for WhatsApp Business Account submission, including variable interpolation, button configuration, and Meta policy compliance checks.

  • Convert messaging intent into valid Sent v3 template POST requests with category classification (UTILITY, MARKETING, AUTHENTICATION)
  • Define and validate template variables with type-specific placeholders ({{id:type}}) and sample values for preview
  • Configure supported button types (QUICK_REPLY, URL, VOICE_CALL, PHONE_NUMBER, COPY_CODE) with per-type limits and validation
  • Handle channel-specific overrides for WhatsApp, SMS, and RCS with 1,024-character body limits
  • Validate authentication templates with security recommendations and code expiration (1–90 minutes)
  • Detect policy risks and explain template lifecycle states (DRAFT, PENDING, APPROVED, REJECTED, PAUSED)

How to install waba-template-author

npx skills add https://github.com/sentdm/sent-plugin --skill waba-template-author
Prerequisites
  • Sent v3 API access and authentication credentials
  • Python environment for running the lint_waba_template.py validation script
  • Understanding of WhatsApp Business Account (WABA) template categories and Meta approval process
Claude Code
Cursor
Windsurf
Cline

How to use waba-template-author

  1. 1.Collect the business event, recipient expectation, requested action, language, and sample values for your message
  2. 2.Choose a category: UTILITY for transactions, MARKETING for promotions, or AUTHENTICATION for verification codes
  3. 3.Define all variables with unique IDs, names, types, and realistic sample values using {{id:type}} placeholders
  4. 4.Add buttons (up to 10 total) with type-specific properties, respecting per-type limits (max 2 URL, 1 voice call, 1 phone, 1 copy-code)
  5. 5.For authentication templates, enable security recommendation and set code expiration (1–90 minutes)
  6. 6.Run the linter script to validate the request shape, variable alignment, character limits, and button configuration
  7. 7.Set sandbox: true and submit_for_review: false to test without side effects, then review the final payload before Meta submission

Use cases

Good for
  • Build a transactional order-update template with customer name and order number variables for UTILITY category
  • Create a marketing promotion template with URL buttons and review-ready payload for Meta submission
  • Author an OTP authentication template with copy-code button and security recommendation enabled
  • Validate and repair a rejected template by analyzing Meta feedback and adjusting variables or button configuration
  • Generate channel-specific overrides for the same template across WhatsApp, SMS, and RCS with consistent variable IDs
Who it's for
  • Backend engineers integrating WhatsApp messaging into applications
  • Product managers designing transactional and marketing message flows
  • Compliance teams reviewing templates for Meta policy adherence before submission
  • Customer support teams managing template rejections and resubmissions

waba-template-author FAQ

What is the difference between Sent's template request and Meta's Cloud API components[] format?

Sent uses a unified definition contract with multiChannel body, channel overrides, and variable objects with IDs and names. Meta's Cloud API uses a components[] array structure. The skill enforces Sent's shape; Meta examples must be clearly labelled non-Sent and never passed to the linter.

How do I handle variables across multiple channels (WhatsApp, SMS, RCS)?

Define variables in definition.body.multiChannel as the default. For channel-specific overrides (definition.body.whatsapp, definition.body.sms, definition.body.rcs), keep placeholder IDs and variable IDs aligned across all bodies. Each body is a complete override, not a fragment.

What happens if my template is rejected by Meta?

The webhook payload includes the rejection reason in the status field. Use the template-rejection-playbook reference to diagnose common issues (policy violations, variable misalignment, button limits). Adjust the template and resubmit without changing the template ID.

Can I mix quick-reply buttons with URL buttons in the same template?

Yes. Quick replies and calls-to-action (URL, voice call, phone, copy-code) may coexist. The total button count is capped at 10, with per-type limits: max 2 URL, 1 voice call, 1 phone, 1 copy-code, and the remainder as quick replies.

What is the sandbox parameter for?

Set sandbox: true to validate the template request without side effects or state changes. Use this during development and integration. When ready for Meta review, set sandbox: false and submit_for_review: true, but review the final payload first since submission changes external state.

Full instructions (SKILL.md)

Source of truth, from sentdm/sent-plugin.


name: waba-template-author description: Writes, classifies, validates, and repairs WhatsApp templates using the Sent v3 template definition contract. Use for utility, marketing, authentication, OTP, Meta review, rejected templates, variables, buttons, channel overrides, or submission-ready Sent payloads.

WhatsApp Template Author

Use this skill to turn a messaging intent into a valid body for POST /v3/templates, review it for WhatsApp policy risk, and explain the resulting lifecycle. Sent's template request is not Meta's Cloud API components[] shape.

Source precedence

When official sources disagree:

  1. Use the live Sent v3 OpenAPI for paths, request fields, and response shapes.
  2. Use the most specific current Sent guide for lifecycle and policy semantics.
  3. Preserve unknown provider values instead of forcing them into a closed enum.

The canonical references are the Sent template-definition guide, the v3 OpenAPI, and the webhook events reference. Do not use snapshot-era v2 examples.

Authoring workflow

1. Establish intent and category

Collect the business event, recipient expectation, requested action, language, channel overrides, and realistic sample values. Choose:

  • UTILITY for a specific non-promotional transaction, account, or service event.
  • MARKETING for promotions, offers, re-engagement, product discovery, or mixed promotional content.
  • AUTHENTICATION for one-time verification codes and supported authentication flows.

If content mixes utility and promotion, classify it as marketing or split it. See references/waba-template-categories.md.

2. Build the Sent create request

POST /v3/templates accepts these top-level fields:

FieldRequirement
definitionRequired. Contains header, body, footer, buttons, optional definitionVersion, and optional authenticationConfig.
categoryOptional: UTILITY, MARKETING, or AUTHENTICATION; omit for detection only when ambiguity is acceptable.
languageOptional locale such as en_US.
creation_sourceOptional source string; from-api is the documented default.
submit_for_reviewOptional Boolean; default false. Draft and validate before review.
sandboxOptional Boolean for validation without side effects.

Do not put name, channels, body, header, buttons, or components at the request root. name exists on update/response surfaces, not on the current create request.

{
  "category": "UTILITY",
  "language": "en_US",
  "definition": {
    "header": null,
    "body": {
      "multiChannel": {
        "type": "body",
        "template": "Hi {{0:variable}}, order {{1:variable}} has shipped.",
        "variables": [
          {
            "id": 0,
            "name": "customerName",
            "type": "variable",
            "props": {"sample": "Avery"}
          },
          {
            "id": 1,
            "name": "orderNumber",
            "type": "variable",
            "props": {"sample": "A-1042"}
          }
        ]
      },
      "sms": null,
      "whatsapp": null,
      "rcs": null
    },
    "footer": null,
    "buttons": null,
    "definitionVersion": "1.0",
    "authenticationConfig": null
  },
  "creation_source": "from-api",
  "submit_for_review": false,
  "sandbox": true
}

Use definition.body.multiChannel as the channel-neutral body. sms, whatsapp, and rcs are complete channel overrides, not fragments. Keep each body at or below 1,024 characters.

3. Define variables exactly

Use placeholders such as {{0:variable}}, {{1:link}}, or {{2:media}}. Each placeholder needs one matching definition with:

  • a unique non-negative integer id;
  • a readable name;
  • a matching type;
  • props.sample with realistic review and preview data.

Keep placeholder IDs and variable IDs aligned inside every body override. Never output naked {{1}} placeholders in a Sent request.

4. Add supported buttons

Sent currently recognizes QUICK_REPLY, URL, VOICE_CALL, PHONE_NUMBER, and COPY_CODE. Enforce:

  • 10 buttons total;
  • at most 2 URL buttons;
  • at most 1 voice-call button;
  • at most 1 phone-number button;
  • at most 1 copy-code button;
  • quick replies may use the remaining slots, up to the total of 10.

Buttons use id, type, and props. Labels are at most 25 characters. Require type-specific properties: quickReplyType; urlType and url; countryCode and phoneNumber; or offerCode. Quick replies and calls-to-action may coexist—do not invent an XOR rule.

5. Handle authentication templates

For AUTHENTICATION, use definition.authenticationConfig:

{
  "addSecurityRecommendation": true,
  "codeExpirationMinutes": 10
}

Expiration is 1–90 minutes. Keep authentication content to the verification purpose, use one code variable and the supported copy-code action, and do not add marketing language, unrelated links, media, or promotional buttons.

6. Validate before submission

Run:

python scripts/lint_waba_template.py template.json

The linter validates the Sent request shape, variables, the 1,024-character limit, channel overrides, every current button type, per-type limits, and authentication configuration. A Meta Cloud API example with components[] must fail with an explicit conversion error.

Use sandbox: true and submit_for_review: false while integrating. When the user is ready for provider review, show the final payload and explain that submission changes external state before proceeding.

7. Track the right lifecycle surface

Sent template resources use the known states DRAFT, PENDING, APPROVED, REJECTED, and PAUSED. Do not claim this is every value the API may ever return.

Template webhooks are WhatsApp approval events. They use field: "templates", omit sub_type and event, and carry the provider status in payload.status:

{
  "field": "templates",
  "timestamp": "2026-08-09T12:00:00Z",
  "payload": {
    "account_id": "00000000-0000-0000-0000-000000000000",
    "template_id": "11111111-1111-1111-1111-111111111111",
    "template_name": "order_update",
    "whatsapp_template_id": "2222222222222222",
    "status": "APPROVED",
    "language": "en_US",
    "category": "UTILITY",
    "channel": "whatsapp",
    "reason": null
  }
}

Common forwarded values include PENDING, APPROVED, REJECTED, and CATEGORY_UPDATED. Meta can also send values such as PAUSED or DISABLED. Persist the raw string, handle known values, and safely surface unknown ones. See references/template-rejection-playbook.md.

Boundaries

Use template-builder-ui for editor architecture and client-side validation UX. Use sent-templates to list, inspect, or delete existing templates through the connected Sent tools. Use waba-embedded-signup for WABA connection. Use rcs-agent-onboarding for current RCS launch capabilities.

Meta Cloud API payloads may appear in references/waba-template-examples.md, but every such example must be clearly labelled non-Sent and must never be passed to the Sent linter as a valid request.