@comando.one/mcp-server 0.1.0 → 0.2.0

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.
Files changed (3) hide show
  1. package/README.md +21 -3
  2. package/dist/index.js +740 -14
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -1,4 +1,4 @@
1
- # @comando/mcp-server
1
+ # @comando.one/mcp-server
2
2
 
3
3
  Servidor **MCP (Model Context Protocol)** para a API pública do **Comando.One**. Conecte o Claude (Desktop, Code ou qualquer cliente MCP) ao seu ERP e **opere tudo por linguagem natural**: clientes, propostas, contratos, faturas, cobranças Pix/boleto, NFS-e, contas a pagar, financeiro e webhooks.
4
4
 
@@ -11,7 +11,7 @@ Adicione ao seu `claude_desktop_config.json`:
11
11
  "mcpServers": {
12
12
  "comando": {
13
13
  "command": "npx",
14
- "args": ["-y", "@comando/mcp-server"],
14
+ "args": ["-y", "@comando.one/mcp-server"],
15
15
  "env": {
16
16
  "COMANDO_API_KEY": "cmd_live_...",
17
17
  "COMANDO_COMPANY_ID": ""
@@ -23,6 +23,24 @@ Adicione ao seu `claude_desktop_config.json`:
23
23
 
24
24
  Gere sua chave em **Configurações → API Keys** no app. Reinicie o Claude Desktop e pronto.
25
25
 
26
+ ## Alternativa: MCP remoto (sem instalar nada)
27
+
28
+ Além deste pacote stdio, existe um **endpoint MCP remoto (streaming)** em `https://api.comando.one/mcp` (transporte MCP Streamable HTTP). Para clientes com conector remoto:
29
+
30
+ ```json
31
+ {
32
+ "mcpServers": {
33
+ "comando-remoto": {
34
+ "type": "http",
35
+ "url": "https://api.comando.one/mcp",
36
+ "headers": { "Authorization": "Bearer cmd_live_..." }
37
+ }
38
+ }
39
+ }
40
+ ```
41
+
42
+ Ambos expõem o **mesmo conjunto de ferramentas** (50 curadas + `lookups` + `comando_request` = cobertura total da API).
43
+
26
44
  ## Variáveis de ambiente
27
45
 
28
46
  | Variável | Obrigatória | Padrão | Descrição |
@@ -33,7 +51,7 @@ Gere sua chave em **Configurações → API Keys** no app. Reinicie o Claude Des
33
51
 
34
52
  ## Como funciona
35
53
 
36
- - **~50 tools curadas** (gerados a partir do OpenAPI canônico, zero drift) cobrindo as operações de maior valor — `customers_list`, `invoices_create`, `charges_create`, `nfse_emit`, `payouts_create`, etc.
54
+ - **~70 tools curadas** (gerados a partir do OpenAPI canônico, zero drift) cobrindo as operações de maior valor — `customers_list`, `invoices_create`/`invoices_delete`, `charges_create`, `nfse_emit`, `payouts_create`, `contracts_pause`/`contracts_resume`, `service_categories_create`, `reports_aging_actions`/`reports_cashflow_forecast`, `audit_timeline`, `cost_centers_create`, etc.
37
55
  - **`comando_request`** — escape hatch genérico (`method`, `path`, `query`, `body`) que cobre 100% dos endpoints restantes.
38
56
  - **`lookups`** — catálogos read-only (centros de custo, condições/métodos de pagamento, naturezas, contas bancárias).
39
57
  - **`whoami`** — identidade, empresas acessíveis e scopes da chave.
package/dist/index.js CHANGED
@@ -180,7 +180,50 @@ var MANIFEST = [
180
180
  // ----- Webhooks -----
181
181
  { operationId: "listWebhooks", tool: "webhooks_list" },
182
182
  { operationId: "getWebhookById", tool: "webhooks_get" },
183
- { operationId: "createWebhook", tool: "webhooks_create", write: true }
183
+ { operationId: "createWebhook", tool: "webhooks_create", write: true },
184
+ // ----- Split de Pagamentos -----
185
+ { operationId: "listSplitRules", tool: "split_rules_list" },
186
+ { operationId: "getSplitRule", tool: "split_rules_get" },
187
+ { operationId: "createSplitRule", tool: "split_rules_create", write: true },
188
+ { operationId: "updateSplitRule", tool: "split_rules_update", write: true },
189
+ { operationId: "deleteSplitRule", tool: "split_rules_delete", write: true, destructive: true },
190
+ { operationId: "listSplitExecutions", tool: "split_executions_list" },
191
+ { operationId: "getSplitExecution", tool: "split_executions_get" },
192
+ { operationId: "reverseSplitExecution", tool: "split_reverse", write: true, destructive: true },
193
+ { operationId: "releaseSplitItem", tool: "split_release_item", write: true },
194
+ // Auditoria
195
+ { operationId: "getAuditTimeline", tool: "audit_timeline" },
196
+ // Categorias de serviço
197
+ { operationId: "listServiceCategories", tool: "service_categories_list" },
198
+ { operationId: "createServiceCategory", tool: "service_categories_create", write: true },
199
+ { operationId: "updateServiceCategory", tool: "service_categories_update", write: true },
200
+ { operationId: "deleteServiceCategory", tool: "service_categories_delete", write: true, destructive: true },
201
+ // Relatórios (read-only)
202
+ { operationId: "reportAgingActions", tool: "reports_aging_actions" },
203
+ { operationId: "reportCashflowForecast", tool: "reports_cashflow_forecast" },
204
+ // Contratos — pausar/retomar
205
+ { operationId: "pauseContract", tool: "contracts_pause", write: true },
206
+ { operationId: "resumeContract", tool: "contracts_resume", write: true },
207
+ // Reajustes de contrato (specs/reajustes/) — aplicar muda preço → destructive
208
+ { operationId: "listDueReadjustments", tool: "contracts_readjustments_due" },
209
+ { operationId: "listContractReadjustments", tool: "contracts_readjustments_list" },
210
+ { operationId: "applyContractReadjustment", tool: "contracts_readjustments_apply", write: true, destructive: true },
211
+ { operationId: "getMarketIndices", tool: "market_indices_get" },
212
+ // Faturas — exclusão física
213
+ { operationId: "deleteInvoice", tool: "invoices_delete", write: true, destructive: true },
214
+ // NFS-e — sincronizar status / baixar arquivos
215
+ { operationId: "syncNfse", tool: "nfse_sync", write: true },
216
+ { operationId: "getNfseFiles", tool: "nfse_files" },
217
+ // Centros de custo (CRUD)
218
+ { operationId: "listCostCenters", tool: "cost_centers_list" },
219
+ { operationId: "createCostCenter", tool: "cost_centers_create", write: true },
220
+ { operationId: "updateCostCenter", tool: "cost_centers_update", write: true },
221
+ { operationId: "deleteCostCenter", tool: "cost_centers_delete", write: true, destructive: true },
222
+ // Lembretes (CRUD)
223
+ { operationId: "listReminders", tool: "reminders_list" },
224
+ { operationId: "createReminder", tool: "reminders_create", write: true },
225
+ { operationId: "updateReminder", tool: "reminders_update", write: true },
226
+ { operationId: "deleteReminder", tool: "reminders_delete", write: true, destructive: true }
184
227
  ];
185
228
 
186
229
  // ../../src/lib/openApiSpec.ts
@@ -230,7 +273,14 @@ var WEBHOOK_EVENT_KEYS = [
230
273
  "customer.deleted",
231
274
  "supplier.created",
232
275
  "supplier.updated",
233
- "supplier.deleted"
276
+ "supplier.deleted",
277
+ "split.calculated",
278
+ "repasse.released",
279
+ "repasse.paid",
280
+ "repasse.failed",
281
+ "repasse.reversed",
282
+ "supplier_payout_request.created",
283
+ "supplier_payout_request.approved"
234
284
  ];
235
285
  var SCHEMAS = {
236
286
  Error: {
@@ -406,6 +456,65 @@ var SCHEMAS = {
406
456
  notes: { type: "string" }
407
457
  }
408
458
  },
459
+ ContractReadjustment: {
460
+ type: "object",
461
+ description: "Reajuste aplicado a um contrato (specs/reajustes/).",
462
+ properties: {
463
+ id: { type: "string", format: "uuid" },
464
+ contract_id: { type: "string", format: "uuid" },
465
+ applied_at: { type: "string", format: "date-time" },
466
+ applied_by: { type: ["string", "null"], format: "uuid" },
467
+ period_start: { type: ["string", "null"], format: "date", description: "In\xEDcio do per\xEDodo coberto (\xFAltimo reajuste anterior)" },
468
+ period_end: { type: ["string", "null"], format: "date" },
469
+ previous_amount: { type: "number" },
470
+ new_amount: { type: "number" },
471
+ applied_percent: { type: "number", description: "Percentual efetivamente aplicado" },
472
+ suggested_percent: { type: ["number", "null"], description: "Sugest\xE3o do \xEDndice preferido no momento da aplica\xE7\xE3o" },
473
+ suggested_index: { type: ["string", "null"], enum: ["ipca", "igpm", "inpc", "usd", "eur", null] },
474
+ notes: { type: ["string", "null"] }
475
+ }
476
+ },
477
+ ContractReadjustmentCreate: {
478
+ type: "object",
479
+ description: "Informe 'new_amount' OU 'percent' \u2014 o outro \xE9 derivado do valor atual do contrato.",
480
+ properties: {
481
+ new_amount: { type: "number", description: "Novo valor do contrato (R$)" },
482
+ percent: { type: "number", description: "Percentual de reajuste (ex.: 4.62)" },
483
+ suggested_percent: { type: "number", description: "Sugest\xE3o exibida no momento (para o hist\xF3rico sugerido \xD7 aplicado)" },
484
+ suggested_index: { type: "string", enum: ["ipca", "igpm", "inpc", "usd", "eur"] },
485
+ notes: { type: "string" }
486
+ }
487
+ },
488
+ ContractReadjustmentQueueItem: {
489
+ type: "object",
490
+ description: "Contrato na fila de reajuste (vencido ou na janela).",
491
+ properties: {
492
+ id: { type: "string", format: "uuid" },
493
+ customer_id: { type: "string", format: "uuid" },
494
+ customers: { type: "object", properties: { name: { type: "string" } } },
495
+ title: { type: ["string", "null"] },
496
+ status: { type: "string" },
497
+ frequency: { type: "string" },
498
+ amount: { type: "number" },
499
+ readjustment_index: { type: "string", enum: ["ipca", "igpm", "inpc", "usd", "eur", "manual"] },
500
+ readjustment_period_months: { type: "integer" },
501
+ last_readjustment_date: { type: ["string", "null"], format: "date" },
502
+ next_readjustment_date: { type: ["string", "null"], format: "date" },
503
+ next_generation_date: { type: ["string", "null"], format: "date", description: "Quando a pr\xF3xima fatura ser\xE1 gerada \u2014 se antes do reajuste, ela sai no valor antigo" },
504
+ overdue: { type: "boolean" }
505
+ }
506
+ },
507
+ MarketIndexSuggestion: {
508
+ type: "object",
509
+ description: "Acumulado de um \xEDndice oficial no per\xEDodo (fonte: BCB, cache local).",
510
+ properties: {
511
+ index_code: { type: "string", enum: ["ipca", "igpm", "inpc", "usd", "eur"] },
512
+ accumulated_pct: { type: ["number", "null"], description: "Acumulado em pontos percentuais (4.62 = 4,62%); null = sem cobertura de dados" },
513
+ coverage_start: { type: ["string", "null"], format: "date" },
514
+ coverage_end: { type: ["string", "null"], format: "date" },
515
+ last_ref_date: { type: ["string", "null"], format: "date", description: "At\xE9 onde o \xEDndice cobre (IPCA sai com ~15 dias de atraso)" }
516
+ }
517
+ },
409
518
  InvoiceItem: {
410
519
  type: "object",
411
520
  properties: {
@@ -510,7 +619,9 @@ var SCHEMAS = {
510
619
  type: "object",
511
620
  properties: {
512
621
  id: { type: "string", format: "uuid" },
513
- name: { type: "string" },
622
+ name: { type: "string", description: "T\xEDtulo / r\xF3tulo de exibi\xE7\xE3o do fornecedor" },
623
+ legal_name: { type: ["string", "null"], description: "Raz\xE3o social (PJ) ou nome completo (PF/estrangeira)" },
624
+ surname: { type: ["string", "null"], description: "Sobrenome (pessoa f\xEDsica)" },
514
625
  email: { type: ["string", "null"] },
515
626
  phone: { type: ["string", "null"] },
516
627
  document: { type: ["string", "null"], description: "CPF ou CNPJ" },
@@ -523,6 +634,8 @@ var SCHEMAS = {
523
634
  payment_terms_days: { type: ["integer", "null"] },
524
635
  status: { type: "string", enum: ["ativo", "inativo"] },
525
636
  notes: { type: ["string", "null"] },
637
+ pagarme_recipient_id: { type: ["string", "null"], description: "ID do recebedor Pagar.me (re_\u2026) para split nativo. Criado pela aplica\xE7\xE3o." },
638
+ pagarme_kyc_status: { type: ["string", "null"], enum: ["pending", "registration", "approved", "refused", "suspended", "blocked", null], description: "Status de KYC do recebedor Pagar.me." },
526
639
  created_at: { type: "string", format: "date-time" },
527
640
  updated_at: { type: "string", format: "date-time" }
528
641
  }
@@ -531,7 +644,9 @@ var SCHEMAS = {
531
644
  type: "object",
532
645
  required: ["name"],
533
646
  properties: {
534
- name: { type: "string" },
647
+ name: { type: "string", description: "T\xEDtulo / r\xF3tulo de exibi\xE7\xE3o. Se omitido, derivado de legal_name." },
648
+ legal_name: { type: "string", description: "Raz\xE3o social (PJ) ou nome completo (PF/estrangeira)" },
649
+ surname: { type: "string", description: "Sobrenome (pessoa f\xEDsica)" },
535
650
  email: { type: "string" },
536
651
  phone: { type: "string" },
537
652
  document: { type: "string" },
@@ -674,8 +789,8 @@ var SCHEMAS = {
674
789
  id: { type: "string", format: "uuid" },
675
790
  status: { type: "string", enum: ["pending", "paid", "cancelled", "expired", "failed"] },
676
791
  status_raw: { type: "string", description: "Status bruto do provider" },
677
- method: { type: "string", enum: ["pix", "boleto", "checkout"] },
678
- provider: { type: "string", enum: ["inter", "c6bank", "pix_offline"], description: "Provedor resolvido. 'pix_offline' = Pix est\xE1tico (BR Code gerado localmente, sem API banc\xE1ria)." },
792
+ method: { type: "string", enum: ["pix", "boleto", "checkout", "credit_card"] },
793
+ provider: { type: "string", enum: ["inter", "c6bank", "pix_offline", "pagarme"], description: "Provedor resolvido. 'pix_offline' = Pix est\xE1tico (BR Code local). 'pagarme' = Pix server-side ou cart\xE3o (method=credit_card retorna 'checkout.url' = link da p\xE1gina de pagamento)." },
679
794
  invoice_id: { type: ["string", "null"], format: "uuid" },
680
795
  customer_id: { type: ["string", "null"], format: "uuid" },
681
796
  amount: { type: ["number", "null"] },
@@ -691,7 +806,8 @@ var SCHEMAS = {
691
806
  type: "object",
692
807
  required: ["method"],
693
808
  properties: {
694
- method: { type: "string", enum: ["pix", "boleto", "checkout"], description: "Canal de pagamento" },
809
+ method: { type: "string", enum: ["pix", "boleto", "checkout", "credit_card"], description: "Canal de pagamento" },
810
+ provider: { type: "string", enum: ["inter", "c6bank", "pix_offline", "pagarme"], description: "Opcional. Desambigua quando a empresa tem mais de um provedor no mesmo canal (ex.: Pix Inter x Pix Pagar.me). Se omitido, usa o provedor ativo do canal." },
695
811
  invoice_id: { type: "string", format: "uuid", description: "Fatura existente (opcional)" },
696
812
  customer_id: { type: "string", format: "uuid", description: "Obrigat\xF3rio se invoice_id omitido" },
697
813
  amount: { type: "number", description: "Obrigat\xF3rio se invoice_id omitido" },
@@ -773,6 +889,122 @@ var SCHEMAS = {
773
889
  description: { type: "string" }
774
890
  }
775
891
  },
892
+ SplitRuleRecipient: {
893
+ type: "object",
894
+ description: "Linha de uma regra de split: um benefici\xE1rio e sua base de c\xE1lculo.",
895
+ properties: {
896
+ id: { type: "string", format: "uuid" },
897
+ recipient_type: { type: "string", enum: ["supplier", "platform", "company_master"] },
898
+ supplier_id: { type: ["string", "null"], format: "uuid" },
899
+ supplier_payment_method_id: { type: ["string", "null"], format: "uuid" },
900
+ basis: { type: "string", enum: ["percentual", "fixo", "combinado"] },
901
+ percent: { type: "number", description: "0\u2013100 (percentual)" },
902
+ fixed_cents: { type: "integer", description: "Valor fixo em centavos" },
903
+ is_platform_fee: { type: "boolean" },
904
+ apply_per_installment: { type: "boolean" },
905
+ installments: { type: ["object", "null"], description: "Divis\xE3o por parcela (jsonb)" },
906
+ sort_order: { type: "integer" }
907
+ }
908
+ },
909
+ SplitRule: {
910
+ type: "object",
911
+ description: "Regra de divis\xE3o (template) de um recebimento entre benefici\xE1rios.",
912
+ properties: {
913
+ id: { type: "string", format: "uuid" },
914
+ name: { type: "string" },
915
+ description: { type: ["string", "null"] },
916
+ scope: { type: "string", enum: ["company_default", "contract", "invoice", "charge"] },
917
+ contract_id: { type: ["string", "null"], format: "uuid" },
918
+ fiscal_mode: { type: "string", enum: ["intermediacao", "revenda"] },
919
+ fee_payer: { type: "string", enum: ["platform", "recipients", "proportional"] },
920
+ release_trigger: { type: "string", enum: ["on_settlement", "on_nota", "manual", "scheduled"] },
921
+ rounding_strategy: { type: "string", enum: ["remainder_to_master", "largest_remainder"] },
922
+ is_active: { type: "boolean" },
923
+ gateway_split_enabled: { type: "boolean", description: "Quando true, usa o split nativo da Pagar.me (divis\xE3o no ato do pagamento) se a cobran\xE7a for Pagar.me e os fornecedores tiverem recebedor aprovado; sen\xE3o, repasse interno." },
924
+ recipients: { type: "array", items: { $ref: "#/components/schemas/SplitRuleRecipient" } },
925
+ created_at: { type: "string", format: "date-time" },
926
+ updated_at: { type: "string", format: "date-time" }
927
+ }
928
+ },
929
+ SplitRuleCreate: {
930
+ type: "object",
931
+ required: ["name", "recipients"],
932
+ properties: {
933
+ name: { type: "string" },
934
+ description: { type: "string" },
935
+ scope: { type: "string", enum: ["company_default", "contract", "invoice", "charge"], default: "company_default" },
936
+ contract_id: { type: "string", format: "uuid", description: "Obrigat\xF3rio quando scope=contract" },
937
+ fiscal_mode: { type: "string", enum: ["intermediacao", "revenda"], default: "intermediacao" },
938
+ fee_payer: { type: "string", enum: ["platform", "recipients", "proportional"], default: "platform" },
939
+ release_trigger: { type: "string", enum: ["on_settlement", "on_nota", "manual", "scheduled"], default: "on_settlement" },
940
+ rounding_strategy: { type: "string", enum: ["remainder_to_master", "largest_remainder"], default: "remainder_to_master" },
941
+ is_active: { type: "boolean", default: true },
942
+ gateway_split_enabled: { type: "boolean", default: true, description: "Usar o split nativo da Pagar.me quando aplic\xE1vel (sen\xE3o repasse interno)." },
943
+ recipients: {
944
+ type: "array",
945
+ description: "Benefici\xE1rios. Percentual primeiro, depois fixo. Soma de percentuais \u2264 100.",
946
+ items: {
947
+ type: "object",
948
+ required: ["recipient_type", "basis"],
949
+ properties: {
950
+ recipient_type: { type: "string", enum: ["supplier", "platform", "company_master"] },
951
+ supplier_id: { type: "string", format: "uuid", description: "Obrigat\xF3rio se recipient_type=supplier" },
952
+ supplier_payment_method_id: { type: "string", format: "uuid" },
953
+ basis: { type: "string", enum: ["percentual", "fixo", "combinado"] },
954
+ percent: { type: "number" },
955
+ fixed_cents: { type: "integer" },
956
+ is_platform_fee: { type: "boolean" },
957
+ sort_order: { type: "integer" },
958
+ apply_per_installment: { type: "boolean", description: "Split por parcela: percent/fixo v\xEAm de 'installments'" },
959
+ installments: { type: "object", description: 'Por n\xBA de parcela, ex.: { "1": { "percent": 50 }, "default": { "percent": 100 } }' }
960
+ }
961
+ }
962
+ }
963
+ }
964
+ },
965
+ SplitExecutionItem: {
966
+ type: "object",
967
+ description: "Fatia de uma execu\xE7\xE3o de split, por benefici\xE1rio.",
968
+ properties: {
969
+ id: { type: "string", format: "uuid" },
970
+ recipient_type: { type: "string", enum: ["supplier", "platform", "company_master"] },
971
+ supplier_id: { type: ["string", "null"], format: "uuid" },
972
+ supplier_name: { type: ["string", "null"] },
973
+ is_platform_fee: { type: "boolean" },
974
+ gross_share_cents: { type: "integer" },
975
+ fee_share_cents: { type: "integer" },
976
+ net_share_cents: { type: "integer" },
977
+ status: { type: "string", enum: ["pending", "awaiting_nota", "released", "paying", "paid", "reversed", "failed"] },
978
+ payment_order_id: { type: ["string", "null"], format: "uuid" },
979
+ nota_status: { type: "string" },
980
+ error_message: { type: ["string", "null"], description: "Motivo da falha do repasse (quando status=failed)" },
981
+ released_at: { type: ["string", "null"], format: "date-time" },
982
+ paid_at: { type: ["string", "null"], format: "date-time" },
983
+ reversed_at: { type: ["string", "null"], format: "date-time" }
984
+ }
985
+ },
986
+ SplitExecution: {
987
+ type: "object",
988
+ description: "Execu\xE7\xE3o de split: inst\xE2ncia concreta de uma divis\xE3o por cobran\xE7a recebida.",
989
+ properties: {
990
+ id: { type: "string", format: "uuid" },
991
+ invoice_id: { type: ["string", "null"], format: "uuid" },
992
+ charge_id: { type: ["string", "null"], format: "uuid" },
993
+ split_rule_id: { type: ["string", "null"], format: "uuid" },
994
+ gateway_provider: { type: ["string", "null"] },
995
+ gross_cents: { type: "integer" },
996
+ gateway_fee_cents: { type: "integer" },
997
+ net_cents: { type: "integer" },
998
+ fiscal_mode: { type: "string", enum: ["intermediacao", "revenda"] },
999
+ release_trigger: { type: "string", enum: ["on_settlement", "on_nota", "manual", "scheduled"] },
1000
+ status: { type: "string", enum: ["pending", "calculated", "releasing", "completed", "partial", "reversed", "failed"] },
1001
+ settled_at: { type: ["string", "null"], format: "date-time" },
1002
+ error_message: { type: ["string", "null"] },
1003
+ items: { type: "array", items: { $ref: "#/components/schemas/SplitExecutionItem" } },
1004
+ created_at: { type: "string", format: "date-time" },
1005
+ updated_at: { type: "string", format: "date-time" }
1006
+ }
1007
+ },
776
1008
  SupplierPaymentMethod: {
777
1009
  type: "object",
778
1010
  properties: {
@@ -991,6 +1223,34 @@ var SCHEMAS = {
991
1223
  sort_order: { type: "integer" }
992
1224
  }
993
1225
  },
1226
+ Reminder: {
1227
+ type: "object",
1228
+ properties: {
1229
+ id: { type: "string", format: "uuid" },
1230
+ scope: { type: "string", enum: ["personal", "company"] },
1231
+ audience: { type: "array", items: { type: "string", enum: ["admin", "operador", "visualizador"] }, description: "Pap\xE9is que recebem (vazio = todos os membros)." },
1232
+ kind: { type: "string", enum: ["manual", "digest"] },
1233
+ template_key: { type: ["string", "null"], description: "Para digest: revenue.summary, receivables.overdue, payables.due, cards.upcoming, nfse.monthly, cashflow.position, mrr.snapshot." },
1234
+ params: { type: "object", description: "Par\xE2metros do digest (ex: { period: 'week' } ou { days_ahead: 7 })." },
1235
+ title: { type: ["string", "null"] },
1236
+ body: { type: ["string", "null"] },
1237
+ entity_type: { type: ["string", "null"] },
1238
+ entity_id: { type: ["string", "null"], format: "uuid" },
1239
+ channels: { type: "object", properties: { in_app: { type: "boolean" }, email: { type: "boolean" }, push: { type: "boolean" } } },
1240
+ recurrence_type: { type: "string", enum: ["once", "daily", "weekly", "monthly"] },
1241
+ run_time: { type: "string", description: "HH:MM[:SS], hora local do fuso." },
1242
+ weekday: { type: ["integer", "null"], description: "0=domingo \u2026 6=s\xE1bado (semanal)." },
1243
+ day_of_month: { type: ["integer", "null"], description: "1\u201331 (mensal; meses curtos usam o \xFAltimo dia)." },
1244
+ timezone: { type: "string" },
1245
+ start_date: { type: ["string", "null"], format: "date" },
1246
+ end_date: { type: ["string", "null"], format: "date" },
1247
+ next_run_at: { type: ["string", "null"], format: "date-time" },
1248
+ last_run_at: { type: ["string", "null"], format: "date-time" },
1249
+ active: { type: "boolean" },
1250
+ created_at: { type: "string", format: "date-time" },
1251
+ updated_at: { type: "string", format: "date-time" }
1252
+ }
1253
+ },
994
1254
  PaymentCondition: {
995
1255
  type: "object",
996
1256
  properties: {
@@ -1004,6 +1264,15 @@ var SCHEMAS = {
1004
1264
  type: "object",
1005
1265
  properties: { id: { type: "string", format: "uuid" }, name: { type: "string" } }
1006
1266
  },
1267
+ ServiceCategory: {
1268
+ type: "object",
1269
+ properties: {
1270
+ id: { type: "string", format: "uuid" },
1271
+ name: { type: "string" },
1272
+ color: { type: ["string", "null"] },
1273
+ created_at: { type: "string", format: "date-time" }
1274
+ }
1275
+ },
1007
1276
  WebhookDelivery: {
1008
1277
  type: "object",
1009
1278
  properties: {
@@ -1072,7 +1341,7 @@ var OPENAPI_SPEC = {
1072
1341
  },
1073
1342
  servers: [
1074
1343
  { url: "https://api.comando.one/v1", description: "Produ\xE7\xE3o" },
1075
- { url: "https://pecdxlrbutkrtxvjsquf.supabase.co/functions/v1/public-api/v1", description: "Supabase direto" }
1344
+ { url: "https://sb.comando.one/functions/v1/public-api/v1", description: "Supabase direto" }
1076
1345
  ],
1077
1346
  security: API_KEY_SECURITY,
1078
1347
  tags: [
@@ -1093,7 +1362,8 @@ var OPENAPI_SPEC = {
1093
1362
  { name: "Contas banc\xE1rias", description: "Contas banc\xE1rias (somente leitura)" },
1094
1363
  { name: "Pagamentos a Fornecedor", description: "Payouts \u2014 pagar/agendar Pix e boleto a fornecedores" },
1095
1364
  { name: "M\xE9todos de pagamento", description: "Formas de recebimento dispon\xEDveis" },
1096
- { name: "Formas de pagamento do fornecedor", description: "Cadastro de destinos de pagamento por fornecedor" }
1365
+ { name: "Formas de pagamento do fornecedor", description: "Cadastro de destinos de pagamento por fornecedor" },
1366
+ { name: "Lembretes", description: "Lembretes e resumos agendados (recorrentes ou avulsos)" }
1097
1367
  ],
1098
1368
  components: {
1099
1369
  securitySchemes: {
@@ -1526,6 +1796,89 @@ var OPENAPI_SPEC = {
1526
1796
  responses: { "204": { description: "Exclu\xEDdo" }, "404": errorResponse("Contrato n\xE3o encontrado"), "409": errorResponse("H\xE1 registros vinculados que impedem a exclus\xE3o"), ...COMMON_ERRORS }
1527
1797
  }
1528
1798
  },
1799
+ "/contracts/{id}/pause": {
1800
+ parameters: [{ name: "id", in: "path", required: true, schema: { type: "string", format: "uuid" } }],
1801
+ post: {
1802
+ tags: ["Contratos"],
1803
+ summary: "Pausar contrato (status \u2192 suspenso)",
1804
+ operationId: "pauseContract",
1805
+ security: [{ ApiKeyAuth: ["contracts:write"] }],
1806
+ responses: { "200": { description: "Contrato pausado", content: { "application/json": { schema: { $ref: "#/components/schemas/Contract" } } } }, "404": errorResponse("Contrato n\xE3o encontrado"), ...COMMON_ERRORS }
1807
+ }
1808
+ },
1809
+ "/contracts/{id}/resume": {
1810
+ parameters: [{ name: "id", in: "path", required: true, schema: { type: "string", format: "uuid" } }],
1811
+ post: {
1812
+ tags: ["Contratos"],
1813
+ summary: "Retomar contrato (status \u2192 ativo)",
1814
+ operationId: "resumeContract",
1815
+ security: [{ ApiKeyAuth: ["contracts:write"] }],
1816
+ responses: { "200": { description: "Contrato retomado", content: { "application/json": { schema: { $ref: "#/components/schemas/Contract" } } } }, "404": errorResponse("Contrato n\xE3o encontrado"), "409": errorResponse("Status n\xE3o permite retomada"), ...COMMON_ERRORS }
1817
+ }
1818
+ },
1819
+ "/contracts/readjustments/due": {
1820
+ get: {
1821
+ tags: ["Contratos"],
1822
+ summary: "Fila de reajuste (contratos atrasados + janela)",
1823
+ description: "Contratos ativos, n\xE3o isentos, com reajuste vencido ou vencendo na janela informada. Campo 'overdue' indica atraso.",
1824
+ operationId: "listDueReadjustments",
1825
+ security: [{ ApiKeyAuth: ["contracts:read"] }],
1826
+ parameters: [
1827
+ { name: "days", in: "query", schema: { type: "integer", default: 30, minimum: 0, maximum: 365 }, description: "Janela em dias al\xE9m dos atrasados" }
1828
+ ],
1829
+ responses: {
1830
+ "200": { description: "Fila de reajuste", content: { "application/json": { schema: { type: "object", properties: { data: { type: "array", items: { $ref: "#/components/schemas/ContractReadjustmentQueueItem" } }, window_days: { type: "integer" } } } } } },
1831
+ ...COMMON_ERRORS
1832
+ }
1833
+ }
1834
+ },
1835
+ "/contracts/{id}/readjustments": {
1836
+ parameters: [{ name: "id", in: "path", required: true, schema: { type: "string", format: "uuid" } }],
1837
+ get: {
1838
+ tags: ["Contratos"],
1839
+ summary: "Hist\xF3rico de reajustes do contrato",
1840
+ operationId: "listContractReadjustments",
1841
+ security: [{ ApiKeyAuth: ["contracts:read"] }],
1842
+ responses: {
1843
+ "200": { description: "Reajustes aplicados (mais recente primeiro)", content: { "application/json": { schema: { type: "object", properties: { data: { type: "array", items: { $ref: "#/components/schemas/ContractReadjustment" } } } } } } },
1844
+ "404": errorResponse("Contrato n\xE3o encontrado"),
1845
+ ...COMMON_ERRORS
1846
+ }
1847
+ },
1848
+ post: {
1849
+ tags: ["Contratos"],
1850
+ summary: "Aplicar reajuste no contrato",
1851
+ description: "Atualiza o valor do contrato (e escala os itens proporcionalmente), grava o hist\xF3rico e avan\xE7a a data do pr\xF3ximo reajuste. Informe 'new_amount' OU 'percent'. Faturas j\xE1 geradas n\xE3o s\xE3o alteradas.",
1852
+ operationId: "applyContractReadjustment",
1853
+ security: [{ ApiKeyAuth: ["contracts:write"] }],
1854
+ requestBody: { required: true, content: { "application/json": { schema: { $ref: "#/components/schemas/ContractReadjustmentCreate" } } } },
1855
+ responses: {
1856
+ "201": { description: "Reajuste aplicado", content: { "application/json": { schema: { $ref: "#/components/schemas/ContractReadjustment" } } } },
1857
+ "400": errorResponse("Dados inv\xE1lidos"),
1858
+ "404": errorResponse("Contrato n\xE3o encontrado"),
1859
+ "409": errorResponse("Contrato com valor zero \u2014 informe new_amount"),
1860
+ ...COMMON_ERRORS
1861
+ }
1862
+ }
1863
+ },
1864
+ "/market-indices": {
1865
+ get: {
1866
+ tags: ["Contratos"],
1867
+ summary: "\xCDndices de mercado acumulados no per\xEDodo (BCB)",
1868
+ description: "Acumulado de IPCA/IGP-M/INPC (composto mensal) e varia\xE7\xE3o da PTAX de d\xF3lar/euro entre 'from' e 'to'. Fonte: Banco Central (SGS e PTAX), sincronizada diariamente.",
1869
+ operationId: "getMarketIndices",
1870
+ security: [{ ApiKeyAuth: ["contracts:read"] }],
1871
+ parameters: [
1872
+ { name: "from", in: "query", required: true, schema: { type: "string", format: "date" }, description: "In\xEDcio do per\xEDodo (ex.: data do \xFAltimo reajuste)" },
1873
+ { name: "to", in: "query", schema: { type: "string", format: "date" }, description: "Fim do per\xEDodo (padr\xE3o: hoje)" }
1874
+ ],
1875
+ responses: {
1876
+ "200": { description: "Acumulados por \xEDndice", content: { "application/json": { schema: { type: "object", properties: { from: { type: "string", format: "date" }, to: { type: "string", format: "date" }, data: { type: "array", items: { $ref: "#/components/schemas/MarketIndexSuggestion" } } } } } } },
1877
+ "400": errorResponse("Par\xE2metro 'from' obrigat\xF3rio"),
1878
+ ...COMMON_ERRORS
1879
+ }
1880
+ }
1881
+ },
1529
1882
  // -----------------------------------------------------------------------
1530
1883
  // Invoices
1531
1884
  // -----------------------------------------------------------------------
@@ -1571,6 +1924,14 @@ var OPENAPI_SPEC = {
1571
1924
  "404": errorResponse("Fatura n\xE3o encontrada"),
1572
1925
  ...COMMON_ERRORS
1573
1926
  }
1927
+ },
1928
+ delete: {
1929
+ tags: ["Faturas"],
1930
+ summary: "Excluir fatura",
1931
+ operationId: "deleteInvoice",
1932
+ description: "Exclus\xE3o f\xEDsica da fatura (itens e cobran\xE7as vinculadas via cascade). Use cancel para apenas cancelar.",
1933
+ security: [{ ApiKeyAuth: ["invoices:delete"] }],
1934
+ responses: { "204": { description: "Exclu\xEDda" }, "404": errorResponse("Fatura n\xE3o encontrada"), "409": errorResponse("H\xE1 registros vinculados que impedem a exclus\xE3o"), ...COMMON_ERRORS }
1574
1935
  }
1575
1936
  },
1576
1937
  "/invoices/{id}/cancel": {
@@ -1668,6 +2029,114 @@ var OPENAPI_SPEC = {
1668
2029
  security: [{ ApiKeyAuth: ["expenses:read", "expenses:write", "finance:read"] }],
1669
2030
  parameters: [...PAGINATION_PARAMS, { name: "active", in: "query", schema: { type: "string", enum: ["true", "false"] } }],
1670
2031
  responses: { "200": paginatedResponse("#/components/schemas/CostCenter"), ...COMMON_ERRORS }
2032
+ },
2033
+ post: {
2034
+ tags: ["Cat\xE1logos"],
2035
+ summary: "Criar centro de custo",
2036
+ operationId: "createCostCenter",
2037
+ security: [{ ApiKeyAuth: ["finance:write"] }],
2038
+ requestBody: { required: true, content: { "application/json": { schema: { type: "object", required: ["name"], properties: {
2039
+ name: { type: "string" },
2040
+ color: { type: "string" },
2041
+ icon: { type: "string" },
2042
+ dre_group: { type: "string" },
2043
+ sort_order: { type: "integer" },
2044
+ active: { type: "boolean" }
2045
+ } } } } },
2046
+ responses: { "201": { description: "Centro de custo criado", content: { "application/json": { schema: { $ref: "#/components/schemas/CostCenter" } } } }, "400": errorResponse("Nome ausente"), "409": errorResponse("Nome duplicado"), ...COMMON_ERRORS }
2047
+ }
2048
+ },
2049
+ "/cost-centers/{id}": {
2050
+ parameters: [{ name: "id", in: "path", required: true, schema: { type: "string", format: "uuid" } }],
2051
+ patch: {
2052
+ tags: ["Cat\xE1logos"],
2053
+ summary: "Atualizar centro de custo",
2054
+ operationId: "updateCostCenter",
2055
+ security: [{ ApiKeyAuth: ["finance:write"] }],
2056
+ requestBody: { required: true, content: { "application/json": { schema: { type: "object", properties: { name: { type: "string" }, color: { type: "string" }, icon: { type: "string" }, dre_group: { type: "string" }, sort_order: { type: "integer" }, active: { type: "boolean" } } } } } },
2057
+ responses: { "200": { description: "Atualizado", content: { "application/json": { schema: { $ref: "#/components/schemas/CostCenter" } } } }, "400": errorResponse("Nada para atualizar"), "404": errorResponse("N\xE3o encontrado"), "409": errorResponse("Nome duplicado"), ...COMMON_ERRORS }
2058
+ },
2059
+ delete: {
2060
+ tags: ["Cat\xE1logos"],
2061
+ summary: "Excluir centro de custo",
2062
+ operationId: "deleteCostCenter",
2063
+ security: [{ ApiKeyAuth: ["finance:delete"] }],
2064
+ responses: { "204": { description: "Exclu\xEDdo" }, "404": errorResponse("N\xE3o encontrado"), "409": errorResponse("H\xE1 registros vinculados"), ...COMMON_ERRORS }
2065
+ }
2066
+ },
2067
+ "/reminders": {
2068
+ get: {
2069
+ tags: ["Lembretes"],
2070
+ summary: "Listar lembretes",
2071
+ operationId: "listReminders",
2072
+ description: "Lembretes e resumos agendados da empresa.",
2073
+ security: [{ ApiKeyAuth: ["reminders:list"] }],
2074
+ parameters: [
2075
+ ...PAGINATION_PARAMS,
2076
+ { name: "active", in: "query", schema: { type: "string", enum: ["true", "false"] } },
2077
+ { name: "scope", in: "query", schema: { type: "string", enum: ["personal", "company"] } }
2078
+ ],
2079
+ responses: { "200": paginatedResponse("#/components/schemas/Reminder"), ...COMMON_ERRORS }
2080
+ },
2081
+ post: {
2082
+ tags: ["Lembretes"],
2083
+ summary: "Criar lembrete",
2084
+ operationId: "createReminder",
2085
+ description: "Cria um lembrete. ESCOPO: scope='personal' cria um lembrete s\xF3 do usu\xE1rio (aparece em 'Meus lembretes'); scope='company' cria para a empresa (todos os membros veem). No chat, scope='personal' usa o usu\xE1rio autenticado; via chave cmd_live (sem usu\xE1rio) informe owner_user_id para pessoal. RELATIVO ('daqui 30 min'): { title, remind_in_minutes } \u2014 o servidor calcula o hor\xE1rio. ABSOLUTO: { title, remind_at } (ISO, use 'Z' p/ UTC). Em ambos, kind=manual, recurrence_type=once, start_date e run_time s\xE3o inferidos.",
2086
+ security: [{ ApiKeyAuth: ["reminders:create"] }],
2087
+ requestBody: { required: true, content: { "application/json": { schema: { type: "object", required: ["title"], properties: {
2088
+ scope: { type: "string", enum: ["personal", "company"], description: "personal = s\xF3 do usu\xE1rio; company = todos da empresa. Default: personal no chat (com usu\xE1rio), company via chave de API." },
2089
+ owner_user_id: { type: "string", format: "uuid", description: "Dono do lembrete pessoal (membro da empresa). No chat \xE9 inferido do usu\xE1rio; s\xF3 necess\xE1rio via chave cmd_live para scope=personal." },
2090
+ kind: { type: "string", enum: ["manual", "digest"], description: "Default: manual (ou digest se houver template_key)." },
2091
+ title: { type: "string", description: "T\xEDtulo do lembrete (obrigat\xF3rio para kind=manual)." },
2092
+ body: { type: "string" },
2093
+ template_key: { type: "string", description: "Obrigat\xF3rio para kind=digest." },
2094
+ remind_in_minutes: { type: "integer", description: "Atalho RELATIVO: minutos a partir de agora (servidor calcula). Ex.: 'daqui 30min' \u2192 30. Preferir para lembretes relativos." },
2095
+ remind_at: { type: "string", description: "Atalho ABSOLUTO: instante ISO (use 'Z' para UTC). Vira recurrence once + start_date + run_time no fuso." },
2096
+ params: { type: "object" },
2097
+ audience: { type: "array", items: { type: "string", enum: ["admin", "operador", "visualizador"] } },
2098
+ channels: { type: "object", properties: { in_app: { type: "boolean" }, email: { type: "boolean" }, push: { type: "boolean" } } },
2099
+ recurrence_type: { type: "string", enum: ["once", "daily", "weekly", "monthly"], description: "Default once quando se usa remind_in_minutes/remind_at." },
2100
+ run_time: { type: "string", description: "HH:MM (hora local) \u2014 para recorr\xEAncias." },
2101
+ weekday: { type: "integer", description: "0\u20136 (semanal)." },
2102
+ day_of_month: { type: "integer", description: "1\u201331 (mensal)." },
2103
+ timezone: { type: "string" },
2104
+ start_date: { type: "string", format: "date" },
2105
+ end_date: { type: "string", format: "date" }
2106
+ } } } } },
2107
+ responses: { "201": { description: "Lembrete criado", content: { "application/json": { schema: { $ref: "#/components/schemas/Reminder" } } } }, "400": errorResponse("Campos inv\xE1lidos"), ...COMMON_ERRORS }
2108
+ }
2109
+ },
2110
+ "/reminders/{id}": {
2111
+ parameters: [{ name: "id", in: "path", required: true, schema: { type: "string", format: "uuid" } }],
2112
+ patch: {
2113
+ tags: ["Lembretes"],
2114
+ summary: "Atualizar / pausar lembrete",
2115
+ operationId: "updateReminder",
2116
+ security: [{ ApiKeyAuth: ["reminders:update"] }],
2117
+ requestBody: { required: true, content: { "application/json": { schema: { type: "object", properties: {
2118
+ title: { type: "string" },
2119
+ body: { type: "string" },
2120
+ params: { type: "object" },
2121
+ audience: { type: "array", items: { type: "string" } },
2122
+ channels: { type: "object" },
2123
+ recurrence_type: { type: "string", enum: ["once", "daily", "weekly", "monthly"] },
2124
+ run_time: { type: "string" },
2125
+ weekday: { type: "integer" },
2126
+ day_of_month: { type: "integer" },
2127
+ timezone: { type: "string" },
2128
+ start_date: { type: "string", format: "date" },
2129
+ end_date: { type: "string", format: "date" },
2130
+ active: { type: "boolean" }
2131
+ } } } } },
2132
+ responses: { "200": { description: "Atualizado", content: { "application/json": { schema: { $ref: "#/components/schemas/Reminder" } } } }, "400": errorResponse("Nada para atualizar"), "404": errorResponse("N\xE3o encontrado"), ...COMMON_ERRORS }
2133
+ },
2134
+ delete: {
2135
+ tags: ["Lembretes"],
2136
+ summary: "Excluir lembrete",
2137
+ operationId: "deleteReminder",
2138
+ security: [{ ApiKeyAuth: ["reminders:delete"] }],
2139
+ responses: { "204": { description: "Exclu\xEDdo" }, "404": errorResponse("N\xE3o encontrado"), ...COMMON_ERRORS }
1671
2140
  }
1672
2141
  },
1673
2142
  "/payment-conditions": {
@@ -1690,6 +2159,116 @@ var OPENAPI_SPEC = {
1690
2159
  responses: { "200": paginatedResponse("#/components/schemas/ServiceUnit"), ...COMMON_ERRORS }
1691
2160
  }
1692
2161
  },
2162
+ "/audit/timeline": {
2163
+ get: {
2164
+ tags: ["Auditoria"],
2165
+ summary: "Timeline de auditoria de uma entidade",
2166
+ operationId: "getAuditTimeline",
2167
+ description: "Retorna o hist\xF3rico de altera\xE7\xF5es (audit_logs) de uma entidade da empresa, mais recente primeiro.",
2168
+ security: [{ ApiKeyAuth: ["audit:read"] }],
2169
+ parameters: [
2170
+ { name: "entity_type", in: "query", required: true, schema: { type: "string" }, description: "Tipo da entidade (ex.: invoice, customer, contract)" },
2171
+ { name: "entity_id", in: "query", required: true, schema: { type: "string", format: "uuid" }, description: "ID da entidade" },
2172
+ { name: "limit", in: "query", schema: { type: "integer", minimum: 1, maximum: 30, default: 12 }, description: "M\xE1ximo de eventos (1\u201330)" }
2173
+ ],
2174
+ responses: {
2175
+ "200": {
2176
+ description: "Timeline da entidade",
2177
+ content: { "application/json": { schema: {
2178
+ type: "object",
2179
+ properties: {
2180
+ entity_type: { type: "string" },
2181
+ entity_id: { type: "string", format: "uuid" },
2182
+ entries: { type: "array", items: { type: "object", properties: {
2183
+ created_at: { type: "string", format: "date-time" },
2184
+ action: { type: "string" },
2185
+ description: { type: "string" },
2186
+ user_email: { type: "string" }
2187
+ } } }
2188
+ }
2189
+ } } }
2190
+ },
2191
+ ...COMMON_ERRORS
2192
+ }
2193
+ }
2194
+ },
2195
+ "/service-categories": {
2196
+ get: {
2197
+ tags: ["Servi\xE7os"],
2198
+ summary: "Listar categorias de servi\xE7o",
2199
+ operationId: "listServiceCategories",
2200
+ security: [{ ApiKeyAuth: ["services:read"] }],
2201
+ parameters: [...PAGINATION_PARAMS, { name: "search", in: "query", schema: { type: "string" }, description: "Filtro por nome (ilike)" }],
2202
+ responses: { "200": paginatedResponse("#/components/schemas/ServiceCategory"), ...COMMON_ERRORS }
2203
+ },
2204
+ post: {
2205
+ tags: ["Servi\xE7os"],
2206
+ summary: "Criar categoria(s) de servi\xE7o",
2207
+ operationId: "createServiceCategory",
2208
+ security: [{ ApiKeyAuth: ["services:write"] }],
2209
+ requestBody: { required: true, content: { "application/json": { schema: { type: "object", properties: {
2210
+ name: { type: "string", description: "Nome de uma categoria" },
2211
+ names: { type: "array", items: { type: "string" }, description: "Lista de nomes (cria v\xE1rias de uma vez)" },
2212
+ color: { type: "string", description: "Cor hex (default #6366f1)" }
2213
+ } } } } },
2214
+ responses: { "201": { description: "Categoria(s) criada(s)", content: { "application/json": { schema: { $ref: "#/components/schemas/ServiceCategory" } } } }, "400": errorResponse("Nome ausente"), "409": errorResponse("Categoria j\xE1 existe"), ...COMMON_ERRORS }
2215
+ }
2216
+ },
2217
+ "/service-categories/{id}": {
2218
+ parameters: [{ name: "id", in: "path", required: true, schema: { type: "string", format: "uuid" } }],
2219
+ patch: {
2220
+ tags: ["Servi\xE7os"],
2221
+ summary: "Atualizar categoria de servi\xE7o",
2222
+ operationId: "updateServiceCategory",
2223
+ security: [{ ApiKeyAuth: ["services:write"] }],
2224
+ requestBody: { required: true, content: { "application/json": { schema: { type: "object", properties: { name: { type: "string" }, color: { type: "string" } } } } } },
2225
+ responses: { "200": { description: "Atualizada", content: { "application/json": { schema: { $ref: "#/components/schemas/ServiceCategory" } } } }, "400": errorResponse("Nada para atualizar"), "404": errorResponse("N\xE3o encontrada"), "409": errorResponse("Nome duplicado"), ...COMMON_ERRORS }
2226
+ },
2227
+ delete: {
2228
+ tags: ["Servi\xE7os"],
2229
+ summary: "Excluir categoria de servi\xE7o",
2230
+ operationId: "deleteServiceCategory",
2231
+ security: [{ ApiKeyAuth: ["services:delete"] }],
2232
+ responses: { "204": { description: "Exclu\xEDda" }, "404": errorResponse("N\xE3o encontrada"), ...COMMON_ERRORS }
2233
+ }
2234
+ },
2235
+ "/reports/aging-actions": {
2236
+ get: {
2237
+ tags: ["Relat\xF3rios"],
2238
+ summary: "Aging de inadimpl\xEAncia com a\xE7\xF5es sugeridas",
2239
+ operationId: "reportAgingActions",
2240
+ security: [{ ApiKeyAuth: ["invoices:read", "finance:read"] }],
2241
+ parameters: [
2242
+ { name: "limit", in: "query", schema: { type: "integer", minimum: 1, maximum: 40, default: 12 } },
2243
+ { name: "min_overdue_days", in: "query", schema: { type: "integer", minimum: 1, maximum: 365, default: 1 } },
2244
+ { name: "include_shared", in: "query", schema: { type: "boolean", default: true }, description: "Incluir clientes compartilhados" },
2245
+ { name: "customer_id", in: "query", schema: { type: "string", format: "uuid" } },
2246
+ { name: "search", in: "query", schema: { type: "string" } }
2247
+ ],
2248
+ responses: { "200": { description: "Faturas em atraso + a\xE7\xF5es recomendadas", content: { "application/json": { schema: { type: "object", properties: {
2249
+ count: { type: "integer" },
2250
+ limit: { type: "integer" },
2251
+ min_overdue_days: { type: "integer" },
2252
+ total_overdue_amount: { type: "number" },
2253
+ actions: { type: "array", items: { type: "object" } }
2254
+ } } } } }, ...COMMON_ERRORS }
2255
+ }
2256
+ },
2257
+ "/reports/cashflow-forecast": {
2258
+ get: {
2259
+ tags: ["Relat\xF3rios"],
2260
+ summary: "Previs\xE3o de fluxo de caixa",
2261
+ operationId: "reportCashflowForecast",
2262
+ security: [{ ApiKeyAuth: ["finance:read"] }],
2263
+ parameters: [
2264
+ { name: "horizon_days", in: "query", schema: { type: "integer", minimum: 1, maximum: 120, default: 30 } },
2265
+ { name: "opening_balance", in: "query", schema: { type: "number", default: 0 } },
2266
+ { name: "include_receivables", in: "query", schema: { type: "boolean", default: true } },
2267
+ { name: "include_payables", in: "query", schema: { type: "boolean", default: true } }
2268
+ ],
2269
+ responses: { "200": { description: "Proje\xE7\xE3o di\xE1ria de caixa (timeline)", content: { "application/json": { schema: { type: "object" } } } }, ...COMMON_ERRORS }
2270
+ }
2271
+ },
1693
2272
  // -----------------------------------------------------------------------
1694
2273
  // NFS-e
1695
2274
  // -----------------------------------------------------------------------
@@ -1744,6 +2323,27 @@ var OPENAPI_SPEC = {
1744
2323
  }
1745
2324
  }
1746
2325
  },
2326
+ "/nfse/{id}/sync": {
2327
+ parameters: [{ name: "id", in: "path", required: true, schema: { type: "string", format: "uuid" } }],
2328
+ post: {
2329
+ tags: ["NFS-e"],
2330
+ summary: "Sincronizar status da NFS-e com o provedor",
2331
+ operationId: "syncNfse",
2332
+ security: [{ ApiKeyAuth: ["nfse:read"] }],
2333
+ responses: { "200": { description: "Resultado da sincroniza\xE7\xE3o", content: { "application/json": { schema: { type: "object", properties: { id: { type: "string" }, invoice_id: { type: "string" }, processed: { type: "integer" }, updated: { type: "integer" }, attached: { type: "integer" } } } } } }, "404": errorResponse("NFS-e n\xE3o encontrada"), "502": errorResponse("Erro do provedor de NFS-e"), ...COMMON_ERRORS }
2334
+ }
2335
+ },
2336
+ "/nfse/{id}/files": {
2337
+ parameters: [{ name: "id", in: "path", required: true, schema: { type: "string", format: "uuid" } }],
2338
+ get: {
2339
+ tags: ["NFS-e"],
2340
+ summary: "URLs assinadas do XML e DANFSE",
2341
+ operationId: "getNfseFiles",
2342
+ description: "Retorna URLs tempor\xE1rias (30 min) para download do XML e do PDF (DANFSE). Gera o PDF sob demanda se a nota estiver autorizada/cancelada.",
2343
+ security: [{ ApiKeyAuth: ["nfse:read"] }],
2344
+ responses: { "200": { description: "URLs assinadas", content: { "application/json": { schema: { type: "object", properties: { id: { type: "string" }, invoice_id: { type: "string" }, status: { type: "string" }, xml_signed_url: { type: ["string", "null"] }, danfse_signed_url: { type: ["string", "null"] }, signed_url_ttl_seconds: { type: "integer" } } } } } }, "404": errorResponse("NFS-e n\xE3o encontrada"), ...COMMON_ERRORS }
2345
+ }
2346
+ },
1747
2347
  // -----------------------------------------------------------------------
1748
2348
  // Fornecedores
1749
2349
  // -----------------------------------------------------------------------
@@ -1963,7 +2563,7 @@ var OPENAPI_SPEC = {
1963
2563
  parameters: [
1964
2564
  ...PAGINATION_PARAMS,
1965
2565
  { name: "status", in: "query", schema: { type: "string", enum: ["pending", "paid", "cancelled", "expired", "failed"] } },
1966
- { name: "method", in: "query", schema: { type: "string", enum: ["pix", "boleto", "checkout"] } },
2566
+ { name: "method", in: "query", schema: { type: "string", enum: ["pix", "boleto", "checkout", "credit_card"] } },
1967
2567
  { name: "customer_id", in: "query", schema: { type: "string", format: "uuid" } },
1968
2568
  { name: "invoice_id", in: "query", schema: { type: "string", format: "uuid" } }
1969
2569
  ],
@@ -1971,9 +2571,9 @@ var OPENAPI_SPEC = {
1971
2571
  },
1972
2572
  post: {
1973
2573
  tags: ["Cobran\xE7as"],
1974
- summary: "Criar cobran\xE7a (Pix, boleto ou checkout)",
2574
+ summary: "Criar cobran\xE7a (Pix, boleto, checkout ou cart\xE3o)",
1975
2575
  operationId: "createCharge",
1976
- description: "Gera uma cobran\xE7a no provider ativo da empresa (Inter ou C6 Bank). Forne\xE7a invoice_id ou customer_id+amount+due_date.",
2576
+ description: "Gera uma cobran\xE7a no provider ativo da empresa (Inter, C6 Bank, Pix Offline ou Pagar.me). Forne\xE7a invoice_id ou customer_id+amount+due_date. Com Pagar.me, method=pix retorna o copia-e-cola e method=credit_card retorna 'checkout.url' (link da p\xE1gina de pagamento pr\xF3pria).",
1977
2577
  security: [{ ApiKeyAuth: ["charges:create"] }],
1978
2578
  requestBody: { required: true, content: { "application/json": { schema: { $ref: "#/components/schemas/ChargeCreate" } } } },
1979
2579
  responses: {
@@ -2255,6 +2855,104 @@ var OPENAPI_SPEC = {
2255
2855
  }
2256
2856
  },
2257
2857
  // -----------------------------------------------------------------------
2858
+ // Split de Pagamentos (regras, execuções, repasses)
2859
+ // -----------------------------------------------------------------------
2860
+ "/split-rules": {
2861
+ get: {
2862
+ tags: ["Split de Pagamentos"],
2863
+ summary: "Listar regras de split",
2864
+ operationId: "listSplitRules",
2865
+ security: [{ ApiKeyAuth: ["split:list"] }],
2866
+ parameters: [
2867
+ ...PAGINATION_PARAMS,
2868
+ { name: "scope", in: "query", schema: { type: "string", enum: ["company_default", "contract", "invoice", "charge"] } }
2869
+ ],
2870
+ responses: { "200": paginatedResponse("#/components/schemas/SplitRule"), ...COMMON_ERRORS }
2871
+ },
2872
+ post: {
2873
+ tags: ["Split de Pagamentos"],
2874
+ summary: "Criar regra de split",
2875
+ operationId: "createSplitRule",
2876
+ description: "Cria uma regra de divis\xE3o com seus benefici\xE1rios (recipients). Percentual primeiro, depois fixo; soma de percentuais \u2264 100.",
2877
+ security: [{ ApiKeyAuth: ["split:create"] }],
2878
+ requestBody: { required: true, content: { "application/json": { schema: { $ref: "#/components/schemas/SplitRuleCreate" } } } },
2879
+ responses: { "201": { description: "Regra criada", content: { "application/json": { schema: { $ref: "#/components/schemas/SplitRule" } } } }, "400": errorResponse("Dados inv\xE1lidos"), ...COMMON_ERRORS }
2880
+ }
2881
+ },
2882
+ "/split-rules/{id}": {
2883
+ parameters: [{ name: "id", in: "path", required: true, schema: { type: "string", format: "uuid" } }],
2884
+ get: {
2885
+ tags: ["Split de Pagamentos"],
2886
+ summary: "Obter regra de split",
2887
+ operationId: "getSplitRule",
2888
+ security: [{ ApiKeyAuth: ["split:list"] }],
2889
+ responses: { "200": { description: "Regra", content: { "application/json": { schema: { $ref: "#/components/schemas/SplitRule" } } } }, "404": errorResponse("Regra n\xE3o encontrada"), ...COMMON_ERRORS }
2890
+ },
2891
+ patch: {
2892
+ tags: ["Split de Pagamentos"],
2893
+ summary: "Atualizar regra de split",
2894
+ operationId: "updateSplitRule",
2895
+ description: "Atualiza campos da regra. Se 'recipients' for enviado, substitui todos os benefici\xE1rios.",
2896
+ security: [{ ApiKeyAuth: ["split:update"] }],
2897
+ requestBody: { required: true, content: { "application/json": { schema: { $ref: "#/components/schemas/SplitRuleCreate" } } } },
2898
+ responses: { "200": { description: "Regra atualizada", content: { "application/json": { schema: { $ref: "#/components/schemas/SplitRule" } } } }, "404": errorResponse("Regra n\xE3o encontrada"), ...COMMON_ERRORS }
2899
+ },
2900
+ delete: {
2901
+ tags: ["Split de Pagamentos"],
2902
+ summary: "Excluir regra de split",
2903
+ operationId: "deleteSplitRule",
2904
+ security: [{ ApiKeyAuth: ["split:delete"] }],
2905
+ responses: { "200": { description: "Removida", content: { "application/json": { schema: { type: "object", properties: { deleted: { type: "boolean" }, id: { type: "string" } } } } } }, "404": errorResponse("Regra n\xE3o encontrada"), ...COMMON_ERRORS }
2906
+ }
2907
+ },
2908
+ "/split-executions": {
2909
+ get: {
2910
+ tags: ["Split de Pagamentos"],
2911
+ summary: "Listar execu\xE7\xF5es de split",
2912
+ operationId: "listSplitExecutions",
2913
+ security: [{ ApiKeyAuth: ["split:list"] }],
2914
+ parameters: [
2915
+ ...PAGINATION_PARAMS,
2916
+ { name: "status", in: "query", schema: { type: "string", enum: ["pending", "calculated", "releasing", "completed", "partial", "reversed", "failed"] } },
2917
+ { name: "invoice_id", in: "query", schema: { type: "string", format: "uuid" } },
2918
+ { name: "supplier_id", in: "query", schema: { type: "string", format: "uuid" }, description: "Filtra execu\xE7\xF5es que contenham fatia deste fornecedor" }
2919
+ ],
2920
+ responses: { "200": paginatedResponse("#/components/schemas/SplitExecution"), ...COMMON_ERRORS }
2921
+ }
2922
+ },
2923
+ "/split-executions/{id}": {
2924
+ parameters: [{ name: "id", in: "path", required: true, schema: { type: "string", format: "uuid" } }],
2925
+ get: {
2926
+ tags: ["Split de Pagamentos"],
2927
+ summary: "Obter execu\xE7\xE3o de split (com fatias)",
2928
+ operationId: "getSplitExecution",
2929
+ security: [{ ApiKeyAuth: ["split:list"] }],
2930
+ responses: { "200": { description: "Execu\xE7\xE3o", content: { "application/json": { schema: { $ref: "#/components/schemas/SplitExecution" } } } }, "404": errorResponse("Execu\xE7\xE3o n\xE3o encontrada"), ...COMMON_ERRORS }
2931
+ }
2932
+ },
2933
+ "/split-executions/{id}/reverse": {
2934
+ parameters: [{ name: "id", in: "path", required: true, schema: { type: "string", format: "uuid" } }],
2935
+ post: {
2936
+ tags: ["Split de Pagamentos"],
2937
+ summary: "Estornar execu\xE7\xE3o de split",
2938
+ operationId: "reverseSplitExecution",
2939
+ description: "Marca a execu\xE7\xE3o e suas fatias como 'reversed'. Para cada fatia de fornecedor j\xE1 paga, registra um ajuste de recupera\xE7\xE3o (o fornecedor deve devolver o valor).",
2940
+ security: [{ ApiKeyAuth: ["split:update"] }],
2941
+ responses: { "200": { description: "Estornada", content: { "application/json": { schema: { type: "object", properties: { execution_id: { type: "string" }, status: { type: "string" }, adjustments_created: { type: "integer" }, recover_amount_cents: { type: "integer" } } } } } }, "404": errorResponse("Execu\xE7\xE3o n\xE3o encontrada"), "409": errorResponse("J\xE1 estornada"), ...COMMON_ERRORS }
2942
+ }
2943
+ },
2944
+ "/split-items/{id}/release": {
2945
+ parameters: [{ name: "id", in: "path", required: true, schema: { type: "string", format: "uuid" } }],
2946
+ post: {
2947
+ tags: ["Split de Pagamentos"],
2948
+ summary: "Liberar fatia manualmente",
2949
+ operationId: "releaseSplitItem",
2950
+ description: "Libera uma fatia (pending/awaiting_nota/failed \u2192 released), apta a virar payout.",
2951
+ security: [{ ApiKeyAuth: ["split:update"] }],
2952
+ responses: { "200": { description: "Liberada", content: { "application/json": { schema: { type: "object", properties: { id: { type: "string" }, status: { type: "string" } } } } } }, "404": errorResponse("Fatia n\xE3o encontrada"), ...COMMON_ERRORS }
2953
+ }
2954
+ },
2955
+ // -----------------------------------------------------------------------
2258
2956
  // Formas de pagamento do fornecedor
2259
2957
  // -----------------------------------------------------------------------
2260
2958
  "/suppliers/{id}/payment-methods": {
@@ -2310,7 +3008,7 @@ var OPENAPI_SPEC = {
2310
3008
  ...PAGINATION_PARAMS,
2311
3009
  { name: "active", in: "query", schema: { type: "string", enum: ["true", "false"] } },
2312
3010
  { name: "provider", in: "query", schema: { type: "string", enum: ["inter", "c6bank"] } },
2313
- { name: "channel", in: "query", schema: { type: "string", enum: ["pix", "boleto", "checkout"] } }
3011
+ { name: "channel", in: "query", schema: { type: "string", enum: ["pix", "boleto", "checkout", "credit_card"] } }
2314
3012
  ],
2315
3013
  responses: { "200": paginatedResponse("#/components/schemas/PaymentMethod"), ...COMMON_ERRORS }
2316
3014
  }
@@ -2360,7 +3058,8 @@ var API_MODULES = [
2360
3058
  permissions: [
2361
3059
  { key: "read", label: "Listar e visualizar", description: "Consultar faturas e cobran\xE7as" },
2362
3060
  { key: "create", label: "Criar cobran\xE7a", description: "Gerar boletos, Pix e cobran\xE7as" },
2363
- { key: "cancel", label: "Cancelar cobran\xE7a", description: "Cancelar cobran\xE7as em aberto" }
3061
+ { key: "cancel", label: "Cancelar cobran\xE7a", description: "Cancelar cobran\xE7as em aberto" },
3062
+ { key: "delete", label: "Excluir fatura", description: "Excluir faturas permanentemente (itens e cobran\xE7as vinculadas)" }
2364
3063
  ]
2365
3064
  },
2366
3065
  {
@@ -2458,6 +3157,33 @@ var API_MODULES = [
2458
3157
  { key: "create", label: "Pagar / agendar", description: "Executar ou agendar pagamentos Pix e boleto a fornecedores" },
2459
3158
  { key: "cancel", label: "Cancelar agendamento", description: "Cancelar pagamentos agendados" }
2460
3159
  ]
3160
+ },
3161
+ {
3162
+ key: "split",
3163
+ label: "Split de Pagamentos",
3164
+ permissions: [
3165
+ { key: "list", label: "Listar e visualizar", description: "Consultar regras, execu\xE7\xF5es e repasses de split" },
3166
+ { key: "create", label: "Criar regra", description: "Criar regras de divis\xE3o de recebimentos" },
3167
+ { key: "update", label: "Atualizar / liberar", description: "Editar regras, liberar fatias e estornar repasses" },
3168
+ { key: "delete", label: "Excluir regra", description: "Remover regras de split" }
3169
+ ]
3170
+ },
3171
+ {
3172
+ key: "audit",
3173
+ label: "Auditoria",
3174
+ permissions: [
3175
+ { key: "read", label: "Consultar hist\xF3rico", description: "Consultar a timeline de altera\xE7\xF5es de uma entidade (audit_logs)" }
3176
+ ]
3177
+ },
3178
+ {
3179
+ key: "reminders",
3180
+ label: "Lembretes",
3181
+ permissions: [
3182
+ { key: "list", label: "Listar e visualizar", description: "Consultar lembretes e resumos agendados" },
3183
+ { key: "create", label: "Criar", description: "Criar lembretes e resumos recorrentes da empresa" },
3184
+ { key: "update", label: "Atualizar / pausar", description: "Editar, ativar e pausar lembretes" },
3185
+ { key: "delete", label: "Excluir", description: "Excluir lembretes" }
3186
+ ]
2461
3187
  }
2462
3188
  ];
2463
3189
  var ALL_SCOPES = API_MODULES.flatMap(
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@comando.one/mcp-server",
3
- "version": "0.1.0",
3
+ "version": "0.2.0",
4
4
  "description": "Servidor MCP (Model Context Protocol) para a API pública do Comando.One — opere seu ERP por linguagem natural.",
5
5
  "type": "module",
6
6
  "license": "MIT",