@funnelchat-hq/sdk 0.3.1 → 0.3.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +19 -10
- package/dist/index.cjs +28 -3
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +125 -12
- package/dist/index.d.ts +125 -12
- package/dist/index.js +28 -3
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -88,10 +88,10 @@ if (event.type === 'message.received') {
|
|
|
88
88
|
|
|
89
89
|
## Groups
|
|
90
90
|
|
|
91
|
-
|
|
91
|
+
Start from the groups your number is in, read live from WhatsApp, and write to one by its `uid`:
|
|
92
92
|
|
|
93
93
|
```ts
|
|
94
|
-
for await (const group of funnelchat.groups.
|
|
94
|
+
for await (const group of funnelchat.groups.listByDevice(device.id)) {
|
|
95
95
|
console.log(group.uid, group.name); // '120363000000000001@g.us', 'Customers'
|
|
96
96
|
}
|
|
97
97
|
|
|
@@ -102,9 +102,18 @@ const { action_id } = await funnelchat.groups.sendMessage('120363000000000001@g.
|
|
|
102
102
|
});
|
|
103
103
|
```
|
|
104
104
|
|
|
105
|
+
To learn who joins and leaves a group, follow it once:
|
|
106
|
+
|
|
107
|
+
```ts
|
|
108
|
+
const { data: followed } = await funnelchat.groups.follow('120363000000000001@g.us', { device_id: device.id });
|
|
109
|
+
console.log(followed.imported, followed.is_admin); // true, true
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
- The live list is reused for a minute per number, so a group just created in WhatsApp can take that long to show. A group already in your account brings `device_id`; `funnelchat.groups.list()` lists those.
|
|
113
|
+
- Writing to a group that is not in your account follows it first, with the same rules: a number that is not admin of the group answers `422 device_not_group_admin` and nothing is imported. Following needs **Groups and campaigns → Manage groups** (`403 import_permission_required`), takes up to 5 groups per number per minute (`429 import_rate_limited`, with `retryAfter`) and works with QR numbers only (`422 provider_unsupported` with an official one). `followed.imported` is `false` when the group was already in your account.
|
|
105
114
|
- The message goes out in the background: `group_action.completed` (with `action.uuid` equal to `action_id`) or `funnelchat.groups.retrieveAction(action_id)` tell you how it went. A file goes as `type: 'image'` (or `video`, `audio`, `document`) with its `https` `media_url`.
|
|
106
|
-
- Who joins or leaves arrives by `group_participant.joined` and `group_participant.left`: `group`, `participant` (`identity`, `identity_type`, `name`) and `campaign`, `null` for a group without a campaign.
|
|
107
|
-
- Permissions: **Groups and campaigns → View** to read and **Groups and campaigns →
|
|
115
|
+
- Who joins or leaves a followed group arrives by `group_participant.joined` and `group_participant.left`: `group`, `participant` (`identity`, `identity_type`, `name`) and `campaign`, `null` for a group without a campaign.
|
|
116
|
+
- Permissions: **Groups and campaigns → View** to read, **Groups and campaigns → Send** to send and **Groups and campaigns → Manage groups** to follow.
|
|
108
117
|
|
|
109
118
|
## Workspaces
|
|
110
119
|
|
|
@@ -146,7 +155,7 @@ CommonJS: `const { Funnelchat } = require('@funnelchat-hq/sdk');`. Every request
|
|
|
146
155
|
| `funnelchat.contacts` | `list`, `create`, `upsert`, `retrieve`, `update`, `delete`, the tags and fields of a contact, `metaWindow` (the 24-hour window), notes. |
|
|
147
156
|
| `funnelchat.messages` | `send`, `sendDirect`, `sendForm`, `sendContactCard`, `forward`, `get` (one message by id), `list` (the history of a contact), `react`, `removeReaction`. |
|
|
148
157
|
| `funnelchat.templates` | `list`, `create`, `retrieve`, `update`, `quickReplyButtons`, `send`, `delete`. |
|
|
149
|
-
| `funnelchat.groups` | `
|
|
158
|
+
| `funnelchat.groups` | `listByDevice` (a number's live groups), `follow`, `list`, `retrieve`, participants and their joins and leaves, messages, `sendMessage` and `retrieveAction`. |
|
|
150
159
|
| `funnelchat.webhooks` | Subscriptions (`list`, `create`, `retrieve`, `update`, `delete`, `test`, `listDeliveries`), the catalog (`events`), `verify` and `constructEvent`. |
|
|
151
160
|
| `funnelchat.conversations` | `list`, `update`, counters, mark everything as read or unread. |
|
|
152
161
|
| `funnelchat.forms` | WhatsApp forms: `list`, `templates`, `create`, `retrieve`, `update`, `delete`, `createVersion`, `sync`, `publish`, numbers, `versions`, answers and `metrics`. |
|
|
@@ -166,7 +175,8 @@ A key has the permissions ticked when it was created. The panel groups them by a
|
|
|
166
175
|
| Create contacts | **Contacts and conversations → Edit** |
|
|
167
176
|
| Send messages and templates | **Contacts and conversations → Send** |
|
|
168
177
|
| Read groups | **Groups and campaigns → View** |
|
|
169
|
-
| Send to a group | **Groups and campaigns → Send** |
|
|
178
|
+
| Send to a group | **Groups and campaigns → Send** (and **Groups and campaigns → Manage groups** for one not in the account yet) |
|
|
179
|
+
| Follow a group | **Groups and campaigns → Manage groups** |
|
|
170
180
|
| Webhook subscriptions | **Notifications (webhooks) → View** to read, **Notifications (webhooks) → Manage** for the rest, plus **View** of the area of each event |
|
|
171
181
|
|
|
172
182
|
### Send a message
|
|
@@ -524,12 +534,11 @@ const funnelchat = new Funnelchat({ apiKey: '1|fc_live_sandbox', baseUrl: 'http:
|
|
|
524
534
|
|
|
525
535
|
### Pending of the spec
|
|
526
536
|
|
|
527
|
-
The types come from the full unified spec of the developer portal (`spec/funnelchat.json`; where it came from, in `spec/procedencia.json`: developers-portal
|
|
537
|
+
The types come from the full unified spec of the developer portal (`spec/funnelchat.json`; where it came from, in `spec/procedencia.json`: developers-portal 99928866 of 05-11-2026, with the areas at accounts v1.5.97, conversations v1.19.21 and communities v2.35.7). What production has and that spec does not describe, or describes otherwise than production answers, lives in a separate layer, `spec/pending.json`, which generation applies **only while the spec does not bring it**, or still says exactly what the entry corrects; each entry cites the production code it was read in:
|
|
528
538
|
|
|
529
|
-
-
|
|
530
|
-
- the events of the account (`device.*`, billing, subscriptions, monthly active contacts) and some of groups (`group.message_received`, `group.reaction_added`, `group.full`, `group_action.failed`, the join requests): the API publishes them in its catalog (`webhooks.events()`), not in the spec;
|
|
539
|
+
- the events of the account (`device.*`, billing, subscriptions, monthly active contacts) and some of groups (`group.message_received`, `group.reaction_added`, `group.full`, `group_action.completed` and `.failed`, the join requests): the API publishes them in its catalog (`webhooks.events()`), not in the spec;
|
|
531
540
|
- WhatsApp forms (except sending one) and `webhooks.rotateSecret`;
|
|
532
|
-
- where the spec contradicts production: what a send answers (`{ message }`, never `null`), the body of `devices.qr`, the items of `templates.list`, the answer of `webhooks.update`, and the events the spec only shows by one example (`message.received`, `message.status_changed`, `whatsapp_form.completed`, `group_participant.joined` and `.left`).
|
|
541
|
+
- where the spec contradicts production: what a send answers (`{ message }`, never `null`), the body of `devices.qr`, the items of `templates.list`, the answer of `webhooks.update` and of `groups.retrieveAction`, and the events the spec only shows by one example (`message.received`, `message.status_changed`, `whatsapp_form.completed`, `group_participant.joined` and `.left`).
|
|
533
542
|
|
|
534
543
|
`src/pending/` has what is not OpenAPI (the `workspace_id` of every event) and `src/core/error-codes.ts` the error codes.
|
|
535
544
|
|
package/dist/index.cjs
CHANGED
|
@@ -388,7 +388,13 @@ var GROUP_ACTION_ERROR_CODES = {
|
|
|
388
388
|
/** 422: that `type` cannot be sent to this group by this number. */
|
|
389
389
|
unsupported_type: 422,
|
|
390
390
|
/** 429: the number has 50 group actions open. Wait for some to finish; not worth retrying. */
|
|
391
|
-
too_many_pending_actions: 429
|
|
391
|
+
too_many_pending_actions: 429,
|
|
392
|
+
/** 403: following a group (also by writing to one not in the account) needs **Groups and campaigns → Manage groups**. */
|
|
393
|
+
import_permission_required: 403,
|
|
394
|
+
/** 429, with `Retry-After`: the number already followed 5 groups this minute. */
|
|
395
|
+
import_rate_limited: 429,
|
|
396
|
+
/** 409: another call is following the same group right now. */
|
|
397
|
+
import_in_progress: 409
|
|
392
398
|
};
|
|
393
399
|
var IDEMPOTENCY_ERROR_CODES = {
|
|
394
400
|
/** 422: the key was already used with another body. Use a new key for a new resource. */
|
|
@@ -600,6 +606,7 @@ var routes = [
|
|
|
600
606
|
{ "method": "POST", "path": "/api/v1/groups/{group}/admins", "operationId": "apiGroupAction.promoteAdmins", "domain": "communities", "permission": "communities:operate", "tag": "Acciones de grupo", "summary": "Promueve tel\xE9fonos a administrador", "pending": false },
|
|
601
607
|
{ "method": "POST", "path": "/api/v1/groups/{group}/admins/remove", "operationId": "apiGroupAction.demoteAdmins", "domain": "communities", "permission": "communities:operate", "tag": "Acciones de grupo", "summary": "Quita el rol de administrador a tel\xE9fonos", "pending": false },
|
|
602
608
|
{ "method": "PUT", "path": "/api/v1/groups/{group}/description", "operationId": "apiGroupAction.updateDescription", "domain": "communities", "permission": "communities:operate", "tag": "Acciones de grupo", "summary": "Cambia la descripci\xF3n del grupo", "pending": false },
|
|
609
|
+
{ "method": "POST", "path": "/api/v1/groups/{group}/import", "operationId": "v2.apiGroupImport", "domain": "communities", "permission": "communities:operate", "tag": "Grupos", "summary": "Importar un grupo de un n\xFAmero", "pending": false },
|
|
603
610
|
{ "method": "GET", "path": "/api/v1/groups/{group}/invite-link/live", "operationId": "apiGroupAction.inviteLink", "domain": "communities", "permission": "communities:read", "tag": "Acciones de grupo", "summary": "Link de invitaci\xF3n vigente del grupo", "pending": false },
|
|
604
611
|
{ "method": "POST", "path": "/api/v1/groups/{group}/invite-link/renew", "operationId": "apiGroupAction.renewInviteLink", "domain": "communities", "permission": "communities:operate", "tag": "Acciones de grupo", "summary": "Renueva el link de invitaci\xF3n del grupo", "pending": false },
|
|
605
612
|
{ "method": "GET", "path": "/api/v1/groups/{group}/join-requests", "operationId": "apiGroupAction.joinRequests", "domain": "communities", "permission": "communities:read", "tag": "Acciones de grupo", "summary": "Solicitudes pendientes para unirse al grupo", "pending": false },
|
|
@@ -1132,7 +1139,11 @@ var Groups = class extends Resource {
|
|
|
1132
1139
|
retrieve(group, options) {
|
|
1133
1140
|
return this.client.request("GET", "/api/v1/groups/{group}", { ...options, path: { group } });
|
|
1134
1141
|
}
|
|
1135
|
-
/**
|
|
1142
|
+
/**
|
|
1143
|
+
* `GET /api/v1/devices/{device}/groups`, paginated (`page`, `pageSize`): the groups of one number,
|
|
1144
|
+
* read live from WhatsApp (for a key, reused for a minute per number). A group that is already in
|
|
1145
|
+
* the account brings `device_id`; any other can be followed with {@link Groups.follow}.
|
|
1146
|
+
*/
|
|
1136
1147
|
listByDevice(device, query, options) {
|
|
1137
1148
|
return this.client.paginate("/api/v1/devices/{device}/groups", { ...options, path: { device }, query });
|
|
1138
1149
|
}
|
|
@@ -1175,6 +1186,20 @@ var Groups = class extends Resource {
|
|
|
1175
1186
|
sendMessage(group, body, options) {
|
|
1176
1187
|
return this.client.request("POST", "/api/v1/groups/{group}/messages", { ...options, path: { group }, body });
|
|
1177
1188
|
}
|
|
1189
|
+
/**
|
|
1190
|
+
* `POST /api/v1/groups/{group}/import`: follows a WhatsApp group of a QR number (`device_id`), as
|
|
1191
|
+
* importing it in the panel does: from then on its joins and leaves arrive by
|
|
1192
|
+
* `group_participant.joined` and `group_participant.left`. Resolves to `{ data: { uid, name,
|
|
1193
|
+
* imported, is_admin } }`: `imported` is `false` when the group was already in the account, and
|
|
1194
|
+
* `is_admin` says whether the number administers it (without that it cannot write to it). Needs
|
|
1195
|
+
* **Groups and campaigns → Manage groups** (`403 import_permission_required`); up to 5 groups
|
|
1196
|
+
* per number per minute (`429 import_rate_limited`, with `retryAfter`); an official number is
|
|
1197
|
+
* `422 provider_unsupported`. {@link Groups.sendMessage} follows the group itself when it is not in
|
|
1198
|
+
* the account yet.
|
|
1199
|
+
*/
|
|
1200
|
+
follow(group, body, options) {
|
|
1201
|
+
return this.client.request("POST", "/api/v1/groups/{group}/import", { ...options, path: { group }, body });
|
|
1202
|
+
}
|
|
1178
1203
|
/**
|
|
1179
1204
|
* `GET /api/v1/groups/actions/{action}`: where a group action, such as a message sent with
|
|
1180
1205
|
* {@link Groups.sendMessage}, is (`queued`, `running`, `completed` or `failed`) and its `result`.
|
|
@@ -1462,7 +1487,7 @@ var Webhooks = class extends Resource {
|
|
|
1462
1487
|
};
|
|
1463
1488
|
|
|
1464
1489
|
// src/version.ts
|
|
1465
|
-
var VERSION = "0.3.
|
|
1490
|
+
var VERSION = "0.3.2";
|
|
1466
1491
|
|
|
1467
1492
|
// src/client.ts
|
|
1468
1493
|
var BASE_URLS = {
|