Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 7 additions & 1 deletion plugins/kapso/skills/integrate-whatsapp/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -228,6 +228,12 @@ Send-time:
- URL buttons need a `button` component with `sub_type: "url"` and `index`
- Media headers use either `id` or `link` (never both)

Rejected at creation? Kapso forwards to Meta directly, so failures come back as Meta API
errors (often a bare Bad Request / `(#100)`). See the "Troubleshooting: why did my template
get rejected?" section in `references/templates-reference.md` for the cause → fix mapping
(example/variable mismatches, category restrictions, and OAuthException 139000 business
verification).

## WhatsApp Flows

Use Flows to build native WhatsApp forms. Read `references/whatsapp-flows-spec.md` before editing Flow JSON.
Expand Down Expand Up @@ -377,7 +383,7 @@ node scripts/openapi-explore.mjs --spec platform search "setup link"
- [references/webhooks-overview.md](references/webhooks-overview.md) - Webhook types, signature verification, retries
- [references/webhooks-event-types.md](references/webhooks-event-types.md) - Available events
- [references/webhooks-reference.md](references/webhooks-reference.md) - Webhook API and payload notes
- [references/templates-reference.md](references/templates-reference.md) - Template creation rules, components cheat sheet, send-time components
- [references/templates-reference.md](references/templates-reference.md) - Template creation rules, components cheat sheet, send-time components, rejection troubleshooting
- [references/whatsapp-api-reference.md](references/whatsapp-api-reference.md) - Meta proxy payloads for messages and conversations
- [references/whatsapp-cloud-api-js.md](references/whatsapp-cloud-api-js.md) - SDK usage for sending and reading messages
- [references/whatsapp-flows-spec.md](references/whatsapp-flows-spec.md) - Flow JSON spec
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,59 @@ If any variables appear in HEADER or BODY, you must include examples:
- POSITIONAL: `example.header_text` and 2D `example.body_text`.
- NAMED: `example.header_text_named_params` and `example.body_text_named_params`.

## Troubleshooting: why did my template get rejected?

Kapso forwards create/update calls straight to Meta, so a bad template comes back as a
Meta API error (often a bare **Bad Request** / `(#100)`) rather than a Kapso validation
message. Map the failure to a cause and fix before resubmitting.

### Bad Request (`(#100)`) at creation time — almost always example/variable mismatch

The most common wall: the template has variables but the `example` block doesn't line up
with them. Check, in order:

| Cause | How to spot it | Fix |
|-------|----------------|-----|
| Missing example for a HEADER/BODY variable | A `{{...}}` placeholder has no matching entry in `example` | Provide exactly one example per variable in every component that uses variables. See [Components cheat sheet](#components-cheat-sheet-creation-time). |
| Example keys don't match `parameter_format` | Using `example.body_text` (positional keys) while `parameter_format: NAMED`, or `example.body_text_named_params` while `POSITIONAL` | NAMED → `header_text_named_params` / `body_text_named_params`; POSITIONAL → `header_text` / 2D `body_text`. |
| NAMED example `param_name` doesn't match the placeholder | `{{order_id}}` in text but the example lists `param_name: "orderId"` (or a typo) | Make every `param_name` exactly equal the `{{...}}` name (lowercase + underscores). |
| Positional placeholders have gaps | Text uses `{{1}}` and `{{3}}` but not `{{2}}`, or examples don't cover every index | Positional variables must be sequential with no gaps, and `body_text` must supply one value per placeholder. |
| Example count doesn't match variable count | 2 variables but 1 example (or vice-versa) | The number of examples must equal the number of variables in that component. |

Positional body examples are a **2D array** (`[["ORDER-123", "Alex"]]`), not a flat one —
a flat array is a frequent Bad Request cause.

### Rejected for the wrong category

Categories aren't interchangeable; Meta rejects (or silently re-categorizes) templates
whose content doesn't fit:

| Category | Allowed content | Common rejection |
|----------|-----------------|-------------------|
| MARKETING | Promotions, offers, announcements | — |
| UTILITY | Transactional updates tied to an existing order/account | Promotional wording in a UTILITY template → rejected or bumped to MARKETING |
| AUTHENTICATION | OTP / verification only | Custom body text (body is **fixed by Meta**), or no OTP button; also **requires Meta business verification** (see below) |

If you need custom OTP wording, use **UTILITY** instead of AUTHENTICATION.

### OAuthException 139000 — WABA not verified

A `139000` (Integrity) error means the WhatsApp Business Account has not completed **Meta
business verification**. This blocks AUTHENTICATION templates and can block sending. Fix:
verify the business in Meta Security Center / Business Manager, then retry. This is the same
error surfaced when Flows integrity checks fail.

### Duplicate name / language

Creating a template whose `name` + `language` already exists returns an error. List existing
templates first (`node scripts/list-templates.mjs`) and pick a new name or update the
existing one via `hsm_id`.

### Button rejections

See [Button ordering rules](#buttons): don't interleave QUICK_REPLY with URL/PHONE_NUMBER,
and dynamic URL variables must sit at the end of the URL.

## Components cheat sheet (creation time)

### Header (TEXT, named)
Expand Down
4 changes: 4 additions & 0 deletions plugins/kapso/skills/observe-whatsapp/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,10 @@ Preferred path:
2. Run number health: `kapso whatsapp numbers health --phone-number "<display-number>" --output human`
3. Inspect related templates when relevant: `kapso whatsapp templates list --phone-number "<display-number>" --output json`

For **template creation failures** (Bad Request on `whatsapp_templates/new`, rejected or
recategorized templates, OAuthException 139000), see the "Template creation rejected" section
in `references/triage-reference.md`, which maps each Meta failure to a cause and fix.

Fallback path:
1. Message errors: `node scripts/errors.js`
2. API logs: `node scripts/api-logs.js`
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,3 +23,23 @@
1. Review external API call logs.
2. Filter by status code or endpoint.
3. Identify auth errors, rate limits, or upstream failures.

## Template creation rejected (Bad Request / Meta API error)

Kapso forwards template create/update calls straight to Meta, so rejections come back as
Meta API errors (often a bare **Bad Request** / `(#100)`), not Kapso validation messages.
Don't guess — map the failure to a cause:

1. **Bad Request at creation** — almost always an example/variable mismatch: a variable
with no example, example keys that don't match `parameter_format` (NAMED vs POSITIONAL),
a `param_name` that doesn't match the `{{...}}`, positional gaps, or a flat instead of 2D
`body_text` array.
2. **Wrong category** — promotional wording in a UTILITY template, or custom body text in an
AUTHENTICATION template (its body is fixed by Meta and it needs an OTP button).
3. **OAuthException 139000** — the WABA is not verified in Meta business verification; this
blocks AUTHENTICATION templates and can block sending.
4. **Duplicate name/language** — a template with that `name` + `language` already exists.

Full cause → fix mapping (with corrected example payloads) lives in the
`integrate-whatsapp` skill: `references/templates-reference.md` → "Troubleshooting: why did
my template get rejected?".
Loading