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
10 changes: 10 additions & 0 deletions plugins/kapso/skills/integrate-whatsapp/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -232,6 +232,16 @@ Send-time:

Use Flows to build native WhatsApp forms. Read `references/whatsapp-flows-spec.md` before editing Flow JSON.

### Prerequisite: a connected number

A Flow always belongs to a connected WhatsApp number, so confirm one exists **before** starting the builder:

```bash
node scripts/list-platform-phone-numbers.mjs
```

If the list is empty, do **not** proceed into the Flow builder with an empty number selection — that is a dead end. Route the user to connect a number first via embedded signup (`kapso setup`, or generate a setup link with `POST /platform/v1/customers/:id/setup_links`), then return to create the Flow. See `references/getting-started.md` and `references/setup-links.md`. `create-flow.js` enforces this: called without `--phone-number-id`, it lists the connected numbers to pick from, or tells you to connect one first when none exist.

### Create and publish a flow

1. Create flow: `node scripts/create-flow.js --phone-number-id <id> --name <name>`
Expand Down
53 changes: 52 additions & 1 deletion plugins/kapso/skills/integrate-whatsapp/scripts/create-flow.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,62 @@ const { parseArgs, getStringFlag, getBooleanFlag, readFlagJson } = require('./li
const { platformRequest } = require('./lib/http');
const { run } = require('./lib/run');

function summarizeNumbers(response) {
const configs = response?.data;
if (!Array.isArray(configs)) return [];
return configs.map((config) => ({
name: config.name,
display_phone_number: config.display_phone_number,
phone_number_id: config.phone_number_id || config.id,
business_account_id: config.business_account_id
}));
}

// A Flow always belongs to a connected WhatsApp number. When the caller did not
// pass one, look at what is actually connected so we never dead-end the way an
// empty "WhatsApp number" picker would: route to embedded signup if nothing is
// connected, or list the choices if some are.
async function resolvePhoneNumberGuidance() {
let numbers;
try {
const response = await platformRequest({
method: 'GET',
path: '/platform/v1/whatsapp/phone_numbers'
});
numbers = summarizeNumbers(response);
} catch {
// Listing failed (auth/network); fall back to the plain requirement.
throw new Error(
'Missing required flag --phone-number-id. Discover connected numbers with ' +
'`node scripts/list-platform-phone-numbers.mjs`; if none are connected, connect ' +
'a WhatsApp number first via embedded signup (`kapso setup`) before creating a Flow.'
);
}

if (numbers.length === 0) {
throw new Error(
'No WhatsApp numbers are connected, so a Flow cannot be created yet. ' +
'Connect a WhatsApp number first via embedded signup (`kapso setup`, or generate a ' +
'setup link with `POST /platform/v1/customers/:id/setup_links`), then re-run with ' +
'--phone-number-id <id>. See references/getting-started.md and references/setup-links.md.'
);
}

const choices = numbers
.map((n) => `${n.display_phone_number || n.name || 'number'} -> --phone-number-id ${n.phone_number_id}`)
.join('\n ');
throw new Error(
'Missing required flag --phone-number-id. Connected numbers:\n ' +
choices +
'\nRe-run create-flow.js with one of the phone_number_id values above.'
);
}

run(async () => {
const { flags } = parseArgs(process.argv.slice(2));
const phoneNumberId = getStringFlag(flags, 'phone-number-id') || getStringFlag(flags, 'phone_number_id');
if (!phoneNumberId) {
throw new Error('Missing required flag --phone-number-id');
await resolvePhoneNumberGuidance();
}

const name = getStringFlag(flags, 'name');
Expand Down
Loading