Agent-skills integrate-whatsapp
Connect WhatsApp to your product with Kapso: onboard customers with setup links, detect connections, receive events via webhooks, and send messages/templates/media. Also manage WhatsApp Flows (create/update/publish, data endpoints, encryption). Use when integrating WhatsApp end-to-end.
git clone https://github.com/gokapso/agent-skills
T=$(mktemp -d) && git clone --depth=1 https://github.com/gokapso/agent-skills "$T" && mkdir -p ~/.claude/skills && cp -r "$T/skills/integrate-whatsapp" ~/.claude/skills/gokapso-agent-skills-integrate-whatsapp && rm -rf "$T"
skills/integrate-whatsapp/SKILL.mdIntegrate WhatsApp
Setup
Preferred path:
- Kapso CLI installed and authenticated (
)kapso login - Use
to confirm project access before onboarding or messagingkapso status
Fallback path: Env vars:
(host only, noKAPSO_API_BASE_URL
)/platform/v1KAPSO_API_KEY
(optional, defaultMETA_GRAPH_VERSION
)v24.0
Auth header (direct API calls):
X-API-Key: <api_key>
Install deps (once):
npm i
Connect WhatsApp (setup links)
Preferred onboarding path (CLI):
- Start onboarding:
kapso setup - If setup is blocked, resolve context with:
kapso projects listkapso projects use <project-id>kapso customers listkapso customers new --name "<customer-name>" --external-id <external-id>kapso setup --customer <customer-id>
- Complete the hosted onboarding URL
- Confirm connected numbers:
kapso whatsapp numbers list --output json - Resolve the exact number you want to operate:
kapso whatsapp numbers resolve --phone-number "<display-number>" --output json
Fallback onboarding flow (direct API):
- Create customer:
POST /platform/v1/customers - Generate setup link:
POST /platform/v1/customers/:id/setup_links - Customer completes embedded signup
- Use
to send messages and configure webhooksphone_number_id
Detect connection:
- Project webhook
(recommended)whatsapp.phone_number.created - Success redirect URL query params (use for frontend UX)
Recommended Kapso setup-link defaults:
{ "setup_link": { "allowed_connection_types": ["dedicated"], "provision_phone_number": true, "phone_number_country_isos": ["US"] } }
Notes:
-
andkapso setup
use dedicated plus provisioning by default.kapso whatsapp numbers new -
Keep
,phone_number_country_isos
,phone_number_area_code
, and redirect URLs as optional overrides.language -
Platform API base:
/platform/v1 -
Meta proxy base:
(messaging, templates, media)/meta/whatsapp/v24.0 -
Use
as the primary WhatsApp identifierphone_number_id
Receive events (webhooks)
Use webhooks to receive:
- Project events (connection lifecycle, workflow events)
- Phone-number events (messages, conversations, delivery status)
Scope rules:
- Project webhooks: only project-level events (connection lifecycle, workflow events)
- Phone-number webhooks: only WhatsApp message + conversation events for that
phone_number_id - WhatsApp message/conversation events (
,whatsapp.message.*
) are phone-number onlywhatsapp.conversation.*
Create a webhook:
- Project-level:
node scripts/create.js --scope project --url <https://...> --events <csv> - Phone-number:
node scripts/create.js --phone-number-id <id> --url <https://...> --events <csv>
Common flags for create/update:
- webhook destination--url <https://...>
- event types (Kapso webhooks)--events <csv|json-array>
- Kapso (event-based) vs raw Meta forwarding--kind <kapso|meta>
- payload format (--payload-version <v1|v2>
recommended)v2
- enable buffering for--buffer-enabled <true|false>whatsapp.message.received
- 1-60 seconds--buffer-window-seconds <n>
- 1-100--max-buffer-size <n>
- enable/disable--active <true|false>
Test delivery:
node scripts/test.js --webhook-id <id>
Always verify signatures. See:
references/webhooks-overview.mdreferences/webhooks-reference.md
Send and read messages
Discover IDs first
Two Meta IDs are needed for different operations:
| ID | Used for | How to discover |
|---|---|---|
(WABA) | Template CRUD | or |
| Sending messages, media upload | or |
Operate with the CLI first
Common commands:
kapso whatsapp numbers list --output json kapso whatsapp numbers resolve --phone-number "<display-number>" --output json kapso whatsapp messages send --phone-number-id <PHONE_NUMBER_ID> --to <wa-id> --text "Hello from Kapso" kapso whatsapp messages list --phone-number-id <PHONE_NUMBER_ID> --limit 50 --output json kapso whatsapp messages get <MESSAGE_ID> --phone-number-id <PHONE_NUMBER_ID> --output json kapso whatsapp conversations list --phone-number-id <PHONE_NUMBER_ID> --output json kapso whatsapp templates list --phone-number-id <PHONE_NUMBER_ID> --output json kapso whatsapp templates get <TEMPLATE_ID> --phone-number-id <PHONE_NUMBER_ID> --output json
SDK setup
Install:
npm install @kapso/whatsapp-cloud-api
Create client:
import { WhatsAppClient } from "@kapso/whatsapp-cloud-api"; const client = new WhatsAppClient({ baseUrl: "https://api.kapso.ai/meta/whatsapp", kapsoApiKey: process.env.KAPSO_API_KEY! });
Send a text message
Via SDK:
await client.messages.sendText({ phoneNumberId: "<PHONE_NUMBER_ID>", to: "+15551234567", body: "Hello from Kapso" });
Send a template message
- Discover IDs:
node scripts/list-platform-phone-numbers.mjs - Draft template payload from
assets/template-utility-order-status-update.json - Create:
node scripts/create-template.mjs --business-account-id <WABA_ID> --file <payload.json> - Check status:
node scripts/template-status.mjs --business-account-id <WABA_ID> --name <name> - Send:
node scripts/send-template.mjs --phone-number-id <ID> --file <send-payload.json>
Send an interactive message
Interactive messages require an active 24-hour session window. For outbound notifications outside the window, use templates.
- Discover
phone_number_id - Pick payload from
assets/send-interactive-*.json - Send:
node scripts/send-interactive.mjs --phone-number-id <ID> --file <payload.json>
Read inbox data
Preferred path:
- CLI:
,kapso whatsapp messages ...
,kapso whatsapp conversations ...kapso whatsapp templates ...
Fallback path:
- Proxy:
,GET /{phone_number_id}/messagesGET /{phone_number_id}/conversations - SDK:
,client.messages.query()
,client.messages.get()
,client.conversations.list()
,client.conversations.get()client.templates.get()
Template rules
Creation:
- Use
withparameter_format: "NAMED"
(preferred over positional){{param_name}} - Include examples when using variables in HEADER/BODY
- Use
(notlanguage
)language_code - Don't interleave QUICK_REPLY with URL/PHONE_NUMBER buttons
- URL button variables must be at the end of the URL and use positional
{{1}}
Send-time:
- For NAMED templates, include
in header/body paramsparameter_name - URL buttons need a
component withbutton
andsub_type: "url"index - Media headers use either
orid
(never both)link
WhatsApp Flows
Use Flows to build native WhatsApp forms. Read
references/whatsapp-flows-spec.md before editing Flow JSON.
Create and publish a flow
- Create flow:
node scripts/create-flow.js --phone-number-id <id> --name <name> - Update JSON:
node scripts/update-flow-json.js --flow-id <id> --json-file <path> - Publish:
node scripts/publish-flow.js --flow-id <id> - Test:
node scripts/send-test-flow.js --phone-number-id <id> --flow-id <id> --to <phone>
Attach a data endpoint (dynamic flows)
- Set up encryption:
node scripts/setup-encryption.js --flow-id <id> - Create endpoint:
node scripts/set-data-endpoint.js --flow-id <id> --code-file <path> - Deploy:
node scripts/deploy-data-endpoint.js --flow-id <id> - Register:
node scripts/register-data-endpoint.js --flow-id <id>
Flow JSON rules
Static flows (no data endpoint):
- Use
version: "7.3"
androuting_model
are optionaldata_api_version- See
assets/sample-flow.json
Dynamic flows (with data endpoint):
- Use
withversion: "7.3"data_api_version: "3.0"
is required (defines valid screen transitions)routing_model- See
assets/dynamic-flow.json
Data endpoint rules
Handler signature:
async function handler(request, env) { const body = await request.json(); // body.data_exchange.action: INIT | data_exchange | BACK // body.data_exchange.screen: current screen id // body.data_exchange.data: user inputs return Response.json({ version: "3.0", screen: "NEXT_SCREEN_ID", data: { } }); }
- Do not use
orexportmodule.exports - Completion uses
withscreen: "SUCCESS"extension_message_response.params - Do not include
orendpoint_uri
(Kapso injects these)data_channel_uri
Troubleshooting
- Preview shows
: flow is dynamic without a data endpoint. Attach one and refresh."flow_token is missing" - Encryption setup errors: enable encryption in Settings for the phone number/WABA.
- OAuthException 139000 (Integrity): WABA must be verified in Meta security center.
Scripts
Webhooks
| Script | Purpose |
|---|---|
| List webhooks |
| Get webhook details |
| Create a webhook |
| Update a webhook |
| Delete a webhook |
| Send a test event |
Messaging and templates
| Script | Purpose | Required ID |
|---|---|---|
| Discover business_account_id + phone_number_id | — |
| List WABA phone numbers | business_account_id |
| List templates (with filters) | business_account_id |
| Check single template status | business_account_id |
| Create a template | business_account_id |
| Update existing template | business_account_id |
| Send template message | phone_number_id |
| Send interactive message | phone_number_id |
| Upload media for send-time headers | phone_number_id |
Flows
| Script | Purpose |
|---|---|
| List all flows |
| Create a new flow |
| Get flow details |
| Read flow JSON |
| Update flow JSON (creates new version) |
| Publish a flow |
| Get data endpoint config |
| Create/update data endpoint code |
| Deploy data endpoint |
| Register data endpoint with Meta |
| Check encryption status |
| Set up flow encryption |
| Send a test flow message |
| Delete a flow |
| List stored flow responses |
| List function logs |
| List function invocations |
OpenAPI
| Script | Purpose |
|---|---|
| Explore OpenAPI (search/op/schema/where) |
Examples:
node scripts/openapi-explore.mjs --spec whatsapp search "template" node scripts/openapi-explore.mjs --spec whatsapp op sendMessage node scripts/openapi-explore.mjs --spec whatsapp schema TemplateMessage node scripts/openapi-explore.mjs --spec platform ops --tag "WhatsApp Flows" node scripts/openapi-explore.mjs --spec platform op setupWhatsappFlowEncryption node scripts/openapi-explore.mjs --spec platform search "setup link"
Assets
| File | Description |
|---|---|
| UTILITY template with named params + URL button |
| Send-time payload for order_status_update |
| UTILITY template showing button ordering rules |
| MARKETING template with IMAGE header |
| AUTHENTICATION OTP template (COPY_CODE) |
| Interactive button message |
| Interactive list message |
| Interactive CTA URL message |
| Location request message |
| Catalog message |
| Static flow example (no endpoint) |
| Dynamic flow example (with endpoint) |
| Webhook create/update payload example |
References
- references/getting-started.md - Platform onboarding
- references/platform-api-reference.md - Full endpoint reference
- references/setup-links.md - Setup link configuration
- references/detecting-whatsapp-connection.md - Connection detection methods
- references/webhooks-overview.md - Webhook types, signature verification, retries
- references/webhooks-event-types.md - Available events
- references/webhooks-reference.md - Webhook API and payload notes
- references/templates-reference.md - Template creation rules, components cheat sheet, send-time components
- references/whatsapp-api-reference.md - Meta proxy payloads for messages and conversations
- references/whatsapp-cloud-api-js.md - SDK usage for sending and reading messages
- references/whatsapp-flows-spec.md - Flow JSON spec
Related skills
- Workflows, agents, and automationsautomate-whatsapp
- Debugging, logs, health checksobserve-whatsapp
<!-- FILEMAP:END -->[integrate-whatsapp file map]|root: . |.:{package.json,SKILL.md} |assets:{dynamic-flow.json,sample-flow.json,send-interactive-buttons.json,send-interactive-catalog-message.json,send-interactive-cta-url.json,send-interactive-list.json,send-interactive-location-request.json,send-template-order-status-update.json,template-authentication-otp.json,template-marketing-media-header.json,template-utility-named.json,template-utility-order-status-update.json,webhooks-example.json} |references:{detecting-whatsapp-connection.md,getting-started.md,platform-api-reference.md,setup-links.md,templates-reference.md,webhooks-event-types.md,webhooks-overview.md,webhooks-reference.md,whatsapp-api-reference.md,whatsapp-cloud-api-js.md,whatsapp-flows-spec.md} |scripts:{create-flow.js,create-function.js,create-template.mjs,create.js,delete-flow.js,delete.js,deploy-data-endpoint.js,deploy-function.js,get-data-endpoint.js,get-encryption-status.js,get-flow.js,get-function.js,get.js,list-connected-numbers.mjs,list-flow-responses.js,list-flows.js,list-function-invocations.js,list-function-logs.js,list-platform-phone-numbers.mjs,list-templates.mjs,list.js,openapi-explore.mjs,publish-flow.js,read-flow-json.js,register-data-endpoint.js,send-interactive.mjs,send-template.mjs,send-test-flow.js,set-data-endpoint.js,setup-encryption.js,submit-template.mjs,template-status.mjs,test.js,update-flow-json.js,update-function.js,update-template.mjs,update.js,upload-media.mjs,upload-template-header-handle.mjs} |scripts/lib:{args.mjs,cli.js,env.js,env.mjs,http.js,output.js,output.mjs,request.mjs,run.js,whatsapp-flow.js} |scripts/lib/webhooks:{args.js,kapso-api.js,webhook.js}