kommo-aiatende-api 1.2.4 → 1.2.6

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 CHANGED
@@ -1,636 +1,637 @@
1
- # kommo-aiatende-api
2
-
3
- SDK não oficial, moderno e **totalmente tipado** em TypeScript para a API V4 da [Kommo CRM](https://kommo.com). Cobre todos os recursos documentados, normaliza inconsistências da API e oferece validações locais (pre-flight) para evitar erros HTTP desnecessários.
4
-
5
- ---
6
-
7
- ## 📦 Instalação
8
-
9
- ```bash
10
- npm install kommo-aiatende-api
11
- # ou
12
- yarn add kommo-aiatende-api
13
- # ou
14
- pnpm add kommo-aiatende-api
15
- ```
16
-
17
- ---
18
-
19
- ## 🚀 Inicialização
20
-
21
- ```typescript
22
- import { KommoClient } from 'kommo-aiatende-api';
23
-
24
- const client = new KommoClient({
25
- domain: 'meusubdominio', // apenas o subdomínio, sem ".kommo.com"
26
- accessToken: 'SEU_ACCESS_TOKEN',
27
- });
28
-
29
- // Atualizar o token dinamicamente (ex: após refresh OAuth)
30
- client.setAccessToken('NOVO_TOKEN');
31
- ```
32
-
33
- > **Nota:** A biblioteca não gerencia o fluxo OAuth. Você deve implementar a renovação de tokens na sua infraestrutura.
34
-
35
- ---
36
-
37
- ## 🛡️ Tratamento de Erros
38
-
39
- Todos os erros HTTP são convertidos em `KommoApiError`:
40
-
41
- ```typescript
42
- import { KommoApiError } from 'kommo-aiatende-api';
43
-
44
- try {
45
- await client.leads.getById(999999);
46
- } catch (err) {
47
- if (err instanceof KommoApiError) {
48
- console.log(err.status); // número HTTP (ex: 404)
49
- console.log(err.title); // título do erro
50
- console.log(err.detail); // detalhe técnico
51
- console.log(err.raw); // corpo bruto da resposta
52
- }
53
- }
54
- ```
55
-
56
- ---
57
-
58
- ## 📋 Referência Completa da API
59
-
60
- ### `client.account`
61
-
62
- Parâmetros e configurações da conta Kommo.
63
-
64
- | Método | Descrição |
65
- |--------|-----------|
66
- | `get(params?)` | Retorna informações da conta |
67
-
68
- **Parâmetros `with` disponíveis:**
69
-
70
- | Valor | Descrição |
71
- |-------|-----------|
72
- | `amojo_id` | ID da conta no serviço de chat |
73
- | `amojo_rights` | Direitos de chat (grupos e diretos) |
74
- | `users_groups` | Grupos de usuários da conta |
75
- | `task_types` | Tipos de tarefas configurados |
76
- | `version` | Versão atual da Kommo |
77
- | `entity_names` | Nomes de entidades com traduções |
78
- | `datetime_settings` | Configurações de data/hora |
79
- | `drive_url` | URL base do serviço de arquivos (Files API) |
80
-
81
- ```typescript
82
- const account = await client.account.get({
83
- with: ['amojo_id', 'drive_url', 'version'],
84
- });
85
-
86
- console.log(account.name);
87
- console.log(account.subdomain);
88
- console.log(account.amojo_id);
89
- console.log(account._embedded?.drive_url);
90
- ```
91
-
92
- ---
93
-
94
- ### `client.leads`
95
-
96
- | Método | Descrição |
97
- |--------|-----------|
98
- | `list(params?)` | Lista leads com filtros e paginação |
99
- | `getById(id, params?)` | Retorna um lead por ID (ou `null` se não encontrado) |
100
- | `create(items)` | Cria um ou mais leads |
101
- | `update(items)` | Atualiza leads em lote |
102
- | `updateOne(id, payload)` | Atualiza um único lead |
103
- | `createComplex(items)` | Cria leads com contatos e empresas em uma requisição |
104
- | `listLossReasons()` | Lista os motivos de perda configurados |
105
- | `getLossReasonById(id)` | Retorna um motivo de perda por ID |
106
-
107
- **Parâmetros de listagem (`ListLeadsParams`):**
108
-
109
- | Parâmetro | Tipo | Descrição |
110
- |-----------|------|-----------|
111
- | `page` | `number` | Página |
112
- | `limit` | `number` | Itens por página |
113
- | `query` | `string` | Busca textual |
114
- | `with` | `string \| string[]` | Blocos opcionais (`contacts`, `loss_reason`, `catalog_elements`, `is_price_modified_by_robot`, `only_deleted`, `source_id`) |
115
- | `filter_id` | `number[]` | Filtro por IDs |
116
- | `filter_name` | `string[]` | Filtro por nomes |
117
- | `filter_price` | `{ from?, to? }` | Filtro por valor |
118
- | `filter_pipeline_id` | `number[]` | Filtro por pipeline |
119
- | `filter_responsible_user_id` | `number[]` | Filtro por responsável |
120
- | `filter_statuses` | `{ pipeline_id, status_id }[]` | Filtro por estágio |
121
- | `filter_created_at_from` / `_to` | `number` | Unix timestamp de criação |
122
- | `filter_updated_at_from` / `_to` | `number` | Unix timestamp de atualização |
123
- | `filter_closed_at_from` / `_to` | `number` | Unix timestamp de fechamento |
124
- | `filter_closest_task_at_from` / `_to` | `number` | Unix timestamp da próxima tarefa |
125
- | `order_created_at` | `'asc' \| 'desc'` | Ordenação por criação |
126
- | `order_updated_at` | `'asc' \| 'desc'` | Ordenação por atualização |
127
- | `order_id` | `'asc' \| 'desc'` | Ordenação por ID |
128
-
129
- ```typescript
130
- const { _embedded } = await client.leads.list({
131
- with: ['contacts'],
132
- filter_pipeline_id: [1234],
133
- filter_statuses: [{ pipeline_id: 1234, status_id: 5678 }],
134
- order_created_at: 'desc',
135
- page: 1,
136
- limit: 50,
137
- });
138
-
139
- const leads = _embedded?.leads ?? [];
140
- ```
141
-
142
- ---
143
-
144
- ### `client.contacts`
145
-
146
- | Método | Descrição |
147
- |--------|-----------|
148
- | `list(params?)` | Lista contatos |
149
- | `getById(id, params?)` | Retorna contato por ID (ou `null`) |
150
- | `create(items)` | Cria um ou mais contatos |
151
- | `update(items)` | Atualiza contatos em lote |
152
- | `updateOne(id, payload)` | Atualiza um único contato |
153
-
154
- **Parâmetros `with` disponíveis:** `leads`, `catalog_elements`
155
-
156
- **Filtros disponíveis:** `filter_id`, `filter_name`, `filter_created_by`, `filter_updated_by`, `filter_responsible_user_id`, `filter_created_at_from/to`, `filter_updated_at_from/to`, `filter_closest_task_at_from/to`
157
-
158
- ---
159
-
160
- ### `client.companies`
161
-
162
- | Método | Descrição |
163
- |--------|-----------|
164
- | `list(params?)` | Lista empresas |
165
- | `getById(id, params?)` | Retorna empresa por ID (ou `null`) |
166
- | `create(items)` | Cria uma ou mais empresas |
167
- | `update(items)` | Atualiza empresas em lote |
168
- | `updateOne(id, payload)` | Atualiza uma única empresa |
169
-
170
- **Parâmetros `with` disponíveis:** `leads`, `contacts`, `catalog_elements`
171
-
172
- **Filtros disponíveis:** `filter_id`, `filter_name`, `filter_created_by`, `filter_updated_by`, `filter_responsible_user_id`, `filter_created_at_from/to`, `filter_updated_at_from/to`, `filter_closest_task_at_from/to`
173
-
174
- ---
175
-
176
- ### `client.unsorted`
177
-
178
- Gerencia leads da caixa de entrada (Unsorted).
179
-
180
- | Método | Descrição |
181
- |--------|-----------|
182
- | `list(params?)` | Lista leads não classificados |
183
- | `getByUid(uid)` | Retorna um lead não classificado pelo UID |
184
- | `createSip(items)` | Cria leads via integração SIP |
185
- | `createForms(items)` | Cria leads via formulário |
186
- | `accept(uid, payload?)` | Aceita um lead (move para pipeline) |
187
- | `decline(uid, payload?)` | Recusa e remove um lead não classificado |
188
- | `link(uid, payload)` | Vincula o lead a uma entidade existente |
189
- | `summary(params?)` | Resumo estatístico dos leads não classificados |
190
-
191
- ```typescript
192
- // Aceitar um lead não classificado
193
- await client.unsorted.accept('UID_DO_LEAD', {
194
- user_id: 123,
195
- status_id: 456,
196
- });
197
-
198
- // Vincular a um lead existente
199
- await client.unsorted.link('UID_DO_LEAD', {
200
- link: {
201
- entity_id: 9999,
202
- entity_type: 'leads',
203
- },
204
- });
205
- ```
206
-
207
- ---
208
-
209
- ### `client.pipelines`
210
-
211
- Gerencia funis e estágios de leads.
212
-
213
- | Método | Descrição |
214
- |--------|-----------|
215
- | `list()` | Lista todos os funis |
216
- | `getById(id)` | Retorna um funil por ID |
217
- | `create(items)` | Cria funis |
218
- | `update(id, payload)` | Atualiza um funil |
219
- | `delete(id)` | Remove um funil |
220
- | `listStatuses(pipelineId, params?)` | Lista estágios de um funil |
221
- | `getStatusById(pipelineId, id, params?)` | Retorna um estágio por ID |
222
- | `createStatuses(pipelineId, items)` | Cria estágios no funil |
223
- | `updateStatus(pipelineId, id, payload)` | Atualiza um estágio |
224
- | `deleteStatus(pipelineId, id)` | Remove um estágio |
225
-
226
- **Parâmetro `with` disponível para Status:** `'descriptions'`
227
-
228
- > ⚠️ **Validação local:** Estágios aceitam no máximo **3 descrições**, sem repetição de `level`, e cada descrição pode ter no máximo **1000 caracteres**. A SDK valida antes de enviar.
229
-
230
- ---
231
-
232
- ### `client.tasks`
233
-
234
- | Método | Descrição |
235
- |--------|-----------|
236
- | `list(params?)` | Lista tarefas |
237
- | `getById(id)` | Retorna tarefa por ID |
238
- | `create(items)` | Cria tarefas |
239
- | `update(items)` | Atualiza tarefas em lote |
240
- | `updateOne(id, payload)` | Atualiza uma única tarefa |
241
-
242
- **Filtros disponíveis:** `filter_id`, `filter_responsible_user_id`, `filter_is_completed`, `filter_task_type`, `filter_entity_type`, `filter_entity_id`, `filter_updated_at_from/to`
243
-
244
- **Ordenação:** `order_complete_till`, `order_created_at`, `order_id`
245
-
246
- ---
247
-
248
- ### `client.notes`
249
-
250
- Notas são sempre escopadas por tipo de entidade (`leads`, `contacts`, `companies`).
251
-
252
- | Método | Descrição |
253
- |--------|-----------|
254
- | `listByEntity(entityType, entityId, params?)` | Lista notas de uma entidade específica |
255
- | `listByEntityType(entityType, params?)` | Lista notas de todas as entidades do tipo |
256
- | `getById(entityType, id)` | Retorna uma nota por ID |
257
- | `create(entityType, items)` | Cria notas |
258
- | `update(entityType, items)` | Atualiza notas em lote |
259
- | `updateOne(entityType, id, payload)` | Atualiza uma única nota |
260
- | `pin(entityType, id)` | Fixa uma nota |
261
- | `unpin(entityType, id)` | Desafixa uma nota |
262
-
263
- **Tipos de nota (`note_type`):** `common`, `call_in`, `call_out`, `service_message`, `extended_service_message`, `geolocation`, `image`, `video`, `voice`, `doc`, `invoice`, `site_visit`, `messenger`, `sms`, `amolink`, `drive_file`, `chat_message`, entre outros.
264
-
265
- ```typescript
266
- // Criar nota de texto em um lead
267
- await client.notes.create('leads', {
268
- entity_id: 1234,
269
- note_type: 'common',
270
- params: { text: 'Cliente confirmou reunião.' },
271
- });
272
-
273
- // Criar nota de chamada
274
- await client.notes.create('leads', {
275
- entity_id: 1234,
276
- note_type: 'call_in',
277
- params: {
278
- uniq: 'UUID_DA_CHAMADA',
279
- duration: 120,
280
- source: 'minha-ura',
281
- link: 'https://cdn.example.com/recording.mp3',
282
- phone: '+5511999999999',
283
- },
284
- });
285
- ```
286
-
287
- ---
288
-
289
- ### `client.events`
290
-
291
- | Método | Descrição |
292
- |--------|-----------|
293
- | `list(params?)` | Lista eventos do log |
294
- | `getById(id, params?)` | Retorna um evento por ID |
295
- | `listTypes(params?)` | Lista os tipos de evento disponíveis |
296
-
297
- **Parâmetros `with` disponíveis:** `contact_name`
298
-
299
- **Filtros disponíveis:** `filter_id`, `filter_created_by`, `filter_entity`, `filter_entity_id` (exige `filter_entity` único), `filter_type`, `filter_created_at_from/to`, `filter_value_before`, `filter_value_after`
300
-
301
- > ⚠️ **Validação local:** `filter_entity_id` só é aceito quando `filter_entity` contém exatamente **um** tipo de entidade.
302
-
303
- ---
304
-
305
- ### `client.catalogs`
306
-
307
- Gerencia listas (catálogos) e seus elementos.
308
-
309
- | Método | Descrição |
310
- |--------|-----------|
311
- | `list(params?)` | Lista catálogos |
312
- | `getById(id)` | Retorna catálogo por ID |
313
- | `create(items)` | Cria catálogos |
314
- | `update(items)` | Atualiza catálogos em lote |
315
- | `updateOne(id, payload)` | Atualiza um único catálogo |
316
- | `listElements(listId, params?)` | Lista elementos do catálogo |
317
- | `getElementById(listId, elementId)` | Retorna elemento por ID |
318
- | `createElements(listId, items)` | Cria elementos no catálogo |
319
- | `updateElements(listId, items)` | Atualiza elementos em lote |
320
- | `updateElementById(listId, elementId, payload)` | Atualiza um único elemento |
321
-
322
- ```typescript
323
- // Listar elementos de um catálogo com busca textual
324
- const { _embedded } = await client.catalogs.listElements(42, {
325
- query: 'Produto X',
326
- limit: 20,
327
- });
328
- ```
329
-
330
- ---
331
-
332
- ### `client.customFields` e `client.customFieldGroups`
333
-
334
- #### `client.customFields`
335
-
336
- | Método | Descrição |
337
- |--------|-----------|
338
- | `listEntity(entityType)` | Lista campos de uma entidade (`leads`, `contacts`, `companies`) |
339
- | `getEntityById(entityType, id)` | Retorna campo por ID |
340
- | `createEntity(entityType, items)` | Cria campos |
341
- | `updateEntity(entityType, items)` | Atualiza campos em lote |
342
- | `updateEntityById(entityType, id, payload)` | Atualiza um campo |
343
- | `deleteEntity(entityType, id)` | Remove um campo |
344
- | `listList(listId)` | Lista campos de um catálogo |
345
- | `getListById(listId, customFieldId)` | Retorna campo de catálogo por ID |
346
- | `createList(listId, items)` | Cria campos no catálogo |
347
- | `updateList(listId, items)` | Atualiza campos do catálogo em lote |
348
- | `updateListById(listId, customFieldId, payload)` | Atualiza um campo |
349
- | `deleteList(listId, id)` | Remove campo do catálogo |
350
-
351
- #### `client.customFieldGroups`
352
-
353
- | Método | Descrição |
354
- |--------|-----------|
355
- | `list(entityType)` | Lista grupos de campos |
356
- | `getById(entityType, id)` | Retorna grupo por ID |
357
- | `create(entityType, items)` | Cria grupos |
358
- | `update(entityType, id, payload)` | Atualiza um grupo |
359
- | `delete(entityType, id)` | Remove um grupo |
360
-
361
- ---
362
-
363
- ### `client.users` e `client.roles`
364
-
365
- #### `client.users`
366
-
367
- | Método | Descrição |
368
- |--------|-----------|
369
- | `list(params?)` | Lista usuários |
370
- | `getById(id, params?)` | Retorna usuário por ID |
371
- | `create(items)` | Cria usuários (máximo **10** por requisição) |
372
-
373
- **Parâmetros `with` disponíveis:** `role`, `group`, `uuid`, `is_free`, `is_active`, `rights`
374
-
375
- #### `client.roles`
376
-
377
- | Método | Descrição |
378
- |--------|-----------|
379
- | `list(params?)` | Lista funções/roles |
380
- | `getById(id, params?)` | Retorna role por ID |
381
- | `create(items)` | Cria roles |
382
- | `update(items)` | Atualiza roles em lote |
383
- | `delete(id)` | Remove uma role |
384
-
385
- **Parâmetros `with` disponíveis:** `users`
386
-
387
- ---
388
-
389
- ### `client.tags`
390
-
391
- Tags são escopadas por tipo de entidade.
392
-
393
- | Método | Descrição |
394
- |--------|-----------|
395
- | `list(entityType, params?)` | Lista tags da entidade |
396
- | `create(entityType, items)` | Cria tags |
397
- | `updateForMany(entityType, items)` | Atualiza tags de múltiplas entidades via batch PATCH |
398
- | `updateForOne(entityType, id, payload)` | Atualiza tags de uma entidade |
399
-
400
- > ⚠️ **Validação local:** A propriedade `color` nas tags só é suportada para a entidade `leads`. Um aviso é emitido no console se usada em outros tipos.
401
-
402
- ```typescript
403
- // Criar tags coloridas para leads
404
- await client.tags.create('leads', [
405
- { name: 'VIP', color: '#FF0000' },
406
- { name: 'Urgente', color: '#FF5E00' },
407
- ]);
408
-
409
- // Substituir as tags de um contato específico
410
- await client.tags.updateForOne('contacts', 1234, {
411
- _embedded: { tags: [{ id: 99 }, { name: 'Nova Tag' }] },
412
- });
413
- ```
414
-
415
- ---
416
-
417
- ### `client.links`
418
-
419
- Gerencia vínculos entre entidades.
420
-
421
- | Método | Descrição |
422
- |--------|-----------|
423
- | `list(entity, entityId, params?)` | Lista vínculos de uma entidade |
424
- | `link(entity, entityId, items)` | Cria vínculos |
425
- | `unlink(entity, entityId, items)` | Remove vínculos |
426
-
427
- **Entidades fonte suportadas:** `leads`, `contacts`, `companies`
428
-
429
- **Filtros disponíveis:**
430
-
431
- | Parâmetro | Obs |
432
- |-----------|-----|
433
- | `filter_to_entity_id` | Deve ser usado **junto** com `filter_to_entity_type` |
434
- | `filter_to_entity_type` | Deve ser usado **junto** com `filter_to_entity_id` |
435
- | `filter_to_catalog_id` | Filtro por catálogo |
436
-
437
- > ⚠️ **Validação local:** `filter_to_entity_id` e `filter_to_entity_type` devem ser fornecidos **juntos**. A SDK lança erro se apenas um deles for informado.
438
-
439
- ---
440
-
441
- ### `client.salesbots`
442
-
443
- | Método | Descrição |
444
- |--------|-----------|
445
- | `list(params?)` | Lista salesbots disponíveis |
446
- | `run(botId, payload)` | Executa um bot em um lead/contato |
447
- | `runMany(items)` | Executa múltiplos bots em lote (máx. **100**) |
448
- | `stop(botId, payload)` | Para a execução de um bot |
449
- | `continueWidgetExecution(bot, botId, continueId, payload)` | Confirma execução de bloco de widget interativo |
450
-
451
- > ⚠️ **Validações locais:**
452
- > - `runMany` limita a **100 itens** por chamada.
453
- > - `continueWidgetExecution` limita `execute_handlers` a **10 itens**.
454
- > - Handlers `show` com mais de **80 caracteres** em `value` emitem aviso.
455
- > - Handlers `show` com mais de **25 botões** lançam erro.
456
-
457
- ---
458
-
459
- ### `client.sources` e `client.websiteButtons`
460
-
461
- #### `client.sources`
462
-
463
- | Método | Descrição |
464
- |--------|-----------|
465
- | `list()` | Lista fontes de captação |
466
- | `getById(id)` | Retorna fonte por ID |
467
- | `create(items)` | Cria fontes (máx. **100** por vez) |
468
- | `updateOne(id, payload)` | Atualiza uma fonte |
469
- | `update(items)` | Atualiza fontes em lote (máx. **100**) |
470
- | `deleteOne(id)` | Remove uma fonte |
471
- | `delete(items)` | Remove fontes em lote |
472
-
473
- #### `client.websiteButtons`
474
-
475
- | Método | Descrição |
476
- |--------|-----------|
477
- | `list(params?)` | Lista botões de chat web |
478
- | `getBySourceId(sourceId, params?)` | Retorna botão por source ID |
479
- | `create(payload)` | Cria um botão de chat web |
480
- | `connectOnlineChat(sourceId)` | Conecta chat online ao botão |
481
- | `update(sourceId, payload)` | Atualiza um botão |
482
-
483
- **Parâmetros `with` disponíveis para botões:** `'scripts'`
484
-
485
- > ⚠️ **Validação local:** Se `trusted_websites` não for informado e `is_used_in_app` não for `true`, a SDK emite aviso no console.
486
-
487
- ---
488
-
489
- ### `client.chatTemplates`
490
-
491
- Gerencia modelos de mensagem (inclui WABA/WhatsApp Business).
492
-
493
- | Método | Descrição |
494
- |--------|-----------|
495
- | `list(params?)` | Lista modelos da integração atual |
496
- | `getById(id, params?)` | Retorna modelo por ID |
497
- | `create(items)` | Cria modelos |
498
- | `update(items)` | Atualiza modelos em lote |
499
- | `submitForReview(id)` | Envia modelo WABA para moderação Meta |
500
- | `updateReviewStatus(id, reviewId, payload)` | Atualiza status de revisão (`approved`, `paused`, `rejected`) |
501
- | `delete(items)` | Remove modelos em lote |
502
- | `deleteOne(id)` | Remove um único modelo |
503
-
504
- **Parâmetros `with` disponíveis:** `'reviews'` — inclui `review_status`, `is_on_review` e `_embedded.reviews`
505
-
506
- **Filtros disponíveis:** `filter_external_id`
507
-
508
- > ⚠️ **Validação local:** A SDK emite aviso ao tentar atualizar modelos do tipo `waba` — eles só podem ser editados quando estão em estado `draft`.
509
-
510
- ```typescript
511
- // Criar modelo WABA (WhatsApp Business)
512
- await client.chatTemplates.create({
513
- name: 'confirmacao_consulta',
514
- content: 'Olá {{1}}, sua consulta está confirmada para {{2}}.',
515
- type: 'waba',
516
- waba_category: 'UTILITY',
517
- waba_language: 'pt_BR',
518
- waba_examples: { '1': 'João', '2': '10/06 às 14h' },
519
- });
520
-
521
- // Enviar para revisão da Meta
522
- const { _embedded } = await client.chatTemplates.submitForReview(templateId);
523
- console.log(_embedded?.reviews?.[0].status); // "review"
524
- ```
525
-
526
- ---
527
-
528
- ### `client.webhooks`
529
-
530
- | Método | Descrição |
531
- |--------|-----------|
532
- | `list(params?)` | Lista webhooks registrados |
533
- | `create(payload)` | Cria um webhook |
534
- | `delete(payload)` | Remove um webhook **pela URL** (`destination`) |
535
-
536
- **Filtros disponíveis:** `filter_destination`
537
-
538
- > ⚠️ A exclusão de webhook **não usa ID** — usa a URL de destino (`destination`). Isso é um comportamento intencional da API Kommo.
539
-
540
- ```typescript
541
- await client.webhooks.create({
542
- destination: 'https://meuservidor.com/kommo-webhook',
543
- settings: ['add_lead', 'update_lead', 'add_contact'],
544
- sort: 10,
545
- });
546
-
547
- await client.webhooks.delete({
548
- destination: 'https://meuservidor.com/kommo-webhook',
549
- });
550
- ```
551
-
552
- **Eventos conhecidos (`settings`):** `add_lead`, `update_lead`, `delete_lead`, `restore_lead`, `add_contact`, `update_contact`, `delete_contact`, `add_company`, `update_company`, `add_task`, `update_task`, `delete_task`, entre outros.
553
-
554
- ---
555
-
556
- ### `client.files`
557
-
558
- A Files API é dividida em três sub-módulos: `service`, `entities` e `links`.
559
-
560
- #### `client.files.service` — CDN de arquivos (`/v1.0/files`)
561
-
562
- | Método | Descrição |
563
- |--------|-----------|
564
- | `getByUuid(fileUuid)` | Retorna arquivo por UUID (ou `null` se não encontrado) |
565
- | `list(params?)` | Lista arquivos com filtros avançados |
566
- | `createUploadSession(payload)` | Abre uma sessão de upload multipart |
567
- | `uploadPart(sessionToken, filePart)` | Envia parte binária do arquivo |
568
- | `update(fileUuid, payload)` | Renomeia arquivo ou define nova versão ativa |
569
- | `delete(items)` | Remove arquivos em lote |
570
- | `restore(items)` | Restaura arquivos removidos |
571
- | `listVersions(fileUuid)` | Lista versões de um arquivo |
572
-
573
- **Filtros de listagem disponíveis:**
574
-
575
- | Parâmetro | Tipo | Descrição |
576
- |-----------|------|-----------|
577
- | `filter_uuid` | `string[]` | Por UUID |
578
- | `filter_name` | `string` | Por nome |
579
- | `filter_extensions` | `string[]` | Por extensão |
580
- | `filter_term` | `string` | Busca textual |
581
- | `filter_source_id` | `number` | Por fonte |
582
- | `filter_deleted` | `boolean` | Incluir/excluir deletados |
583
- | `filter_size_unit` / `_from` / `_to` | `number` | Por tamanho |
584
- | `filter_date_type` | `'created_at' \| 'updated_at'` | Tipo de data |
585
- | `filter_date_preset` | `string` | Preset de data (`day`, `week`, `month`, `year`, `last_3_days`, etc.) |
586
- | `filter_date_from` / `_to` | `number` | Intervalo de datas (Unix) |
587
- | `filter_created_by` / `filter_updated_by` | `number[]` | Por usuário (`-1` = cliente, `0` = robô) |
588
-
589
- > ⚠️ **Validação local:** `update()` lança erro se `name` e `version_uuid` forem informados simultaneamente — a API não permite os dois juntos.
590
-
591
- ```typescript
592
- // Fluxo completo de upload
593
- const session = await client.files.service.createUploadSession({
594
- file_name: 'contrato.pdf',
595
- file_size: buffer.byteLength,
596
- content_type: 'application/pdf',
597
- });
598
-
599
- const sessionToken = (session as any).upload_url?.split('/').pop();
600
-
601
- await client.files.service.uploadPart(sessionToken, buffer);
602
- ```
603
-
604
- #### `client.files.entities` — Anexos em entidades (`/api/v4`)
605
-
606
- | Método | Descrição |
607
- |--------|-----------|
608
- | `listAttachedToEntity(entity, entityId, params?)` | Lista arquivos anexados |
609
- | `attachToEntity(entity, entityId, items)` | Anexa arquivos |
610
- | `detachFromEntity(entity, entityId, items)` | Desanexa arquivos |
611
-
612
- **Entidades suportadas:** `leads`, `contacts`, `companies`
613
-
614
- #### `client.files.links` — Vínculos reversos de arquivo
615
-
616
- | Método | Descrição |
617
- |--------|-----------|
618
- | `listLinkedEntities(fileUuid)` | Lista as entidades associadas a um arquivo |
619
-
620
- ---
621
-
622
- ## 🏗️ Arquitetura Interna
623
-
624
- | Mecanismo | Descrição |
625
- |-----------|-----------|
626
- | **Raw Body** | Rotas com `RAW_BODY` na Kommo são automaticamente envelopadas como array pelo SDK |
627
- | **Query String** | Usa `qs` com `arrayFormat: 'brackets'` — compatível com o backend da Kommo |
628
- | **204 → null/void** | Respostas `204 No Content` são normalizadas para `null` ou arrays vazios |
629
- | **Pre-flight checks** | Validações locais antes da requisição HTTP para evitar erros 4xx desnecessários |
630
- | **Normalização PT→EN** | Entidades em português (`contatos`, `empresas`) são automaticamente normalizadas para o inglês usado na API |
631
-
632
- ---
633
-
634
- ## 📄 Licença
635
-
636
- MIT — livre para uso, modificação e distribuição.
1
+ # kommo-aiatende-api
2
+
3
+ SDK não oficial, moderno e **totalmente tipado** em TypeScript para a API V4 da [Kommo CRM](https://kommo.com). Cobre todos os recursos documentados, normaliza inconsistências da API e oferece validações locais (pre-flight) para evitar erros HTTP desnecessários.
4
+
5
+ ---
6
+
7
+ ## 📦 Instalação
8
+
9
+ ```bash
10
+ npm install kommo-aiatende-api
11
+ # ou
12
+ yarn add kommo-aiatende-api
13
+ # ou
14
+ pnpm add kommo-aiatende-api
15
+ ```
16
+
17
+ ---
18
+
19
+ ## 🚀 Inicialização
20
+
21
+ ```typescript
22
+ import { KommoClient } from 'kommo-aiatende-api';
23
+
24
+ const client = new KommoClient({
25
+ domain: 'meusubdominio', // apenas o subdomínio, sem ".kommo.com"
26
+ accessToken: 'SEU_ACCESS_TOKEN',
27
+ });
28
+
29
+ // Atualizar o token dinamicamente (ex: após refresh OAuth)
30
+ client.setAccessToken('NOVO_TOKEN');
31
+ ```
32
+
33
+ > **Nota:** A biblioteca não gerencia o fluxo OAuth. Você deve implementar a renovação de tokens na sua infraestrutura.
34
+
35
+ ---
36
+
37
+ ## 🛡️ Tratamento de Erros
38
+
39
+ Todos os erros HTTP são convertidos em `KommoApiError`:
40
+
41
+ ```typescript
42
+ import { KommoApiError } from 'kommo-aiatende-api';
43
+
44
+ try {
45
+ await client.leads.getById(999999);
46
+ } catch (err) {
47
+ if (err instanceof KommoApiError) {
48
+ console.log(err.status); // número HTTP (ex: 404)
49
+ console.log(err.title); // título do erro
50
+ console.log(err.detail); // detalhe técnico
51
+ console.log(err.raw); // corpo bruto da resposta
52
+ }
53
+ }
54
+ ```
55
+
56
+ ---
57
+
58
+ ## 📋 Referência Completa da API
59
+
60
+ ### `client.account`
61
+
62
+ Parâmetros e configurações da conta Kommo.
63
+
64
+ | Método | Descrição |
65
+ | -------------- | ---------------------------- |
66
+ | `get(params?)` | Retorna informações da conta |
67
+
68
+ **Parâmetros `with` disponíveis:**
69
+
70
+ | Valor | Descrição |
71
+ | ------------------- | ------------------------------------------- |
72
+ | `amojo_id` | ID da conta no serviço de chat |
73
+ | `amojo_rights` | Direitos de chat (grupos e diretos) |
74
+ | `users_groups` | Grupos de usuários da conta |
75
+ | `task_types` | Tipos de tarefas configurados |
76
+ | `version` | Versão atual da Kommo |
77
+ | `entity_names` | Nomes de entidades com traduções |
78
+ | `datetime_settings` | Configurações de data/hora |
79
+ | `drive_url` | URL base do serviço de arquivos (Files API) |
80
+
81
+ ```typescript
82
+ const account = await client.account.get({
83
+ with: ['amojo_id', 'drive_url', 'version'],
84
+ });
85
+
86
+ console.log(account.name);
87
+ console.log(account.subdomain);
88
+ console.log(account.amojo_id);
89
+ console.log(account._embedded?.drive_url);
90
+ ```
91
+
92
+ ---
93
+
94
+ ### `client.leads`
95
+
96
+ | Método | Descrição |
97
+ | ------------------------ | ---------------------------------------------------- |
98
+ | `list(params?)` | Lista leads com filtros e paginação |
99
+ | `getById(id, params?)` | Retorna um lead por ID (ou `null` se não encontrado) |
100
+ | `create(items)` | Cria um ou mais leads |
101
+ | `update(items)` | Atualiza leads em lote |
102
+ | `updateOne(id, payload)` | Atualiza um único lead |
103
+ | `createComplex(items)` | Cria leads com contatos e empresas em uma requisição |
104
+ | `listLossReasons()` | Lista os motivos de perda configurados |
105
+ | `getLossReasonById(id)` | Retorna um motivo de perda por ID |
106
+
107
+ **Parâmetros de listagem (`ListLeadsParams`):**
108
+
109
+ | Parâmetro | Tipo | Descrição |
110
+ | ------------------------------------- | ------------------------------ | --------------------------------------------------------------------------------------------------------------------------- |
111
+ | `page` | `number` | Página |
112
+ | `limit` | `number` | Itens por página |
113
+ | `query` | `string` | Busca textual |
114
+ | `with` | `string \| string[]` | Blocos opcionais (`contacts`, `loss_reason`, `catalog_elements`, `is_price_modified_by_robot`, `only_deleted`, `source_id`) |
115
+ | `filter_id` | `number[]` | Filtro por IDs |
116
+ | `filter_name` | `string[]` | Filtro por nomes |
117
+ | `filter_price` | `{ from?, to? }` | Filtro por valor |
118
+ | `filter_pipeline_id` | `number[]` | Filtro por pipeline |
119
+ | `filter_responsible_user_id` | `number[]` | Filtro por responsável |
120
+ | `filter_statuses` | `{ pipeline_id, status_id }[]` | Filtro por estágio |
121
+ | `filter_created_at_from` / `_to` | `number` | Unix timestamp de criação |
122
+ | `filter_updated_at_from` / `_to` | `number` | Unix timestamp de atualização |
123
+ | `filter_closed_at_from` / `_to` | `number` | Unix timestamp de fechamento |
124
+ | `filter_closest_task_at_from` / `_to` | `number` | Unix timestamp da próxima tarefa |
125
+ | `order_created_at` | `'asc' \| 'desc'` | Ordenação por criação |
126
+ | `order_updated_at` | `'asc' \| 'desc'` | Ordenação por atualização |
127
+ | `order_id` | `'asc' \| 'desc'` | Ordenação por ID |
128
+
129
+ ```typescript
130
+ const { _embedded } = await client.leads.list({
131
+ with: ['contacts'],
132
+ filter_pipeline_id: [1234],
133
+ filter_statuses: [{ pipeline_id: 1234, status_id: 5678 }],
134
+ order_created_at: 'desc',
135
+ page: 1,
136
+ limit: 50,
137
+ });
138
+
139
+ const leads = _embedded?.leads ?? [];
140
+ ```
141
+
142
+ ---
143
+
144
+ ### `client.contacts`
145
+
146
+ | Método | Descrição |
147
+ | ------------------------ | ---------------------------------- |
148
+ | `list(params?)` | Lista contatos |
149
+ | `getById(id, params?)` | Retorna contato por ID (ou `null`) |
150
+ | `create(items)` | Cria um ou mais contatos |
151
+ | `update(items)` | Atualiza contatos em lote |
152
+ | `updateOne(id, payload)` | Atualiza um único contato |
153
+
154
+ **Parâmetros `with` disponíveis:** `leads`, `catalog_elements`
155
+
156
+ **Filtros disponíveis:** `filter_id`, `filter_name`, `filter_created_by`, `filter_updated_by`, `filter_responsible_user_id`, `filter_created_at_from/to`, `filter_updated_at_from/to`, `filter_closest_task_at_from/to`
157
+
158
+ ---
159
+
160
+ ### `client.companies`
161
+
162
+ | Método | Descrição |
163
+ | ------------------------ | ---------------------------------- |
164
+ | `list(params?)` | Lista empresas |
165
+ | `getById(id, params?)` | Retorna empresa por ID (ou `null`) |
166
+ | `create(items)` | Cria uma ou mais empresas |
167
+ | `update(items)` | Atualiza empresas em lote |
168
+ | `updateOne(id, payload)` | Atualiza uma única empresa |
169
+
170
+ **Parâmetros `with` disponíveis:** `leads`, `contacts`, `catalog_elements`
171
+
172
+ **Filtros disponíveis:** `filter_id`, `filter_name`, `filter_created_by`, `filter_updated_by`, `filter_responsible_user_id`, `filter_created_at_from/to`, `filter_updated_at_from/to`, `filter_closest_task_at_from/to`
173
+
174
+ ---
175
+
176
+ ### `client.unsorted`
177
+
178
+ Gerencia leads da caixa de entrada (Unsorted).
179
+
180
+ | Método | Descrição |
181
+ | ------------------------ | ---------------------------------------------- |
182
+ | `list(params?)` | Lista leads não classificados |
183
+ | `getByUid(uid)` | Retorna um lead não classificado pelo UID |
184
+ | `createSip(items)` | Cria leads via integração SIP |
185
+ | `createForms(items)` | Cria leads via formulário |
186
+ | `accept(uid, payload?)` | Aceita um lead (move para pipeline) |
187
+ | `decline(uid, payload?)` | Recusa e remove um lead não classificado |
188
+ | `link(uid, payload)` | Vincula o lead a uma entidade existente |
189
+ | `summary(params?)` | Resumo estatístico dos leads não classificados |
190
+
191
+ ```typescript
192
+ // Aceitar um lead não classificado
193
+ await client.unsorted.accept('UID_DO_LEAD', {
194
+ user_id: 123,
195
+ status_id: 456,
196
+ });
197
+
198
+ // Vincular a um lead existente
199
+ await client.unsorted.link('UID_DO_LEAD', {
200
+ link: {
201
+ entity_id: 9999,
202
+ entity_type: 'leads',
203
+ },
204
+ });
205
+ ```
206
+
207
+ ---
208
+
209
+ ### `client.pipelines`
210
+
211
+ Gerencia funis e estágios de leads.
212
+
213
+ | Método | Descrição |
214
+ | ---------------------------------------- | -------------------------- |
215
+ | `list()` | Lista todos os funis |
216
+ | `getById(id)` | Retorna um funil por ID |
217
+ | `create(items)` | Cria funis |
218
+ | `update(id, payload)` | Atualiza um funil |
219
+ | `delete(id)` | Remove um funil |
220
+ | `listStatuses(pipelineId, params?)` | Lista estágios de um funil |
221
+ | `getStatusById(pipelineId, id, params?)` | Retorna um estágio por ID |
222
+ | `createStatuses(pipelineId, items)` | Cria estágios no funil |
223
+ | `updateStatus(pipelineId, id, payload)` | Atualiza um estágio |
224
+ | `deleteStatus(pipelineId, id)` | Remove um estágio |
225
+
226
+ **Parâmetro `with` disponível para Status:** `'descriptions'`
227
+
228
+ > ⚠️ **Validação local:** Estágios aceitam no máximo **3 descrições**, sem repetição de `level`, e cada descrição pode ter no máximo **1000 caracteres**. A SDK valida antes de enviar.
229
+
230
+ ---
231
+
232
+ ### `client.tasks`
233
+
234
+ | Método | Descrição |
235
+ | ------------------------ | ------------------------- |
236
+ | `list(params?)` | Lista tarefas |
237
+ | `getById(id)` | Retorna tarefa por ID |
238
+ | `create(items)` | Cria tarefas |
239
+ | `update(items)` | Atualiza tarefas em lote |
240
+ | `updateOne(id, payload)` | Atualiza uma única tarefa |
241
+
242
+ **Filtros disponíveis:** `filter_id`, `filter_responsible_user_id`, `filter_is_completed`, `filter_task_type`, `filter_entity_type`, `filter_entity_id`, `filter_updated_at_from/to`
243
+
244
+ **Ordenação:** `order_complete_till`, `order_created_at`, `order_id`
245
+
246
+ ---
247
+
248
+ ### `client.notes`
249
+
250
+ Notas são sempre escopadas por tipo de entidade (`leads`, `contacts`, `companies`).
251
+
252
+ | Método | Descrição |
253
+ | --------------------------------------------- | ----------------------------------------- |
254
+ | `listByEntity(entityType, entityId, params?)` | Lista notas de uma entidade específica |
255
+ | `listByEntityType(entityType, params?)` | Lista notas de todas as entidades do tipo |
256
+ | `getById(entityType, id)` | Retorna uma nota por ID |
257
+ | `create(entityType, items)` | Cria notas |
258
+ | `update(entityType, items)` | Atualiza notas em lote |
259
+ | `updateOne(entityType, id, payload)` | Atualiza uma única nota |
260
+ | `pin(entityType, id)` | Fixa uma nota |
261
+ | `unpin(entityType, id)` | Desafixa uma nota |
262
+
263
+ **Tipos de nota (`note_type`):** `common`, `call_in`, `call_out`, `service_message`, `extended_service_message`, `geolocation`, `image`, `video`, `voice`, `doc`, `invoice`, `site_visit`, `messenger`, `sms`, `amolink`, `drive_file`, `chat_message`, entre outros.
264
+
265
+ ```typescript
266
+ // Criar nota de texto em um lead
267
+ await client.notes.create('leads', {
268
+ entity_id: 1234,
269
+ note_type: 'common',
270
+ params: { text: 'Cliente confirmou reunião.' },
271
+ });
272
+
273
+ // Criar nota de chamada
274
+ await client.notes.create('leads', {
275
+ entity_id: 1234,
276
+ note_type: 'call_in',
277
+ params: {
278
+ uniq: 'UUID_DA_CHAMADA',
279
+ duration: 120,
280
+ source: 'minha-ura',
281
+ link: 'https://cdn.example.com/recording.mp3',
282
+ phone: '+5511999999999',
283
+ },
284
+ });
285
+ ```
286
+
287
+ ---
288
+
289
+ ### `client.events`
290
+
291
+ | Método | Descrição |
292
+ | ---------------------- | ------------------------------------ |
293
+ | `list(params?)` | Lista eventos do log |
294
+ | `getById(id, params?)` | Retorna um evento por ID |
295
+ | `listTypes(params?)` | Lista os tipos de evento disponíveis |
296
+
297
+ **Parâmetros `with` disponíveis:** `contact_name`
298
+
299
+ **Filtros disponíveis:** `filter_id`, `filter_created_by`, `filter_entity`, `filter_entity_id` (exige `filter_entity` único), `filter_type`, `filter_created_at_from/to`, `filter_value_before`, `filter_value_after`
300
+
301
+ > ⚠️ **Validação local:** `filter_entity_id` só é aceito quando `filter_entity` contém exatamente **um** tipo de entidade.
302
+
303
+ ---
304
+
305
+ ### `client.catalogs`
306
+
307
+ Gerencia listas (catálogos) e seus elementos.
308
+
309
+ | Método | Descrição |
310
+ | ----------------------------------------------- | --------------------------- |
311
+ | `list(params?)` | Lista catálogos |
312
+ | `getById(id)` | Retorna catálogo por ID |
313
+ | `create(items)` | Cria catálogos |
314
+ | `update(items)` | Atualiza catálogos em lote |
315
+ | `updateOne(id, payload)` | Atualiza um único catálogo |
316
+ | `listElements(listId, params?)` | Lista elementos do catálogo |
317
+ | `getElementById(listId, elementId)` | Retorna elemento por ID |
318
+ | `createElements(listId, items)` | Cria elementos no catálogo |
319
+ | `updateElements(listId, items)` | Atualiza elementos em lote |
320
+ | `updateElementById(listId, elementId, payload)` | Atualiza um único elemento |
321
+
322
+ ```typescript
323
+ // Listar elementos de um catálogo com busca textual
324
+ const { _embedded } = await client.catalogs.listElements(42, {
325
+ query: 'Produto X',
326
+ limit: 20,
327
+ });
328
+ ```
329
+
330
+ ---
331
+
332
+ ### `client.customFields` e `client.customFieldGroups`
333
+
334
+ #### `client.customFields`
335
+
336
+ | Método | Descrição |
337
+ | ------------------------------------------------ | --------------------------------------------------------------- |
338
+ | `listEntity(entityType)` | Lista campos de uma entidade (`leads`, `contacts`, `companies`) |
339
+ | `getEntityById(entityType, id)` | Retorna campo por ID |
340
+ | `createEntity(entityType, items)` | Cria campos |
341
+ | `updateEntity(entityType, items)` | Atualiza campos em lote |
342
+ | `updateEntityById(entityType, id, payload)` | Atualiza um campo |
343
+ | `deleteEntity(entityType, id)` | Remove um campo |
344
+ | `listList(listId)` | Lista campos de um catálogo |
345
+ | `getListById(listId, customFieldId)` | Retorna campo de catálogo por ID |
346
+ | `createList(listId, items)` | Cria campos no catálogo |
347
+ | `updateList(listId, items)` | Atualiza campos do catálogo em lote |
348
+ | `updateListById(listId, customFieldId, payload)` | Atualiza um campo |
349
+ | `deleteList(listId, id)` | Remove campo do catálogo |
350
+
351
+ #### `client.customFieldGroups`
352
+
353
+ | Método | Descrição |
354
+ | --------------------------------- | ---------------------- |
355
+ | `list(entityType)` | Lista grupos de campos |
356
+ | `getById(entityType, id)` | Retorna grupo por ID |
357
+ | `create(entityType, items)` | Cria grupos |
358
+ | `update(entityType, id, payload)` | Atualiza um grupo |
359
+ | `delete(entityType, id)` | Remove um grupo |
360
+
361
+ ---
362
+
363
+ ### `client.users` e `client.roles`
364
+
365
+ #### `client.users`
366
+
367
+ | Método | Descrição |
368
+ | ---------------------- | -------------------------------------------- |
369
+ | `list(params?)` | Lista usuários |
370
+ | `getById(id, params?)` | Retorna usuário por ID |
371
+ | `create(items)` | Cria usuários (máximo **10** por requisição) |
372
+
373
+ **Parâmetros `with` disponíveis:** `role`, `group`, `uuid`, `is_free`, `is_active`, `rights`
374
+
375
+ #### `client.roles`
376
+
377
+ | Método | Descrição |
378
+ | ---------------------- | ---------------------- |
379
+ | `list(params?)` | Lista funções/roles |
380
+ | `getById(id, params?)` | Retorna role por ID |
381
+ | `create(items)` | Cria roles |
382
+ | `update(items)` | Atualiza roles em lote |
383
+ | `delete(id)` | Remove uma role |
384
+
385
+ **Parâmetros `with` disponíveis:** `users`
386
+
387
+ ---
388
+
389
+ ### `client.tags`
390
+
391
+ Tags são escopadas por tipo de entidade.
392
+
393
+ | Método | Descrição |
394
+ | --------------------------------------- | ---------------------------------------------------- |
395
+ | `list(entityType, params?)` | Lista tags da entidade |
396
+ | `create(entityType, items)` | Cria tags |
397
+ | `updateForMany(entityType, items)` | Atualiza tags de múltiplas entidades via batch PATCH |
398
+ | `updateForOne(entityType, id, payload)` | Atualiza tags de uma entidade |
399
+
400
+ > ⚠️ **Validação local:** A propriedade `color` nas tags só é suportada para a entidade `leads`. Um aviso é emitido no console se usada em outros tipos.
401
+
402
+ ```typescript
403
+ // Criar tags coloridas para leads
404
+ await client.tags.create('leads', [
405
+ { name: 'VIP', color: '#FF0000' },
406
+ { name: 'Urgente', color: '#FF5E00' },
407
+ ]);
408
+
409
+ // Substituir as tags de um contato específico
410
+ await client.tags.updateForOne('contacts', 1234, {
411
+ _embedded: { tags: [{ id: 99 }, { name: 'Nova Tag' }] },
412
+ });
413
+ ```
414
+
415
+ ---
416
+
417
+ ### `client.links`
418
+
419
+ Gerencia vínculos entre entidades.
420
+
421
+ | Método | Descrição |
422
+ | --------------------------------- | ------------------------------ |
423
+ | `list(entity, entityId, params?)` | Lista vínculos de uma entidade |
424
+ | `link(entity, entityId, items)` | Cria vínculos |
425
+ | `unlink(entity, entityId, items)` | Remove vínculos |
426
+
427
+ **Entidades fonte suportadas:** `leads`, `contacts`, `companies`
428
+
429
+ **Filtros disponíveis:**
430
+
431
+ | Parâmetro | Obs |
432
+ | ----------------------- | ---------------------------------------------------- |
433
+ | `filter_to_entity_id` | Deve ser usado **junto** com `filter_to_entity_type` |
434
+ | `filter_to_entity_type` | Deve ser usado **junto** com `filter_to_entity_id` |
435
+ | `filter_to_catalog_id` | Filtro por catálogo |
436
+
437
+ > ⚠️ **Validação local:** `filter_to_entity_id` e `filter_to_entity_type` devem ser fornecidos **juntos**. A SDK lança erro se apenas um deles for informado.
438
+
439
+ ---
440
+
441
+ ### `client.salesbots`
442
+
443
+ | Método | Descrição |
444
+ | ---------------------------------------------------------- | ----------------------------------------------- |
445
+ | `list(params?)` | Lista salesbots disponíveis |
446
+ | `run(botId, payload)` | Executa um bot em um lead/contato |
447
+ | `runMany(items)` | Executa múltiplos bots em lote (máx. **100**) |
448
+ | `stop(botId, payload)` | Para a execução de um bot |
449
+ | `continueWidgetExecution(bot, botId, continueId, payload)` | Confirma execução de bloco de widget interativo |
450
+
451
+ > ⚠️ **Validações locais:**
452
+ >
453
+ > - `runMany` limita a **100 itens** por chamada.
454
+ > - `continueWidgetExecution` limita `execute_handlers` a **10 itens**.
455
+ > - Handlers `show` com mais de **80 caracteres** em `value` emitem aviso.
456
+ > - Handlers `show` com mais de **25 botões** lançam erro.
457
+
458
+ ---
459
+
460
+ ### `client.sources` e `client.websiteButtons`
461
+
462
+ #### `client.sources`
463
+
464
+ | Método | Descrição |
465
+ | ------------------------ | -------------------------------------- |
466
+ | `list()` | Lista fontes de captação |
467
+ | `getById(id)` | Retorna fonte por ID |
468
+ | `create(items)` | Cria fontes (máx. **100** por vez) |
469
+ | `updateOne(id, payload)` | Atualiza uma fonte |
470
+ | `update(items)` | Atualiza fontes em lote (máx. **100**) |
471
+ | `deleteOne(id)` | Remove uma fonte |
472
+ | `delete(items)` | Remove fontes em lote |
473
+
474
+ #### `client.websiteButtons`
475
+
476
+ | Método | Descrição |
477
+ | ---------------------------------- | ---------------------------- |
478
+ | `list(params?)` | Lista botões de chat web |
479
+ | `getBySourceId(sourceId, params?)` | Retorna botão por source ID |
480
+ | `create(payload)` | Cria um botão de chat web |
481
+ | `connectOnlineChat(sourceId)` | Conecta chat online ao botão |
482
+ | `update(sourceId, payload)` | Atualiza um botão |
483
+
484
+ **Parâmetros `with` disponíveis para botões:** `'scripts'`
485
+
486
+ > ⚠️ **Validação local:** Se `trusted_websites` não for informado e `is_used_in_app` não for `true`, a SDK emite aviso no console.
487
+
488
+ ---
489
+
490
+ ### `client.chatTemplates`
491
+
492
+ Gerencia modelos de mensagem (inclui WABA/WhatsApp Business).
493
+
494
+ | Método | Descrição |
495
+ | ------------------------------------------- | ------------------------------------------------------------- |
496
+ | `list(params?)` | Lista modelos da integração atual |
497
+ | `getById(id, params?)` | Retorna modelo por ID |
498
+ | `create(items)` | Cria modelos |
499
+ | `update(items)` | Atualiza modelos em lote |
500
+ | `submitForReview(id)` | Envia modelo WABA para moderação Meta |
501
+ | `updateReviewStatus(id, reviewId, payload)` | Atualiza status de revisão (`approved`, `paused`, `rejected`) |
502
+ | `delete(items)` | Remove modelos em lote |
503
+ | `deleteOne(id)` | Remove um único modelo |
504
+
505
+ **Parâmetros `with` disponíveis:** `'reviews'` — inclui `review_status`, `is_on_review` e `_embedded.reviews`
506
+
507
+ **Filtros disponíveis:** `filter_external_id`
508
+
509
+ > ⚠️ **Validação local:** A SDK emite aviso ao tentar atualizar modelos do tipo `waba` — eles só podem ser editados quando estão em estado `draft`.
510
+
511
+ ```typescript
512
+ // Criar modelo WABA (WhatsApp Business)
513
+ await client.chatTemplates.create({
514
+ name: 'confirmacao_consulta',
515
+ content: 'Olá {{1}}, sua consulta está confirmada para {{2}}.',
516
+ type: 'waba',
517
+ waba_category: 'UTILITY',
518
+ waba_language: 'pt_BR',
519
+ waba_examples: { '1': 'João', '2': '10/06 às 14h' },
520
+ });
521
+
522
+ // Enviar para revisão da Meta
523
+ const { _embedded } = await client.chatTemplates.submitForReview(templateId);
524
+ console.log(_embedded?.reviews?.[0].status); // "review"
525
+ ```
526
+
527
+ ---
528
+
529
+ ### `client.webhooks`
530
+
531
+ | Método | Descrição |
532
+ | ----------------- | ---------------------------------------------- |
533
+ | `list(params?)` | Lista webhooks registrados |
534
+ | `create(payload)` | Cria um webhook |
535
+ | `delete(payload)` | Remove um webhook **pela URL** (`destination`) |
536
+
537
+ **Filtros disponíveis:** `filter_destination`
538
+
539
+ > ⚠️ A exclusão de webhook **não usa ID** — usa a URL de destino (`destination`). Isso é um comportamento intencional da API Kommo.
540
+
541
+ ```typescript
542
+ await client.webhooks.create({
543
+ destination: 'https://meuservidor.com/kommo-webhook',
544
+ settings: ['add_lead', 'update_lead', 'add_contact'],
545
+ sort: 10,
546
+ });
547
+
548
+ await client.webhooks.delete({
549
+ destination: 'https://meuservidor.com/kommo-webhook',
550
+ });
551
+ ```
552
+
553
+ **Eventos conhecidos (`settings`):** `add_lead`, `update_lead`, `delete_lead`, `restore_lead`, `add_contact`, `update_contact`, `delete_contact`, `add_company`, `update_company`, `add_task`, `update_task`, `delete_task`, entre outros.
554
+
555
+ ---
556
+
557
+ ### `client.files`
558
+
559
+ A Files API é dividida em três sub-módulos: `service`, `entities` e `links`.
560
+
561
+ #### `client.files.service` — CDN de arquivos (`/v1.0/files`)
562
+
563
+ | Método | Descrição |
564
+ | ------------------------------------ | ------------------------------------------------------ |
565
+ | `getByUuid(fileUuid)` | Retorna arquivo por UUID (ou `null` se não encontrado) |
566
+ | `list(params?)` | Lista arquivos com filtros avançados |
567
+ | `createUploadSession(payload)` | Abre uma sessão de upload multipart |
568
+ | `uploadPart(sessionToken, filePart)` | Envia parte binária do arquivo |
569
+ | `update(fileUuid, payload)` | Renomeia arquivo ou define nova versão ativa |
570
+ | `delete(items)` | Remove arquivos em lote |
571
+ | `restore(items)` | Restaura arquivos removidos |
572
+ | `listVersions(fileUuid)` | Lista versões de um arquivo |
573
+
574
+ **Filtros de listagem disponíveis:**
575
+
576
+ | Parâmetro | Tipo | Descrição |
577
+ | ----------------------------------------- | ------------------------------ | -------------------------------------------------------------------- |
578
+ | `filter_uuid` | `string[]` | Por UUID |
579
+ | `filter_name` | `string` | Por nome |
580
+ | `filter_extensions` | `string[]` | Por extensão |
581
+ | `filter_term` | `string` | Busca textual |
582
+ | `filter_source_id` | `number` | Por fonte |
583
+ | `filter_deleted` | `boolean` | Incluir/excluir deletados |
584
+ | `filter_size_unit` / `_from` / `_to` | `number` | Por tamanho |
585
+ | `filter_date_type` | `'created_at' \| 'updated_at'` | Tipo de data |
586
+ | `filter_date_preset` | `string` | Preset de data (`day`, `week`, `month`, `year`, `last_3_days`, etc.) |
587
+ | `filter_date_from` / `_to` | `number` | Intervalo de datas (Unix) |
588
+ | `filter_created_by` / `filter_updated_by` | `number[]` | Por usuário (`-1` = cliente, `0` = robô) |
589
+
590
+ > ⚠️ **Validação local:** `update()` lança erro se `name` e `version_uuid` forem informados simultaneamente — a API não permite os dois juntos.
591
+
592
+ ```typescript
593
+ // Fluxo completo de upload
594
+ const session = await client.files.service.createUploadSession({
595
+ file_name: 'contrato.pdf',
596
+ file_size: buffer.byteLength,
597
+ content_type: 'application/pdf',
598
+ });
599
+
600
+ const sessionToken = (session as any).upload_url?.split('/').pop();
601
+
602
+ await client.files.service.uploadPart(sessionToken, buffer);
603
+ ```
604
+
605
+ #### `client.files.entities` — Anexos em entidades (`/api/v4`)
606
+
607
+ | Método | Descrição |
608
+ | ------------------------------------------------- | ----------------------- |
609
+ | `listAttachedToEntity(entity, entityId, params?)` | Lista arquivos anexados |
610
+ | `attachToEntity(entity, entityId, items)` | Anexa arquivos |
611
+ | `detachFromEntity(entity, entityId, items)` | Desanexa arquivos |
612
+
613
+ **Entidades suportadas:** `leads`, `contacts`, `companies`
614
+
615
+ #### `client.files.links` — Vínculos reversos de arquivo
616
+
617
+ | Método | Descrição |
618
+ | ------------------------------ | ------------------------------------------ |
619
+ | `listLinkedEntities(fileUuid)` | Lista as entidades associadas a um arquivo |
620
+
621
+ ---
622
+
623
+ ## 🏗️ Arquitetura Interna
624
+
625
+ | Mecanismo | Descrição |
626
+ | ---------------------- | ----------------------------------------------------------------------------------------------------------- |
627
+ | **Raw Body** | Rotas com `RAW_BODY` na Kommo são automaticamente envelopadas como array pelo SDK |
628
+ | **Query String** | Usa `qs` com `arrayFormat: 'brackets'` — compatível com o backend da Kommo |
629
+ | **204 → null/void** | Respostas `204 No Content` são normalizadas para `null` ou arrays vazios |
630
+ | **Pre-flight checks** | Validações locais antes da requisição HTTP para evitar erros 4xx desnecessários |
631
+ | **Normalização PT→EN** | Entidades em português (`contatos`, `empresas`) são automaticamente normalizadas para o inglês usado na API |
632
+
633
+ ---
634
+
635
+ ## 📄 Licença
636
+
637
+ MIT — livre para uso, modificação e distribuição.