@comando.one/mcp-server 0.1.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.
- package/README.md +66 -0
- package/dist/index.js +2901 -0
- package/package.json +44 -0
package/dist/index.js
ADDED
|
@@ -0,0 +1,2901 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
// src/index.ts
|
|
4
|
+
import { readFileSync } from "fs";
|
|
5
|
+
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
|
|
6
|
+
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
7
|
+
import { CallToolRequestSchema, ListToolsRequestSchema } from "@modelcontextprotocol/sdk/types.js";
|
|
8
|
+
|
|
9
|
+
// src/comando-api.ts
|
|
10
|
+
var ComandoApiError = class extends Error {
|
|
11
|
+
status;
|
|
12
|
+
body;
|
|
13
|
+
constructor(status, body, method, path) {
|
|
14
|
+
const errMsg = body && typeof body === "object" && "error" in body ? String(body.error) : JSON.stringify(body);
|
|
15
|
+
super(`${method} ${path} \u2192 ${status}: ${errMsg}`);
|
|
16
|
+
this.name = "ComandoApiError";
|
|
17
|
+
this.status = status;
|
|
18
|
+
this.body = body;
|
|
19
|
+
}
|
|
20
|
+
};
|
|
21
|
+
function qs(params) {
|
|
22
|
+
if (!params) return "";
|
|
23
|
+
const u = new URLSearchParams();
|
|
24
|
+
for (const [k, v] of Object.entries(params)) {
|
|
25
|
+
if (v !== void 0 && v !== null && v !== "") u.set(k, String(v));
|
|
26
|
+
}
|
|
27
|
+
const s = u.toString();
|
|
28
|
+
return s ? `?${s}` : "";
|
|
29
|
+
}
|
|
30
|
+
var _autoCounter = 0;
|
|
31
|
+
function genIdemKey() {
|
|
32
|
+
try {
|
|
33
|
+
return `auto-${crypto.randomUUID()}`;
|
|
34
|
+
} catch {
|
|
35
|
+
return `auto-${Date.now()}-${_autoCounter++}`;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
var ComandoApi = class _ComandoApi {
|
|
39
|
+
apiKey;
|
|
40
|
+
baseUrl;
|
|
41
|
+
companyId;
|
|
42
|
+
autoIdempotency;
|
|
43
|
+
constructor({ apiKey, baseUrl = "https://api.comando.one/v1", companyId, autoIdempotency = false }) {
|
|
44
|
+
if (!apiKey) throw new Error("apiKey \xE9 obrigat\xF3rio (cmd_live_...).");
|
|
45
|
+
this.apiKey = apiKey;
|
|
46
|
+
this.baseUrl = baseUrl.replace(/\/+$/, "");
|
|
47
|
+
this.companyId = companyId || null;
|
|
48
|
+
this.autoIdempotency = autoIdempotency;
|
|
49
|
+
}
|
|
50
|
+
/** Clona o client fixando uma empresa (header X-Company-Id). */
|
|
51
|
+
withCompany(companyId) {
|
|
52
|
+
return new _ComandoApi({
|
|
53
|
+
apiKey: this.apiKey,
|
|
54
|
+
baseUrl: this.baseUrl,
|
|
55
|
+
companyId,
|
|
56
|
+
autoIdempotency: this.autoIdempotency
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
async request(method, path, opts = {}) {
|
|
60
|
+
const headers = {
|
|
61
|
+
"x-api-key": this.apiKey,
|
|
62
|
+
"Content-Type": "application/json"
|
|
63
|
+
};
|
|
64
|
+
const company = opts.companyId ?? this.companyId;
|
|
65
|
+
if (company) headers["X-Company-Id"] = company;
|
|
66
|
+
let idem = opts.idempotencyKey;
|
|
67
|
+
if (!idem && this.autoIdempotency && method === "POST") idem = genIdemKey();
|
|
68
|
+
if (idem) headers["Idempotency-Key"] = idem;
|
|
69
|
+
const init = { method, headers };
|
|
70
|
+
if (opts.body !== void 0) init.body = JSON.stringify(opts.body);
|
|
71
|
+
const res = await fetch(`${this.baseUrl}${path}`, init);
|
|
72
|
+
const text = await res.text();
|
|
73
|
+
let body = null;
|
|
74
|
+
try {
|
|
75
|
+
body = text ? JSON.parse(text) : null;
|
|
76
|
+
} catch {
|
|
77
|
+
body = { raw: text };
|
|
78
|
+
}
|
|
79
|
+
if (opts.raw) {
|
|
80
|
+
return { status: res.status, body, replayed: res.headers.get("idempotent-replayed") === "true" };
|
|
81
|
+
}
|
|
82
|
+
if (!res.ok) throw new ComandoApiError(res.status, body, method, path);
|
|
83
|
+
return body;
|
|
84
|
+
}
|
|
85
|
+
get(path, opts) {
|
|
86
|
+
return this.request("GET", path, opts);
|
|
87
|
+
}
|
|
88
|
+
post(path, body, opts) {
|
|
89
|
+
return this.request("POST", path, { ...opts, body });
|
|
90
|
+
}
|
|
91
|
+
patch(path, body, opts) {
|
|
92
|
+
return this.request("PATCH", path, { ...opts, body });
|
|
93
|
+
}
|
|
94
|
+
delete(path, opts) {
|
|
95
|
+
return this.request("DELETE", path, opts);
|
|
96
|
+
}
|
|
97
|
+
/** Paginação automática: itera ?page= até cobrir meta.total. Retorna array achatado. */
|
|
98
|
+
async listAll(path, params = {}, opts) {
|
|
99
|
+
const perPage = params.per_page ?? 100;
|
|
100
|
+
let page = 1;
|
|
101
|
+
let all = [];
|
|
102
|
+
let total = Infinity;
|
|
103
|
+
while (all.length < total) {
|
|
104
|
+
const r = await this.get(`${path}${qs({ ...params, page, per_page: perPage })}`, opts);
|
|
105
|
+
const data = r.data ?? [];
|
|
106
|
+
all = all.concat(data);
|
|
107
|
+
total = r.meta?.total ?? all.length;
|
|
108
|
+
if (data.length === 0) break;
|
|
109
|
+
page++;
|
|
110
|
+
if (page > 1e3) break;
|
|
111
|
+
}
|
|
112
|
+
return all;
|
|
113
|
+
}
|
|
114
|
+
me(opts) {
|
|
115
|
+
return this.get("/me", opts);
|
|
116
|
+
}
|
|
117
|
+
};
|
|
118
|
+
|
|
119
|
+
// src/manifest.ts
|
|
120
|
+
var MANIFEST = [
|
|
121
|
+
// ----- Identidade -----
|
|
122
|
+
{ operationId: "listCompanies", tool: "companies_list" },
|
|
123
|
+
// ----- Clientes -----
|
|
124
|
+
{ operationId: "listCustomers", tool: "customers_list" },
|
|
125
|
+
{ operationId: "getCustomer", tool: "customers_get" },
|
|
126
|
+
{ operationId: "createCustomer", tool: "customers_create", write: true },
|
|
127
|
+
{ operationId: "updateCustomer", tool: "customers_update", write: true },
|
|
128
|
+
{ operationId: "deleteCustomer", tool: "customers_delete", write: true, destructive: true },
|
|
129
|
+
{ operationId: "listCustomerInvoices", tool: "customers_list_invoices" },
|
|
130
|
+
{ operationId: "createCustomerAddress", tool: "customers_add_address", write: true },
|
|
131
|
+
{ operationId: "createCustomerContact", tool: "customers_add_contact", write: true },
|
|
132
|
+
// ----- Propostas -----
|
|
133
|
+
{ operationId: "listProposals", tool: "proposals_list" },
|
|
134
|
+
{ operationId: "getProposal", tool: "proposals_get" },
|
|
135
|
+
{ operationId: "createProposal", tool: "proposals_create", write: true },
|
|
136
|
+
{ operationId: "sendProposal", tool: "proposals_send", write: true },
|
|
137
|
+
// ----- Contratos -----
|
|
138
|
+
{ operationId: "listContracts", tool: "contracts_list" },
|
|
139
|
+
{ operationId: "getContract", tool: "contracts_get" },
|
|
140
|
+
{ operationId: "createContract", tool: "contracts_create", write: true },
|
|
141
|
+
// ----- Faturas -----
|
|
142
|
+
{ operationId: "listInvoices", tool: "invoices_list" },
|
|
143
|
+
{ operationId: "getInvoice", tool: "invoices_get" },
|
|
144
|
+
{ operationId: "createInvoice", tool: "invoices_create", write: true },
|
|
145
|
+
{ operationId: "cancelInvoice", tool: "invoices_cancel", write: true, destructive: true },
|
|
146
|
+
// ----- Cobranças -----
|
|
147
|
+
{ operationId: "listCharges", tool: "charges_list" },
|
|
148
|
+
{ operationId: "getCharge", tool: "charges_get" },
|
|
149
|
+
{ operationId: "createCharge", tool: "charges_create", write: true },
|
|
150
|
+
{ operationId: "confirmCharge", tool: "charges_confirm", write: true },
|
|
151
|
+
{ operationId: "cancelCharge", tool: "charges_cancel", write: true, destructive: true },
|
|
152
|
+
{ operationId: "refundCharge", tool: "charges_refund", write: true, destructive: true },
|
|
153
|
+
// ----- NFS-e -----
|
|
154
|
+
{ operationId: "listNfse", tool: "nfse_list" },
|
|
155
|
+
{ operationId: "getNfse", tool: "nfse_get" },
|
|
156
|
+
{ operationId: "emitNfse", tool: "nfse_emit", write: true },
|
|
157
|
+
{ operationId: "cancelNfse", tool: "nfse_cancel", write: true, destructive: true },
|
|
158
|
+
// ----- Pagamentos a fornecedor (payouts) -----
|
|
159
|
+
{ operationId: "listPayouts", tool: "payouts_list" },
|
|
160
|
+
{ operationId: "getPayout", tool: "payouts_get" },
|
|
161
|
+
{ operationId: "createPayout", tool: "payouts_create", write: true, destructive: true },
|
|
162
|
+
{ operationId: "cancelPayout", tool: "payouts_cancel", write: true, destructive: true },
|
|
163
|
+
// ----- Financeiro -----
|
|
164
|
+
{ operationId: "getFinanceLedger", tool: "finance_ledger" },
|
|
165
|
+
{ operationId: "createFinancialMovement", tool: "finance_create_movement", write: true },
|
|
166
|
+
// ----- Fornecedores -----
|
|
167
|
+
{ operationId: "listSuppliers", tool: "suppliers_list" },
|
|
168
|
+
{ operationId: "getSupplier", tool: "suppliers_get" },
|
|
169
|
+
{ operationId: "createSupplier", tool: "suppliers_create", write: true },
|
|
170
|
+
// ----- Contas a pagar -----
|
|
171
|
+
{ operationId: "listPurchaseInvoices", tool: "purchase_invoices_list" },
|
|
172
|
+
{ operationId: "getPurchaseInvoice", tool: "purchase_invoices_get" },
|
|
173
|
+
{ operationId: "createPurchaseInvoice", tool: "purchase_invoices_create", write: true },
|
|
174
|
+
{ operationId: "cancelPurchaseInvoice", tool: "purchase_invoices_cancel", write: true, destructive: true },
|
|
175
|
+
// ----- Despesas & Serviços -----
|
|
176
|
+
{ operationId: "listExpenses", tool: "expenses_list" },
|
|
177
|
+
{ operationId: "createExpense", tool: "expenses_create", write: true },
|
|
178
|
+
{ operationId: "listServices", tool: "services_list" },
|
|
179
|
+
{ operationId: "createService", tool: "services_create", write: true },
|
|
180
|
+
// ----- Webhooks -----
|
|
181
|
+
{ operationId: "listWebhooks", tool: "webhooks_list" },
|
|
182
|
+
{ operationId: "getWebhookById", tool: "webhooks_get" },
|
|
183
|
+
{ operationId: "createWebhook", tool: "webhooks_create", write: true }
|
|
184
|
+
];
|
|
185
|
+
|
|
186
|
+
// ../../src/lib/openApiSpec.ts
|
|
187
|
+
var PAGINATION_PARAMS = [
|
|
188
|
+
{
|
|
189
|
+
name: "page",
|
|
190
|
+
in: "query",
|
|
191
|
+
schema: { type: "integer", default: 1, minimum: 1 },
|
|
192
|
+
description: "N\xFAmero da p\xE1gina (default: 1)"
|
|
193
|
+
},
|
|
194
|
+
{
|
|
195
|
+
name: "per_page",
|
|
196
|
+
in: "query",
|
|
197
|
+
schema: { type: "integer", default: 20, minimum: 1, maximum: 100 },
|
|
198
|
+
description: "Itens por p\xE1gina (default: 20, m\xE1x: 100)"
|
|
199
|
+
}
|
|
200
|
+
];
|
|
201
|
+
var API_KEY_SECURITY = [{ ApiKeyAuth: [] }];
|
|
202
|
+
var WEBHOOK_EVENT_KEYS = [
|
|
203
|
+
"charge.paid",
|
|
204
|
+
"charge.cancelled",
|
|
205
|
+
"charge.expired",
|
|
206
|
+
"charge.failed",
|
|
207
|
+
"charge.refunded",
|
|
208
|
+
"payout.completed",
|
|
209
|
+
"payout.failed",
|
|
210
|
+
"payout.scheduled",
|
|
211
|
+
"payout.cancelled",
|
|
212
|
+
"invoice.created",
|
|
213
|
+
"invoice.paid",
|
|
214
|
+
"invoice.cancelled",
|
|
215
|
+
"proposal.created",
|
|
216
|
+
"proposal.sent",
|
|
217
|
+
"proposal.accepted",
|
|
218
|
+
"proposal.rejected",
|
|
219
|
+
"contract.created",
|
|
220
|
+
"contract.cancelled",
|
|
221
|
+
"contract.finished",
|
|
222
|
+
"nfse.issued",
|
|
223
|
+
"nfse.rejected",
|
|
224
|
+
"nfse.cancelled",
|
|
225
|
+
"purchase_invoice.created",
|
|
226
|
+
"purchase_invoice.paid",
|
|
227
|
+
"expense.paid",
|
|
228
|
+
"customer.created",
|
|
229
|
+
"customer.updated",
|
|
230
|
+
"customer.deleted",
|
|
231
|
+
"supplier.created",
|
|
232
|
+
"supplier.updated",
|
|
233
|
+
"supplier.deleted"
|
|
234
|
+
];
|
|
235
|
+
var SCHEMAS = {
|
|
236
|
+
Error: {
|
|
237
|
+
type: "object",
|
|
238
|
+
required: ["error"],
|
|
239
|
+
properties: {
|
|
240
|
+
error: { type: "string", description: "Descri\xE7\xE3o do erro" }
|
|
241
|
+
}
|
|
242
|
+
},
|
|
243
|
+
PaginatedMeta: {
|
|
244
|
+
type: "object",
|
|
245
|
+
required: ["page", "per_page", "total"],
|
|
246
|
+
properties: {
|
|
247
|
+
page: { type: "integer", description: "P\xE1gina atual" },
|
|
248
|
+
per_page: { type: "integer", description: "Itens por p\xE1gina" },
|
|
249
|
+
total: { type: "integer", description: "Total de itens" }
|
|
250
|
+
}
|
|
251
|
+
},
|
|
252
|
+
Customer: {
|
|
253
|
+
type: "object",
|
|
254
|
+
properties: {
|
|
255
|
+
id: { type: "string", format: "uuid" },
|
|
256
|
+
name: { type: "string" },
|
|
257
|
+
email: { type: ["string", "null"] },
|
|
258
|
+
phone: { type: ["string", "null"] },
|
|
259
|
+
document: { type: ["string", "null"], description: "CPF ou CNPJ" },
|
|
260
|
+
type: { type: "string", enum: ["fisica", "juridica", "estrangeira"] },
|
|
261
|
+
company_name: { type: ["string", "null"] },
|
|
262
|
+
trade_name: { type: ["string", "null"] },
|
|
263
|
+
status: { type: "string" },
|
|
264
|
+
created_at: { type: "string", format: "date-time" },
|
|
265
|
+
updated_at: { type: "string", format: "date-time" }
|
|
266
|
+
}
|
|
267
|
+
},
|
|
268
|
+
CustomerCreate: {
|
|
269
|
+
type: "object",
|
|
270
|
+
required: ["name"],
|
|
271
|
+
properties: {
|
|
272
|
+
name: { type: "string" },
|
|
273
|
+
email: { type: "string" },
|
|
274
|
+
phone: { type: "string" },
|
|
275
|
+
document: { type: "string" },
|
|
276
|
+
type: { type: "string", enum: ["fisica", "juridica", "estrangeira"], default: "fisica" },
|
|
277
|
+
company_name: { type: "string" },
|
|
278
|
+
trade_name: { type: "string" },
|
|
279
|
+
status: { type: "string", default: "ativo" }
|
|
280
|
+
}
|
|
281
|
+
},
|
|
282
|
+
CustomerUpdate: {
|
|
283
|
+
type: "object",
|
|
284
|
+
properties: {
|
|
285
|
+
name: { type: "string" },
|
|
286
|
+
email: { type: ["string", "null"] },
|
|
287
|
+
phone: { type: ["string", "null"] },
|
|
288
|
+
document: { type: ["string", "null"] },
|
|
289
|
+
type: { type: "string", enum: ["fisica", "juridica", "estrangeira"] },
|
|
290
|
+
company_name: { type: ["string", "null"] },
|
|
291
|
+
trade_name: { type: ["string", "null"] },
|
|
292
|
+
status: { type: "string" }
|
|
293
|
+
}
|
|
294
|
+
},
|
|
295
|
+
ProposalItem: {
|
|
296
|
+
type: "object",
|
|
297
|
+
properties: {
|
|
298
|
+
id: { type: "string", format: "uuid" },
|
|
299
|
+
name: { type: "string" },
|
|
300
|
+
description: { type: ["string", "null"] },
|
|
301
|
+
unit: { type: ["string", "null"] },
|
|
302
|
+
quantity: { type: "number" },
|
|
303
|
+
unit_price: { type: "number" },
|
|
304
|
+
subtotal: { type: "number" }
|
|
305
|
+
}
|
|
306
|
+
},
|
|
307
|
+
Proposal: {
|
|
308
|
+
type: "object",
|
|
309
|
+
properties: {
|
|
310
|
+
id: { type: "string", format: "uuid" },
|
|
311
|
+
customer_id: { type: "string", format: "uuid" },
|
|
312
|
+
customers: { type: "object", properties: { name: { type: "string" } } },
|
|
313
|
+
status: { type: "string", enum: ["rascunho", "enviada", "aceita", "recusada", "cancelada", "faturada"] },
|
|
314
|
+
total_amount: { type: "number" },
|
|
315
|
+
valid_until: { type: ["string", "null"], format: "date" },
|
|
316
|
+
notes: { type: ["string", "null"] },
|
|
317
|
+
created_at: { type: "string", format: "date-time" },
|
|
318
|
+
updated_at: { type: "string", format: "date-time" }
|
|
319
|
+
}
|
|
320
|
+
},
|
|
321
|
+
ProposalDetail: {
|
|
322
|
+
allOf: [
|
|
323
|
+
{ $ref: "#/components/schemas/Proposal" },
|
|
324
|
+
{
|
|
325
|
+
type: "object",
|
|
326
|
+
properties: {
|
|
327
|
+
proposal_items: { type: "array", items: { $ref: "#/components/schemas/ProposalItem" } }
|
|
328
|
+
}
|
|
329
|
+
}
|
|
330
|
+
]
|
|
331
|
+
},
|
|
332
|
+
ContractItem: {
|
|
333
|
+
type: "object",
|
|
334
|
+
properties: {
|
|
335
|
+
id: { type: "string", format: "uuid" },
|
|
336
|
+
name: { type: "string" },
|
|
337
|
+
description: { type: ["string", "null"] },
|
|
338
|
+
unit: { type: ["string", "null"] },
|
|
339
|
+
quantity: { type: "number" },
|
|
340
|
+
unit_price: { type: "number" },
|
|
341
|
+
subtotal: { type: "number" }
|
|
342
|
+
}
|
|
343
|
+
},
|
|
344
|
+
ContractSection: {
|
|
345
|
+
type: "object",
|
|
346
|
+
properties: {
|
|
347
|
+
title: { type: "string" },
|
|
348
|
+
content: { type: "string" }
|
|
349
|
+
}
|
|
350
|
+
},
|
|
351
|
+
Contract: {
|
|
352
|
+
type: "object",
|
|
353
|
+
properties: {
|
|
354
|
+
id: { type: "string", format: "uuid" },
|
|
355
|
+
customer_id: { type: "string", format: "uuid" },
|
|
356
|
+
customers: { type: "object", properties: { name: { type: "string" } } },
|
|
357
|
+
title: { type: ["string", "null"] },
|
|
358
|
+
status: { type: "string", enum: ["ativo", "suspenso", "cancelado", "finalizado"] },
|
|
359
|
+
frequency: { type: "string", enum: ["semanal", "quinzenal", "mensal", "bimestral", "trimestral", "semestral", "anual"] },
|
|
360
|
+
start_date: { type: "string", format: "date" },
|
|
361
|
+
end_date: { type: ["string", "null"], format: "date" },
|
|
362
|
+
amount: { type: "number" },
|
|
363
|
+
due_days: { type: "integer" },
|
|
364
|
+
next_generation_date: { type: ["string", "null"], format: "date" },
|
|
365
|
+
notes: { type: ["string", "null"] },
|
|
366
|
+
created_at: { type: "string", format: "date-time" },
|
|
367
|
+
updated_at: { type: "string", format: "date-time" }
|
|
368
|
+
}
|
|
369
|
+
},
|
|
370
|
+
ContractDetail: {
|
|
371
|
+
allOf: [
|
|
372
|
+
{ $ref: "#/components/schemas/Contract" },
|
|
373
|
+
{
|
|
374
|
+
type: "object",
|
|
375
|
+
properties: {
|
|
376
|
+
contract_items: { type: "array", items: { $ref: "#/components/schemas/ContractItem" } },
|
|
377
|
+
contract_sections: { type: ["array", "null"], items: { $ref: "#/components/schemas/ContractSection" } }
|
|
378
|
+
}
|
|
379
|
+
}
|
|
380
|
+
]
|
|
381
|
+
},
|
|
382
|
+
ProposalCreate: {
|
|
383
|
+
type: "object",
|
|
384
|
+
required: ["customer_id"],
|
|
385
|
+
properties: {
|
|
386
|
+
customer_id: { type: "string", format: "uuid" },
|
|
387
|
+
status: { type: "string", enum: ["rascunho", "enviada", "aceita", "recusada", "cancelada"], default: "rascunho" },
|
|
388
|
+
total_amount: { type: "number" },
|
|
389
|
+
valid_until: { type: "string", format: "date" },
|
|
390
|
+
notes: { type: "string" }
|
|
391
|
+
}
|
|
392
|
+
},
|
|
393
|
+
ContractCreate: {
|
|
394
|
+
type: "object",
|
|
395
|
+
required: ["customer_id"],
|
|
396
|
+
properties: {
|
|
397
|
+
customer_id: { type: "string", format: "uuid" },
|
|
398
|
+
title: { type: "string" },
|
|
399
|
+
status: { type: "string", enum: ["ativo", "suspenso", "cancelado", "finalizado"], default: "ativo" },
|
|
400
|
+
frequency: { type: "string", enum: ["semanal", "quinzenal", "mensal", "bimestral", "trimestral", "semestral", "anual"], default: "mensal" },
|
|
401
|
+
start_date: { type: "string", format: "date" },
|
|
402
|
+
end_date: { type: "string", format: "date" },
|
|
403
|
+
due_days: { type: "integer", default: 10 },
|
|
404
|
+
amount: { type: "number" },
|
|
405
|
+
payment_method_id: { type: "string", format: "uuid" },
|
|
406
|
+
notes: { type: "string" }
|
|
407
|
+
}
|
|
408
|
+
},
|
|
409
|
+
InvoiceItem: {
|
|
410
|
+
type: "object",
|
|
411
|
+
properties: {
|
|
412
|
+
id: { type: "string", format: "uuid" },
|
|
413
|
+
service_id: { type: ["string", "null"], format: "uuid", description: "Servi\xE7o vinculado (null se item avulso)." },
|
|
414
|
+
name: { type: "string" },
|
|
415
|
+
description: { type: ["string", "null"] },
|
|
416
|
+
unit: { type: ["string", "null"] },
|
|
417
|
+
quantity: { type: "number" },
|
|
418
|
+
unit_price: { type: "number" },
|
|
419
|
+
subtotal: { type: "number" },
|
|
420
|
+
is_manual: { type: "boolean", description: "true = item avulso; false = vindo de um servi\xE7o cadastrado." }
|
|
421
|
+
}
|
|
422
|
+
},
|
|
423
|
+
InvoiceCharge: {
|
|
424
|
+
type: "object",
|
|
425
|
+
properties: {
|
|
426
|
+
id: { type: "string", format: "uuid" },
|
|
427
|
+
due_date: { type: "string", format: "date" },
|
|
428
|
+
amount: { type: "number" },
|
|
429
|
+
payment_status: { type: "string" }
|
|
430
|
+
}
|
|
431
|
+
},
|
|
432
|
+
Invoice: {
|
|
433
|
+
type: "object",
|
|
434
|
+
properties: {
|
|
435
|
+
id: { type: "string", format: "uuid" },
|
|
436
|
+
customer_id: { type: "string", format: "uuid" },
|
|
437
|
+
customers: { type: "object", properties: { name: { type: "string" }, legal_name: { type: ["string", "null"] } } },
|
|
438
|
+
invoice_number: { type: ["string", "null"] },
|
|
439
|
+
title: { type: ["string", "null"] },
|
|
440
|
+
amount: { type: "number" },
|
|
441
|
+
status: { type: "string", enum: ["rascunho", "enviada", "aceita", "cancelada"] },
|
|
442
|
+
payment_status: { type: "string", enum: ["pendente", "parcial", "pago", "vencido"] },
|
|
443
|
+
due_date: { type: ["string", "null"], format: "date" },
|
|
444
|
+
proposal_id: { type: ["string", "null"], format: "uuid" },
|
|
445
|
+
contract_id: { type: ["string", "null"], format: "uuid" },
|
|
446
|
+
created_at: { type: "string", format: "date-time" },
|
|
447
|
+
updated_at: { type: "string", format: "date-time" }
|
|
448
|
+
}
|
|
449
|
+
},
|
|
450
|
+
InvoiceDetail: {
|
|
451
|
+
allOf: [
|
|
452
|
+
{ $ref: "#/components/schemas/Invoice" },
|
|
453
|
+
{
|
|
454
|
+
type: "object",
|
|
455
|
+
properties: {
|
|
456
|
+
invoice_items: { type: "array", items: { $ref: "#/components/schemas/InvoiceItem" } },
|
|
457
|
+
invoice_charges: { type: "array", items: { $ref: "#/components/schemas/InvoiceCharge" } }
|
|
458
|
+
}
|
|
459
|
+
}
|
|
460
|
+
]
|
|
461
|
+
},
|
|
462
|
+
FinanceLedgerEntry: {
|
|
463
|
+
type: "object",
|
|
464
|
+
properties: {
|
|
465
|
+
origin_id: { type: "string", format: "uuid" },
|
|
466
|
+
origin: { type: "string", enum: ["payment", "supplier_payment", "expense", "financial_movement"] },
|
|
467
|
+
direction: { type: "string", enum: ["entrada", "saida"] },
|
|
468
|
+
entry_date: { type: "string", format: "date" },
|
|
469
|
+
amount: { type: "number" },
|
|
470
|
+
signed_amount: { type: "number" },
|
|
471
|
+
counterparty_name: { type: ["string", "null"] },
|
|
472
|
+
description: { type: ["string", "null"] },
|
|
473
|
+
document_numbers: { type: ["string", "null"] },
|
|
474
|
+
bank_account_name: { type: ["string", "null"] },
|
|
475
|
+
payment_method_name: { type: ["string", "null"] },
|
|
476
|
+
created_at: { type: "string", format: "date-time" }
|
|
477
|
+
}
|
|
478
|
+
},
|
|
479
|
+
NfseHistory: {
|
|
480
|
+
type: "object",
|
|
481
|
+
properties: {
|
|
482
|
+
id: { type: "string", format: "uuid" },
|
|
483
|
+
invoice_id: { type: "string", format: "uuid" },
|
|
484
|
+
invoice_number: { type: ["string", "null"] },
|
|
485
|
+
numero_nfse: { type: ["string", "null"] },
|
|
486
|
+
status: { type: "string", enum: ["rascunho", "transmitindo", "autorizada", "rejeitada", "cancelada"] },
|
|
487
|
+
protocolo: { type: ["string", "null"] },
|
|
488
|
+
chave_acesso: { type: ["string", "null"] },
|
|
489
|
+
danfse_url: { type: ["string", "null"] },
|
|
490
|
+
artifact_source: { type: ["string", "null"] },
|
|
491
|
+
cancelada_at: { type: ["string", "null"], format: "date-time" },
|
|
492
|
+
created_at: { type: "string", format: "date-time" }
|
|
493
|
+
}
|
|
494
|
+
},
|
|
495
|
+
NfseHistoryDetail: {
|
|
496
|
+
allOf: [
|
|
497
|
+
{ $ref: "#/components/schemas/NfseHistory" },
|
|
498
|
+
{
|
|
499
|
+
type: "object",
|
|
500
|
+
properties: {
|
|
501
|
+
cancel_motivo: { type: ["integer", "null"] },
|
|
502
|
+
cancel_justificativa: { type: ["string", "null"] },
|
|
503
|
+
cancel_protocolo: { type: ["string", "null"] },
|
|
504
|
+
updated_at: { type: "string", format: "date-time" }
|
|
505
|
+
}
|
|
506
|
+
}
|
|
507
|
+
]
|
|
508
|
+
},
|
|
509
|
+
Supplier: {
|
|
510
|
+
type: "object",
|
|
511
|
+
properties: {
|
|
512
|
+
id: { type: "string", format: "uuid" },
|
|
513
|
+
name: { type: "string" },
|
|
514
|
+
email: { type: ["string", "null"] },
|
|
515
|
+
phone: { type: ["string", "null"] },
|
|
516
|
+
document: { type: ["string", "null"], description: "CPF ou CNPJ" },
|
|
517
|
+
type: { type: "string", enum: ["fisica", "juridica", "estrangeira"] },
|
|
518
|
+
company_name: { type: ["string", "null"] },
|
|
519
|
+
trade_name: { type: ["string", "null"] },
|
|
520
|
+
state_registration: { type: ["string", "null"] },
|
|
521
|
+
municipal_registration: { type: ["string", "null"] },
|
|
522
|
+
payment_terms_label: { type: ["string", "null"] },
|
|
523
|
+
payment_terms_days: { type: ["integer", "null"] },
|
|
524
|
+
status: { type: "string", enum: ["ativo", "inativo"] },
|
|
525
|
+
notes: { type: ["string", "null"] },
|
|
526
|
+
created_at: { type: "string", format: "date-time" },
|
|
527
|
+
updated_at: { type: "string", format: "date-time" }
|
|
528
|
+
}
|
|
529
|
+
},
|
|
530
|
+
SupplierCreate: {
|
|
531
|
+
type: "object",
|
|
532
|
+
required: ["name"],
|
|
533
|
+
properties: {
|
|
534
|
+
name: { type: "string" },
|
|
535
|
+
email: { type: "string" },
|
|
536
|
+
phone: { type: "string" },
|
|
537
|
+
document: { type: "string" },
|
|
538
|
+
type: { type: "string", enum: ["fisica", "juridica", "estrangeira"], default: "juridica" },
|
|
539
|
+
company_name: { type: "string" },
|
|
540
|
+
trade_name: { type: "string" },
|
|
541
|
+
state_registration: { type: "string" },
|
|
542
|
+
municipal_registration: { type: "string" },
|
|
543
|
+
payment_terms_label: { type: "string" },
|
|
544
|
+
payment_terms_days: { type: "integer" },
|
|
545
|
+
status: { type: "string", enum: ["ativo", "inativo"], default: "ativo" },
|
|
546
|
+
notes: { type: "string" }
|
|
547
|
+
}
|
|
548
|
+
},
|
|
549
|
+
Service: {
|
|
550
|
+
type: "object",
|
|
551
|
+
properties: {
|
|
552
|
+
id: { type: "string", format: "uuid" },
|
|
553
|
+
name: { type: "string" },
|
|
554
|
+
description: { type: ["string", "null"] },
|
|
555
|
+
price: { type: "number" },
|
|
556
|
+
unit: { type: "string", description: "Unidade (texto livre, ex: hora, unidade, mensal)" },
|
|
557
|
+
item_type: { type: "string", enum: ["venda", "compra", "ambos"] },
|
|
558
|
+
categories: { type: "array", items: { type: "string" } },
|
|
559
|
+
active: { type: "boolean" },
|
|
560
|
+
created_at: { type: "string", format: "date-time" },
|
|
561
|
+
updated_at: { type: "string", format: "date-time" }
|
|
562
|
+
}
|
|
563
|
+
},
|
|
564
|
+
ServiceCreate: {
|
|
565
|
+
type: "object",
|
|
566
|
+
required: ["name", "price"],
|
|
567
|
+
properties: {
|
|
568
|
+
name: { type: "string" },
|
|
569
|
+
description: { type: "string" },
|
|
570
|
+
price: { type: "number" },
|
|
571
|
+
unit: { type: "string", default: "hora" },
|
|
572
|
+
item_type: { type: "string", enum: ["venda", "compra", "ambos"], default: "venda" },
|
|
573
|
+
categories: { type: "array", items: { type: "string" } },
|
|
574
|
+
active: { type: "boolean", default: true }
|
|
575
|
+
}
|
|
576
|
+
},
|
|
577
|
+
Expense: {
|
|
578
|
+
type: "object",
|
|
579
|
+
properties: {
|
|
580
|
+
id: { type: "string", format: "uuid" },
|
|
581
|
+
supplier_id: { type: "string", format: "uuid" },
|
|
582
|
+
description: { type: "string" },
|
|
583
|
+
amount: { type: "number" },
|
|
584
|
+
expense_date: { type: "string", format: "date" },
|
|
585
|
+
payment_date: { type: ["string", "null"], format: "date" },
|
|
586
|
+
category_id: { type: ["string", "null"], format: "uuid" },
|
|
587
|
+
status: { type: "string", enum: ["pendente", "pago", "cancelado"] },
|
|
588
|
+
bank_account_id: { type: ["string", "null"], format: "uuid" },
|
|
589
|
+
payment_method_id: { type: ["string", "null"], format: "uuid" },
|
|
590
|
+
notes: { type: ["string", "null"] },
|
|
591
|
+
created_at: { type: "string", format: "date-time" },
|
|
592
|
+
updated_at: { type: "string", format: "date-time" }
|
|
593
|
+
}
|
|
594
|
+
},
|
|
595
|
+
ExpenseCreate: {
|
|
596
|
+
type: "object",
|
|
597
|
+
required: ["supplier_id", "description", "amount", "expense_date"],
|
|
598
|
+
properties: {
|
|
599
|
+
supplier_id: { type: "string", format: "uuid" },
|
|
600
|
+
description: { type: "string" },
|
|
601
|
+
amount: { type: "number" },
|
|
602
|
+
expense_date: { type: "string", format: "date" },
|
|
603
|
+
payment_date: { type: "string", format: "date" },
|
|
604
|
+
category_id: { type: "string", format: "uuid" },
|
|
605
|
+
status: { type: "string", enum: ["pendente", "pago", "cancelado"], default: "pendente" },
|
|
606
|
+
bank_account_id: { type: "string", format: "uuid" },
|
|
607
|
+
payment_method_id: { type: "string", format: "uuid" },
|
|
608
|
+
notes: { type: "string" }
|
|
609
|
+
}
|
|
610
|
+
},
|
|
611
|
+
PurchaseInvoice: {
|
|
612
|
+
type: "object",
|
|
613
|
+
properties: {
|
|
614
|
+
id: { type: "string", format: "uuid" },
|
|
615
|
+
supplier_id: { type: "string", format: "uuid" },
|
|
616
|
+
status: { type: "string", enum: ["rascunho", "recebida", "aprovada", "cancelada"] },
|
|
617
|
+
payment_status: { type: "string", enum: ["pendente", "parcial", "pago", "vencido"] },
|
|
618
|
+
invoice_number: { type: ["string", "null"] },
|
|
619
|
+
amount: { type: "number" },
|
|
620
|
+
issue_date: { type: ["string", "null"], format: "date" },
|
|
621
|
+
notes: { type: ["string", "null"] },
|
|
622
|
+
created_at: { type: "string", format: "date-time" },
|
|
623
|
+
updated_at: { type: "string", format: "date-time" },
|
|
624
|
+
purchase_invoice_charges: {
|
|
625
|
+
type: "array",
|
|
626
|
+
description: "Parcelas a pagar (o vencimento mora aqui, n\xE3o na fatura).",
|
|
627
|
+
items: {
|
|
628
|
+
type: "object",
|
|
629
|
+
properties: {
|
|
630
|
+
id: { type: "string", format: "uuid" },
|
|
631
|
+
sequence: { type: "integer" },
|
|
632
|
+
description: { type: "string" },
|
|
633
|
+
amount: { type: "number" },
|
|
634
|
+
due_date: { type: "string", format: "date" },
|
|
635
|
+
payment_status: { type: "string", enum: ["pendente", "parcial", "pago", "vencido"] }
|
|
636
|
+
}
|
|
637
|
+
}
|
|
638
|
+
}
|
|
639
|
+
}
|
|
640
|
+
},
|
|
641
|
+
PurchaseInvoiceCreate: {
|
|
642
|
+
type: "object",
|
|
643
|
+
required: ["supplier_id"],
|
|
644
|
+
properties: {
|
|
645
|
+
supplier_id: { type: "string", format: "uuid" },
|
|
646
|
+
status: { type: "string", enum: ["rascunho", "recebida", "aprovada", "cancelada"], default: "recebida" },
|
|
647
|
+
payment_status: { type: "string", enum: ["pendente", "parcial", "pago", "vencido"], default: "pendente" },
|
|
648
|
+
invoice_number: { type: "string" },
|
|
649
|
+
amount: { type: "number" },
|
|
650
|
+
issue_date: { type: "string", format: "date" },
|
|
651
|
+
due_date: { type: "string", format: "date", description: "Atalho: cria uma \xFAnica parcela com este vencimento e o valor de 'amount'. Ignorado se 'charges' for informado." },
|
|
652
|
+
charges: {
|
|
653
|
+
type: "array",
|
|
654
|
+
description: "Parcelas a pagar. Cada uma exige 'due_date'.",
|
|
655
|
+
items: {
|
|
656
|
+
type: "object",
|
|
657
|
+
required: ["due_date"],
|
|
658
|
+
properties: {
|
|
659
|
+
sequence: { type: "integer" },
|
|
660
|
+
description: { type: "string" },
|
|
661
|
+
amount: { type: "number" },
|
|
662
|
+
due_date: { type: "string", format: "date" },
|
|
663
|
+
payment_status: { type: "string", enum: ["pendente", "parcial", "pago", "vencido"], default: "pendente" }
|
|
664
|
+
}
|
|
665
|
+
}
|
|
666
|
+
},
|
|
667
|
+
notes: { type: "string" }
|
|
668
|
+
}
|
|
669
|
+
},
|
|
670
|
+
Charge: {
|
|
671
|
+
type: "object",
|
|
672
|
+
description: "Cobran\xE7a normalizada (independente do provider).",
|
|
673
|
+
properties: {
|
|
674
|
+
id: { type: "string", format: "uuid" },
|
|
675
|
+
status: { type: "string", enum: ["pending", "paid", "cancelled", "expired", "failed"] },
|
|
676
|
+
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)." },
|
|
679
|
+
invoice_id: { type: ["string", "null"], format: "uuid" },
|
|
680
|
+
customer_id: { type: ["string", "null"], format: "uuid" },
|
|
681
|
+
amount: { type: ["number", "null"] },
|
|
682
|
+
due_date: { type: ["string", "null"], format: "date" },
|
|
683
|
+
pix: { type: ["object", "null"], properties: { qr_code: { type: ["string", "null"] }, qr_url: { type: ["string", "null"] }, txid: { type: ["string", "null"] } } },
|
|
684
|
+
boleto: { type: ["object", "null"], properties: { digitable_line: { type: ["string", "null"] }, pdf_url: { type: ["string", "null"] } } },
|
|
685
|
+
checkout: { type: ["object", "null"], properties: { url: { type: ["string", "null"] } } },
|
|
686
|
+
created_at: { type: "string", format: "date-time" },
|
|
687
|
+
updated_at: { type: "string", format: "date-time" }
|
|
688
|
+
}
|
|
689
|
+
},
|
|
690
|
+
ChargeCreate: {
|
|
691
|
+
type: "object",
|
|
692
|
+
required: ["method"],
|
|
693
|
+
properties: {
|
|
694
|
+
method: { type: "string", enum: ["pix", "boleto", "checkout"], description: "Canal de pagamento" },
|
|
695
|
+
invoice_id: { type: "string", format: "uuid", description: "Fatura existente (opcional)" },
|
|
696
|
+
customer_id: { type: "string", format: "uuid", description: "Obrigat\xF3rio se invoice_id omitido" },
|
|
697
|
+
amount: { type: "number", description: "Obrigat\xF3rio se invoice_id omitido" },
|
|
698
|
+
due_date: { type: "string", format: "date", description: "Obrigat\xF3rio se invoice_id omitido" },
|
|
699
|
+
description: { type: "string" }
|
|
700
|
+
}
|
|
701
|
+
},
|
|
702
|
+
Webhook: {
|
|
703
|
+
type: "object",
|
|
704
|
+
properties: {
|
|
705
|
+
id: { type: "string", format: "uuid" },
|
|
706
|
+
name: { type: ["string", "null"], description: "R\xF3tulo opcional do webhook" },
|
|
707
|
+
url: { type: "string", format: "uri" },
|
|
708
|
+
events: { type: "array", items: { type: "string", enum: WEBHOOK_EVENT_KEYS } },
|
|
709
|
+
active: { type: "boolean" },
|
|
710
|
+
created_at: { type: "string", format: "date-time" },
|
|
711
|
+
updated_at: { type: "string", format: "date-time" }
|
|
712
|
+
}
|
|
713
|
+
},
|
|
714
|
+
WebhookCreate: {
|
|
715
|
+
type: "object",
|
|
716
|
+
required: ["url"],
|
|
717
|
+
properties: {
|
|
718
|
+
name: { type: "string", description: "R\xF3tulo opcional" },
|
|
719
|
+
url: { type: "string", format: "uri", description: "Deve come\xE7ar com https://" },
|
|
720
|
+
events: { type: "array", items: { type: "string", enum: WEBHOOK_EVENT_KEYS }, description: "Eventos assinados (default: charge.paid, charge.cancelled, charge.expired)" },
|
|
721
|
+
active: { type: "boolean", default: true }
|
|
722
|
+
}
|
|
723
|
+
},
|
|
724
|
+
BankAccount: {
|
|
725
|
+
type: "object",
|
|
726
|
+
description: "Conta banc\xE1ria (campos sens\xEDveis como ag\xEAncia, conta, chave Pix e documento do titular s\xE3o omitidos da API p\xFAblica).",
|
|
727
|
+
properties: {
|
|
728
|
+
id: { type: "string", format: "uuid" },
|
|
729
|
+
bank_name: { type: "string" },
|
|
730
|
+
bank_code: { type: ["string", "null"] },
|
|
731
|
+
account_type: { type: ["string", "null"] },
|
|
732
|
+
is_primary: { type: "boolean" },
|
|
733
|
+
active: { type: "boolean" },
|
|
734
|
+
created_at: { type: "string", format: "date-time" },
|
|
735
|
+
updated_at: { type: "string", format: "date-time" }
|
|
736
|
+
}
|
|
737
|
+
},
|
|
738
|
+
Payout: {
|
|
739
|
+
type: "object",
|
|
740
|
+
description: "Pagamento a fornecedor normalizado (independente do banco).",
|
|
741
|
+
properties: {
|
|
742
|
+
id: { type: "string", format: "uuid" },
|
|
743
|
+
status: { type: "string", enum: ["pending", "processing", "completed", "failed", "cancelled"] },
|
|
744
|
+
provider: { type: "string", enum: ["inter", "c6bank"] },
|
|
745
|
+
method: { type: "string", enum: ["pix", "boleto"] },
|
|
746
|
+
amount: { type: "number" },
|
|
747
|
+
scheduled_for: { type: ["string", "null"], format: "date" },
|
|
748
|
+
bank_account_id: { type: "string", format: "uuid" },
|
|
749
|
+
purchase_invoice_charge_id: { type: ["string", "null"], format: "uuid" },
|
|
750
|
+
supplier_payment_method_id: { type: ["string", "null"], format: "uuid" },
|
|
751
|
+
provider_reference: { type: ["string", "null"], description: "codigoSolicitacao (Inter) ou group_id (C6)" },
|
|
752
|
+
error_message: { type: ["string", "null"] },
|
|
753
|
+
executed_at: { type: ["string", "null"], format: "date-time" },
|
|
754
|
+
created_at: { type: "string", format: "date-time" },
|
|
755
|
+
updated_at: { type: "string", format: "date-time" }
|
|
756
|
+
}
|
|
757
|
+
},
|
|
758
|
+
PayoutCreate: {
|
|
759
|
+
type: "object",
|
|
760
|
+
required: ["bank_account_id", "method"],
|
|
761
|
+
properties: {
|
|
762
|
+
bank_account_id: { type: "string", format: "uuid", description: "Conta banc\xE1ria de origem" },
|
|
763
|
+
method: { type: "string", enum: ["pix", "boleto"] },
|
|
764
|
+
provider: { type: "string", enum: ["inter", "c6bank"], description: "Opcional \u2014 detectado se houver uma \xFAnica integra\xE7\xE3o ativa" },
|
|
765
|
+
amount: { type: "number", description: "Obrigat\xF3rio se n\xE3o vier de purchase_invoice_charge_id" },
|
|
766
|
+
purchase_invoice_charge_id: { type: "string", format: "uuid", description: "Parcela a quitar (settlement autom\xE1tico)" },
|
|
767
|
+
supplier_payment_method_id: { type: "string", format: "uuid", description: "Forma de pagamento do fornecedor (Pix)" },
|
|
768
|
+
pix_key: { type: "string" },
|
|
769
|
+
pix_key_type: { type: "string", enum: ["cpf", "cnpj", "email", "phone", "random"] },
|
|
770
|
+
pix_copia_e_cola: { type: "string", description: "QR Pix copia e cola (EMV)" },
|
|
771
|
+
boleto_barcode: { type: "string" },
|
|
772
|
+
scheduled_for: { type: "string", format: "date", description: "Data de agendamento (YYYY-MM-DD); omitir paga \xE0 vista" },
|
|
773
|
+
description: { type: "string" }
|
|
774
|
+
}
|
|
775
|
+
},
|
|
776
|
+
SupplierPaymentMethod: {
|
|
777
|
+
type: "object",
|
|
778
|
+
properties: {
|
|
779
|
+
id: { type: "string", format: "uuid" },
|
|
780
|
+
supplier_id: { type: "string", format: "uuid" },
|
|
781
|
+
label: { type: "string" },
|
|
782
|
+
type: { type: "string", enum: ["pix", "transfer", "boleto", "other"] },
|
|
783
|
+
is_default: { type: "boolean" },
|
|
784
|
+
notes: { type: ["string", "null"] },
|
|
785
|
+
pix_key_type: { type: ["string", "null"], enum: ["cpf", "cnpj", "email", "phone", "random", null] },
|
|
786
|
+
pix_key: { type: ["string", "null"] },
|
|
787
|
+
bank_code: { type: ["string", "null"] },
|
|
788
|
+
bank_name: { type: ["string", "null"] },
|
|
789
|
+
agency: { type: ["string", "null"] },
|
|
790
|
+
account_number: { type: ["string", "null"] },
|
|
791
|
+
account_type: { type: ["string", "null"], enum: ["corrente", "poupanca", null] },
|
|
792
|
+
holder_name: { type: ["string", "null"] },
|
|
793
|
+
holder_document: { type: ["string", "null"] },
|
|
794
|
+
created_at: { type: "string", format: "date-time" },
|
|
795
|
+
updated_at: { type: "string", format: "date-time" }
|
|
796
|
+
}
|
|
797
|
+
},
|
|
798
|
+
SupplierPaymentMethodCreate: {
|
|
799
|
+
type: "object",
|
|
800
|
+
required: ["type"],
|
|
801
|
+
properties: {
|
|
802
|
+
type: { type: "string", enum: ["pix", "transfer", "boleto", "other"], default: "pix" },
|
|
803
|
+
label: { type: "string" },
|
|
804
|
+
is_default: { type: "boolean" },
|
|
805
|
+
notes: { type: "string" },
|
|
806
|
+
pix_key_type: { type: "string", enum: ["cpf", "cnpj", "email", "phone", "random"] },
|
|
807
|
+
pix_key: { type: "string", description: "Obrigat\xF3rio para type=pix" },
|
|
808
|
+
bank_code: { type: "string" },
|
|
809
|
+
bank_name: { type: "string" },
|
|
810
|
+
agency: { type: "string" },
|
|
811
|
+
account_number: { type: "string" },
|
|
812
|
+
account_type: { type: "string", enum: ["corrente", "poupanca"] },
|
|
813
|
+
holder_name: { type: "string" },
|
|
814
|
+
holder_document: { type: "string" }
|
|
815
|
+
}
|
|
816
|
+
},
|
|
817
|
+
PaymentMethod: {
|
|
818
|
+
type: "object",
|
|
819
|
+
properties: {
|
|
820
|
+
id: { type: "string", format: "uuid" },
|
|
821
|
+
name: { type: "string" },
|
|
822
|
+
system_key: { type: ["string", "null"], description: "Ex: inter_pix, c6bank_boleto" },
|
|
823
|
+
channel_key: { type: ["string", "null"], enum: ["pix", "boleto", "checkout", null] },
|
|
824
|
+
provider_name: { type: ["string", "null"], enum: ["inter", "c6bank", null] },
|
|
825
|
+
active: { type: "boolean" }
|
|
826
|
+
}
|
|
827
|
+
},
|
|
828
|
+
InvoiceCreate: {
|
|
829
|
+
type: "object",
|
|
830
|
+
required: ["customer_id"],
|
|
831
|
+
properties: {
|
|
832
|
+
customer_id: { type: "string", format: "uuid" },
|
|
833
|
+
title: { type: "string" },
|
|
834
|
+
amount: { type: "number", description: "Ignorado se 'items' for enviado (calculado dos itens)" },
|
|
835
|
+
status: { type: "string", enum: ["rascunho", "enviada", "aceita", "ativa"], default: "rascunho" },
|
|
836
|
+
due_date: { type: "string", format: "date" },
|
|
837
|
+
items: {
|
|
838
|
+
type: "array",
|
|
839
|
+
items: {
|
|
840
|
+
type: "object",
|
|
841
|
+
properties: {
|
|
842
|
+
service_id: { type: "string", format: "uuid", description: "Vincula um servi\xE7o cadastrado (GET /v1/services). Se omitido, o item \xE9 avulso (is_manual)." },
|
|
843
|
+
name: { type: "string" },
|
|
844
|
+
description: { type: "string" },
|
|
845
|
+
unit: { type: "string", default: "un" },
|
|
846
|
+
quantity: { type: "number", default: 1 },
|
|
847
|
+
unit_price: { type: "number" },
|
|
848
|
+
subtotal: { type: "number", description: "Opcional \u2014 calculado como quantity*unit_price se omitido" }
|
|
849
|
+
}
|
|
850
|
+
}
|
|
851
|
+
}
|
|
852
|
+
}
|
|
853
|
+
},
|
|
854
|
+
FinancialMovement: {
|
|
855
|
+
type: "object",
|
|
856
|
+
properties: {
|
|
857
|
+
id: { type: "string", format: "uuid" },
|
|
858
|
+
nature_id: { type: "string", format: "uuid" },
|
|
859
|
+
direction: { type: "string", enum: ["entrada", "saida"] },
|
|
860
|
+
amount: { type: "number" },
|
|
861
|
+
movement_date: { type: "string", format: "date" },
|
|
862
|
+
description: { type: "string" },
|
|
863
|
+
counterparty_name: { type: ["string", "null"] },
|
|
864
|
+
bank_account_id: { type: ["string", "null"], format: "uuid" },
|
|
865
|
+
payment_method_id: { type: ["string", "null"], format: "uuid" },
|
|
866
|
+
notes: { type: ["string", "null"] },
|
|
867
|
+
status: { type: "string", enum: ["realizado", "previsto", "cancelado"] },
|
|
868
|
+
source_type: { type: "string", enum: ["manual", "reconciliation", "rule"] },
|
|
869
|
+
created_at: { type: "string", format: "date-time" },
|
|
870
|
+
updated_at: { type: "string", format: "date-time" }
|
|
871
|
+
}
|
|
872
|
+
},
|
|
873
|
+
FinancialMovementCreate: {
|
|
874
|
+
type: "object",
|
|
875
|
+
required: ["nature_id", "direction", "amount", "movement_date", "description"],
|
|
876
|
+
properties: {
|
|
877
|
+
nature_id: { type: "string", format: "uuid", description: "Natureza financeira (financial_movement_natures)" },
|
|
878
|
+
direction: { type: "string", enum: ["entrada", "saida"] },
|
|
879
|
+
amount: { type: "number" },
|
|
880
|
+
movement_date: { type: "string", format: "date" },
|
|
881
|
+
description: { type: "string" },
|
|
882
|
+
counterparty_name: { type: "string" },
|
|
883
|
+
bank_account_id: { type: "string", format: "uuid" },
|
|
884
|
+
payment_method_id: { type: "string", format: "uuid" },
|
|
885
|
+
notes: { type: "string" },
|
|
886
|
+
status: { type: "string", enum: ["realizado", "previsto", "cancelado"], default: "realizado" }
|
|
887
|
+
}
|
|
888
|
+
},
|
|
889
|
+
NfseEmit: {
|
|
890
|
+
type: "object",
|
|
891
|
+
required: ["invoice_id"],
|
|
892
|
+
properties: {
|
|
893
|
+
invoice_id: { type: "string", format: "uuid", description: "Fatura a partir da qual emitir a NFS-e" }
|
|
894
|
+
}
|
|
895
|
+
},
|
|
896
|
+
NfseCancel: {
|
|
897
|
+
type: "object",
|
|
898
|
+
required: ["motivo", "justificativa"],
|
|
899
|
+
properties: {
|
|
900
|
+
motivo: { type: "integer", enum: [1, 2, 3, 4, 9], description: "1=n\xE3o realizada, 2=duplica\xE7\xE3o, 3=erro de emiss\xE3o, 4=servi\xE7o n\xE3o prestado, 9=outros" },
|
|
901
|
+
justificativa: { type: "string", minLength: 15, maxLength: 255 }
|
|
902
|
+
}
|
|
903
|
+
},
|
|
904
|
+
CustomerAddress: {
|
|
905
|
+
type: "object",
|
|
906
|
+
properties: {
|
|
907
|
+
id: { type: "string", format: "uuid" },
|
|
908
|
+
customer_id: { type: "string", format: "uuid" },
|
|
909
|
+
label: { type: ["string", "null"] },
|
|
910
|
+
street: { type: ["string", "null"] },
|
|
911
|
+
number: { type: ["string", "null"] },
|
|
912
|
+
complement: { type: ["string", "null"] },
|
|
913
|
+
neighborhood: { type: ["string", "null"] },
|
|
914
|
+
city: { type: ["string", "null"] },
|
|
915
|
+
state: { type: ["string", "null"], description: "UF (2 letras)" },
|
|
916
|
+
zip: { type: ["string", "null"] },
|
|
917
|
+
country: { type: ["string", "null"] },
|
|
918
|
+
ibge_code: { type: ["string", "null"] },
|
|
919
|
+
is_default: { type: "boolean" },
|
|
920
|
+
created_at: { type: "string", format: "date-time" },
|
|
921
|
+
updated_at: { type: "string", format: "date-time" }
|
|
922
|
+
}
|
|
923
|
+
},
|
|
924
|
+
CustomerAddressCreate: {
|
|
925
|
+
type: "object",
|
|
926
|
+
description: "Para emitir boleto, street, number, city, state e zip s\xE3o necess\xE1rios.",
|
|
927
|
+
properties: {
|
|
928
|
+
label: { type: "string" },
|
|
929
|
+
street: { type: "string" },
|
|
930
|
+
number: { type: "string" },
|
|
931
|
+
complement: { type: "string" },
|
|
932
|
+
neighborhood: { type: "string" },
|
|
933
|
+
city: { type: "string" },
|
|
934
|
+
state: { type: "string" },
|
|
935
|
+
zip: { type: "string" },
|
|
936
|
+
country: { type: "string" },
|
|
937
|
+
ibge_code: { type: "string" },
|
|
938
|
+
is_default: { type: "boolean" }
|
|
939
|
+
}
|
|
940
|
+
},
|
|
941
|
+
CustomerContact: {
|
|
942
|
+
type: "object",
|
|
943
|
+
properties: {
|
|
944
|
+
id: { type: "string", format: "uuid" },
|
|
945
|
+
customer_id: { type: "string", format: "uuid" },
|
|
946
|
+
name: { type: "string" },
|
|
947
|
+
email: { type: ["string", "null"] },
|
|
948
|
+
phone: { type: ["string", "null"] },
|
|
949
|
+
role: { type: ["string", "null"] },
|
|
950
|
+
department: { type: ["string", "null"] },
|
|
951
|
+
notes: { type: ["string", "null"] },
|
|
952
|
+
is_primary: { type: "boolean" },
|
|
953
|
+
created_at: { type: "string", format: "date-time" },
|
|
954
|
+
updated_at: { type: "string", format: "date-time" }
|
|
955
|
+
}
|
|
956
|
+
},
|
|
957
|
+
CustomerContactCreate: {
|
|
958
|
+
type: "object",
|
|
959
|
+
required: ["name"],
|
|
960
|
+
properties: {
|
|
961
|
+
name: { type: "string" },
|
|
962
|
+
email: { type: "string" },
|
|
963
|
+
phone: { type: "string" },
|
|
964
|
+
role: { type: "string" },
|
|
965
|
+
department: { type: "string" },
|
|
966
|
+
notes: { type: "string" },
|
|
967
|
+
is_primary: { type: "boolean" }
|
|
968
|
+
}
|
|
969
|
+
},
|
|
970
|
+
FinancialNature: {
|
|
971
|
+
type: "object",
|
|
972
|
+
properties: {
|
|
973
|
+
id: { type: "string", format: "uuid" },
|
|
974
|
+
code: { type: "string" },
|
|
975
|
+
name: { type: "string" },
|
|
976
|
+
description: { type: ["string", "null"] },
|
|
977
|
+
allowed_direction: { type: "string", enum: ["credit", "debit", "both"] },
|
|
978
|
+
is_active: { type: "boolean" },
|
|
979
|
+
sort_order: { type: "integer" }
|
|
980
|
+
}
|
|
981
|
+
},
|
|
982
|
+
CostCenter: {
|
|
983
|
+
type: "object",
|
|
984
|
+
properties: {
|
|
985
|
+
id: { type: "string", format: "uuid" },
|
|
986
|
+
name: { type: "string" },
|
|
987
|
+
active: { type: "boolean" },
|
|
988
|
+
color: { type: ["string", "null"] },
|
|
989
|
+
icon: { type: ["string", "null"] },
|
|
990
|
+
dre_group: { type: ["string", "null"] },
|
|
991
|
+
sort_order: { type: "integer" }
|
|
992
|
+
}
|
|
993
|
+
},
|
|
994
|
+
PaymentCondition: {
|
|
995
|
+
type: "object",
|
|
996
|
+
properties: {
|
|
997
|
+
id: { type: "string", format: "uuid" },
|
|
998
|
+
name: { type: "string" },
|
|
999
|
+
active: { type: "boolean" },
|
|
1000
|
+
installments: { type: "array", items: { type: "object" }, description: "[{sequence, label, days, percentage}]" }
|
|
1001
|
+
}
|
|
1002
|
+
},
|
|
1003
|
+
ServiceUnit: {
|
|
1004
|
+
type: "object",
|
|
1005
|
+
properties: { id: { type: "string", format: "uuid" }, name: { type: "string" } }
|
|
1006
|
+
},
|
|
1007
|
+
WebhookDelivery: {
|
|
1008
|
+
type: "object",
|
|
1009
|
+
properties: {
|
|
1010
|
+
id: { type: "string", format: "uuid" },
|
|
1011
|
+
webhook_id: { type: "string", format: "uuid" },
|
|
1012
|
+
event: { type: "string" },
|
|
1013
|
+
status: { type: "string", enum: ["pending", "delivering", "delivered", "failed"] },
|
|
1014
|
+
attempts: { type: "integer" },
|
|
1015
|
+
max_attempts: { type: "integer" },
|
|
1016
|
+
http_status: { type: ["integer", "null"] },
|
|
1017
|
+
last_error: { type: ["string", "null"] },
|
|
1018
|
+
next_retry_at: { type: ["string", "null"], format: "date-time" },
|
|
1019
|
+
delivered_at: { type: ["string", "null"], format: "date-time" },
|
|
1020
|
+
created_at: { type: "string", format: "date-time" },
|
|
1021
|
+
updated_at: { type: "string", format: "date-time" }
|
|
1022
|
+
}
|
|
1023
|
+
},
|
|
1024
|
+
Company: {
|
|
1025
|
+
type: "object",
|
|
1026
|
+
properties: {
|
|
1027
|
+
id: { type: "string", format: "uuid" },
|
|
1028
|
+
name: { type: "string" },
|
|
1029
|
+
trade_name: { type: ["string", "null"] },
|
|
1030
|
+
document: { type: ["string", "null"], description: "CNPJ/CPF" },
|
|
1031
|
+
active: { type: "boolean" },
|
|
1032
|
+
is_default: { type: "boolean", description: "Empresa padr\xE3o da chave (usada quando X-Company-Id \xE9 omitido)" }
|
|
1033
|
+
}
|
|
1034
|
+
}
|
|
1035
|
+
};
|
|
1036
|
+
function paginatedResponse(schemaRef) {
|
|
1037
|
+
return {
|
|
1038
|
+
description: "Listagem paginada",
|
|
1039
|
+
content: {
|
|
1040
|
+
"application/json": {
|
|
1041
|
+
schema: {
|
|
1042
|
+
type: "object",
|
|
1043
|
+
properties: {
|
|
1044
|
+
data: { type: "array", items: { $ref: schemaRef } },
|
|
1045
|
+
meta: { $ref: "#/components/schemas/PaginatedMeta" }
|
|
1046
|
+
}
|
|
1047
|
+
}
|
|
1048
|
+
}
|
|
1049
|
+
}
|
|
1050
|
+
};
|
|
1051
|
+
}
|
|
1052
|
+
function errorResponse(description) {
|
|
1053
|
+
return {
|
|
1054
|
+
description,
|
|
1055
|
+
content: { "application/json": { schema: { $ref: "#/components/schemas/Error" } } }
|
|
1056
|
+
};
|
|
1057
|
+
}
|
|
1058
|
+
var COMMON_ERRORS = {
|
|
1059
|
+
"401": errorResponse("API key n\xE3o fornecida, inv\xE1lida ou revogada"),
|
|
1060
|
+
"403": errorResponse("Scope insuficiente"),
|
|
1061
|
+
"429": errorResponse("Rate limit excedido (60 req/min por padr\xE3o)"),
|
|
1062
|
+
"500": errorResponse("Erro interno")
|
|
1063
|
+
};
|
|
1064
|
+
var OPENAPI_SPEC = {
|
|
1065
|
+
openapi: "3.1.0",
|
|
1066
|
+
info: {
|
|
1067
|
+
title: "Comando.One API",
|
|
1068
|
+
version: "1.1.0",
|
|
1069
|
+
description: "API REST p\xFAblica do Comando.One \u2014 ERP SaaS para empresas de servi\xE7o brasileiras.\n\nAutentique com uma API key no header `x-api-key` ou `Authorization: Bearer <key>`.\n\n**Idempot\xEAncia:** envie o header `Idempotency-Key` (string \xFAnica) em requisi\xE7\xF5es POST. Repeti\xE7\xF5es com a mesma chave retornam a resposta original (header `Idempotent-Replayed: true`), evitando cobran\xE7as/pagamentos duplicados em caso de retry.\n\n**Rate limit:** 60 requisi\xE7\xF5es/minuto por chave (429 ao exceder).\n\n**Multi-empresa:** chaves podem ter acesso a v\xE1rias empresas. Use `GET /v1/companies` para list\xE1-las e o header `X-Company-Id` para escolher o tenant de cada request (omitido = empresa padr\xE3o da chave).\n\nGere sua chave em **Configura\xE7\xF5es \u2192 API Keys** dentro da plataforma.",
|
|
1070
|
+
contact: { email: "contato@comando.one", url: "https://comando.one" },
|
|
1071
|
+
license: { name: "Propriet\xE1rio" }
|
|
1072
|
+
},
|
|
1073
|
+
servers: [
|
|
1074
|
+
{ url: "https://api.comando.one/v1", description: "Produ\xE7\xE3o" },
|
|
1075
|
+
{ url: "https://pecdxlrbutkrtxvjsquf.supabase.co/functions/v1/public-api/v1", description: "Supabase direto" }
|
|
1076
|
+
],
|
|
1077
|
+
security: API_KEY_SECURITY,
|
|
1078
|
+
tags: [
|
|
1079
|
+
{ name: "Auth", description: "Verifica\xE7\xE3o de conectividade e identidade" },
|
|
1080
|
+
{ name: "Clientes", description: "Gerenciamento de clientes e contatos" },
|
|
1081
|
+
{ name: "Propostas", description: "Propostas comerciais" },
|
|
1082
|
+
{ name: "Contratos", description: "Contratos recorrentes" },
|
|
1083
|
+
{ name: "Faturas", description: "Faturas e cobran\xE7as" },
|
|
1084
|
+
{ name: "Financeiro", description: "Raz\xE3o financeiro \u2014 entradas e sa\xEDdas" },
|
|
1085
|
+
{ name: "NFS-e", description: "Notas Fiscais de Servi\xE7o Eletr\xF4nicas" },
|
|
1086
|
+
{ name: "Fornecedores", description: "Cadastro de fornecedores" },
|
|
1087
|
+
{ name: "Servi\xE7os", description: "Cat\xE1logo de servi\xE7os" },
|
|
1088
|
+
{ name: "Despesas", description: "Despesas operacionais" },
|
|
1089
|
+
{ name: "Contas a Pagar", description: "Notas fiscais de entrada / contas a pagar" },
|
|
1090
|
+
{ name: "Cobran\xE7as", description: "Gateway de pagamentos \u2014 Pix, boleto e checkout" },
|
|
1091
|
+
{ name: "Webhooks", description: "Notifica\xE7\xF5es de eventos (cobran\xE7a/pagamento) com retry e log" },
|
|
1092
|
+
{ name: "Cat\xE1logos", description: "Listagens de refer\xEAncia (naturezas, centros de custo, condi\xE7\xF5es, unidades)" },
|
|
1093
|
+
{ name: "Contas banc\xE1rias", description: "Contas banc\xE1rias (somente leitura)" },
|
|
1094
|
+
{ name: "Pagamentos a Fornecedor", description: "Payouts \u2014 pagar/agendar Pix e boleto a fornecedores" },
|
|
1095
|
+
{ 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" }
|
|
1097
|
+
],
|
|
1098
|
+
components: {
|
|
1099
|
+
securitySchemes: {
|
|
1100
|
+
ApiKeyAuth: {
|
|
1101
|
+
type: "apiKey",
|
|
1102
|
+
in: "header",
|
|
1103
|
+
name: "x-api-key",
|
|
1104
|
+
description: "Chave de API no formato `cmd_live_...`. Pode tamb\xE9m ser enviada como `Authorization: Bearer cmd_live_...`"
|
|
1105
|
+
}
|
|
1106
|
+
},
|
|
1107
|
+
schemas: SCHEMAS
|
|
1108
|
+
},
|
|
1109
|
+
paths: {
|
|
1110
|
+
// -----------------------------------------------------------------------
|
|
1111
|
+
// Auth
|
|
1112
|
+
// -----------------------------------------------------------------------
|
|
1113
|
+
"/me": {
|
|
1114
|
+
get: {
|
|
1115
|
+
tags: ["Auth"],
|
|
1116
|
+
summary: "Verificar conectividade",
|
|
1117
|
+
operationId: "getMe",
|
|
1118
|
+
description: "Retorna os dados da empresa e da chave autenticada. N\xE3o exige scope espec\xEDfico \u2014 qualquer chave v\xE1lida funciona.",
|
|
1119
|
+
security: API_KEY_SECURITY,
|
|
1120
|
+
responses: {
|
|
1121
|
+
"200": {
|
|
1122
|
+
description: "Empresa e chave autenticada",
|
|
1123
|
+
content: {
|
|
1124
|
+
"application/json": {
|
|
1125
|
+
schema: {
|
|
1126
|
+
type: "object",
|
|
1127
|
+
properties: {
|
|
1128
|
+
company: {
|
|
1129
|
+
type: "object",
|
|
1130
|
+
properties: {
|
|
1131
|
+
id: { type: "string", format: "uuid" },
|
|
1132
|
+
name: { type: "string" },
|
|
1133
|
+
trade_name: { type: ["string", "null"] },
|
|
1134
|
+
document: { type: "string" }
|
|
1135
|
+
}
|
|
1136
|
+
},
|
|
1137
|
+
api_key: {
|
|
1138
|
+
type: "object",
|
|
1139
|
+
properties: {
|
|
1140
|
+
name: { type: "string" },
|
|
1141
|
+
scopes: { type: "array", items: { type: "string" } },
|
|
1142
|
+
last_used_at: { type: ["string", "null"], format: "date-time" }
|
|
1143
|
+
}
|
|
1144
|
+
}
|
|
1145
|
+
}
|
|
1146
|
+
},
|
|
1147
|
+
example: {
|
|
1148
|
+
company: { id: "18fc359b-...", name: "Acme Servi\xE7os", trade_name: "Acme", document: "12345678000195" },
|
|
1149
|
+
api_key: { name: "Integra\xE7\xE3o ERP", scopes: ["customers:read", "invoices:read"], last_used_at: "2026-06-04T18:17:47+00:00" }
|
|
1150
|
+
}
|
|
1151
|
+
}
|
|
1152
|
+
}
|
|
1153
|
+
},
|
|
1154
|
+
...COMMON_ERRORS
|
|
1155
|
+
}
|
|
1156
|
+
}
|
|
1157
|
+
},
|
|
1158
|
+
"/companies": {
|
|
1159
|
+
get: {
|
|
1160
|
+
tags: ["Auth"],
|
|
1161
|
+
summary: "Listar empresas acess\xEDveis pela chave",
|
|
1162
|
+
operationId: "listCompanies",
|
|
1163
|
+
description: "Lista as empresas que a chave pode acessar. Keys single-company retornam apenas a sua; keys multi-empresa retornam todas as permitidas. Use o id em **X-Company-Id** para escolher o tenant de cada request.",
|
|
1164
|
+
security: API_KEY_SECURITY,
|
|
1165
|
+
responses: {
|
|
1166
|
+
"200": { description: "Empresas acess\xEDveis", content: { "application/json": { schema: { type: "object", properties: { data: { type: "array", items: { $ref: "#/components/schemas/Company" } } } } } } },
|
|
1167
|
+
...COMMON_ERRORS
|
|
1168
|
+
}
|
|
1169
|
+
}
|
|
1170
|
+
},
|
|
1171
|
+
"/companies/{id}": {
|
|
1172
|
+
parameters: [{ name: "id", in: "path", required: true, schema: { type: "string", format: "uuid" } }],
|
|
1173
|
+
get: {
|
|
1174
|
+
tags: ["Auth"],
|
|
1175
|
+
summary: "Obter empresa acess\xEDvel",
|
|
1176
|
+
operationId: "getCompany",
|
|
1177
|
+
security: API_KEY_SECURITY,
|
|
1178
|
+
responses: { "200": { description: "Empresa", content: { "application/json": { schema: { $ref: "#/components/schemas/Company" } } } }, "404": errorResponse("Empresa n\xE3o encontrada ou n\xE3o acess\xEDvel pela chave"), ...COMMON_ERRORS }
|
|
1179
|
+
}
|
|
1180
|
+
},
|
|
1181
|
+
// -----------------------------------------------------------------------
|
|
1182
|
+
// Customers
|
|
1183
|
+
// -----------------------------------------------------------------------
|
|
1184
|
+
"/customers": {
|
|
1185
|
+
get: {
|
|
1186
|
+
tags: ["Clientes"],
|
|
1187
|
+
summary: "Listar clientes",
|
|
1188
|
+
operationId: "listCustomers",
|
|
1189
|
+
security: [{ ApiKeyAuth: ["customers:read"] }],
|
|
1190
|
+
parameters: [
|
|
1191
|
+
...PAGINATION_PARAMS,
|
|
1192
|
+
{ name: "search", in: "query", schema: { type: "string" }, description: "Busca por nome, e-mail ou documento" },
|
|
1193
|
+
{ name: "status", in: "query", schema: { type: "string" }, description: "Filtrar por status" }
|
|
1194
|
+
],
|
|
1195
|
+
responses: {
|
|
1196
|
+
"200": paginatedResponse("#/components/schemas/Customer"),
|
|
1197
|
+
...COMMON_ERRORS
|
|
1198
|
+
}
|
|
1199
|
+
},
|
|
1200
|
+
post: {
|
|
1201
|
+
tags: ["Clientes"],
|
|
1202
|
+
summary: "Criar cliente",
|
|
1203
|
+
operationId: "createCustomer",
|
|
1204
|
+
security: [{ ApiKeyAuth: ["customers:write"] }],
|
|
1205
|
+
requestBody: {
|
|
1206
|
+
required: true,
|
|
1207
|
+
content: {
|
|
1208
|
+
"application/json": {
|
|
1209
|
+
schema: { $ref: "#/components/schemas/CustomerCreate" },
|
|
1210
|
+
example: { name: "Acme Servi\xE7os Ltda", email: "contato@acme.com.br", type: "juridica", document: "12345678000195" }
|
|
1211
|
+
}
|
|
1212
|
+
}
|
|
1213
|
+
},
|
|
1214
|
+
responses: {
|
|
1215
|
+
"201": {
|
|
1216
|
+
description: "Cliente criado",
|
|
1217
|
+
content: { "application/json": { schema: { $ref: "#/components/schemas/Customer" } } }
|
|
1218
|
+
},
|
|
1219
|
+
"400": errorResponse("Par\xE2metros inv\xE1lidos"),
|
|
1220
|
+
...COMMON_ERRORS
|
|
1221
|
+
}
|
|
1222
|
+
}
|
|
1223
|
+
},
|
|
1224
|
+
"/customers/{id}": {
|
|
1225
|
+
parameters: [{ name: "id", in: "path", required: true, schema: { type: "string", format: "uuid" } }],
|
|
1226
|
+
get: {
|
|
1227
|
+
tags: ["Clientes"],
|
|
1228
|
+
summary: "Obter cliente",
|
|
1229
|
+
operationId: "getCustomer",
|
|
1230
|
+
security: [{ ApiKeyAuth: ["customers:read"] }],
|
|
1231
|
+
responses: {
|
|
1232
|
+
"200": { description: "Cliente", content: { "application/json": { schema: { $ref: "#/components/schemas/Customer" } } } },
|
|
1233
|
+
"404": errorResponse("Cliente n\xE3o encontrado"),
|
|
1234
|
+
...COMMON_ERRORS
|
|
1235
|
+
}
|
|
1236
|
+
},
|
|
1237
|
+
patch: {
|
|
1238
|
+
tags: ["Clientes"],
|
|
1239
|
+
summary: "Atualizar cliente",
|
|
1240
|
+
operationId: "updateCustomer",
|
|
1241
|
+
security: [{ ApiKeyAuth: ["customers:write"] }],
|
|
1242
|
+
requestBody: {
|
|
1243
|
+
required: true,
|
|
1244
|
+
content: { "application/json": { schema: { $ref: "#/components/schemas/CustomerUpdate" } } }
|
|
1245
|
+
},
|
|
1246
|
+
responses: {
|
|
1247
|
+
"200": { description: "Cliente atualizado", content: { "application/json": { schema: { $ref: "#/components/schemas/Customer" } } } },
|
|
1248
|
+
"400": errorResponse("Par\xE2metros inv\xE1lidos"),
|
|
1249
|
+
"404": errorResponse("Cliente n\xE3o encontrado"),
|
|
1250
|
+
...COMMON_ERRORS
|
|
1251
|
+
}
|
|
1252
|
+
},
|
|
1253
|
+
delete: {
|
|
1254
|
+
tags: ["Clientes"],
|
|
1255
|
+
summary: "Excluir cliente",
|
|
1256
|
+
operationId: "deleteCustomer",
|
|
1257
|
+
security: [{ ApiKeyAuth: ["customers:delete"] }],
|
|
1258
|
+
responses: {
|
|
1259
|
+
"204": { description: "Cliente exclu\xEDdo (sem corpo)" },
|
|
1260
|
+
"404": errorResponse("Cliente n\xE3o encontrado"),
|
|
1261
|
+
"409": errorResponse("H\xE1 registros vinculados (faturas, contratos, etc.) que impedem a exclus\xE3o"),
|
|
1262
|
+
...COMMON_ERRORS
|
|
1263
|
+
}
|
|
1264
|
+
}
|
|
1265
|
+
},
|
|
1266
|
+
"/customers/{id}/invoices": {
|
|
1267
|
+
parameters: [{ name: "id", in: "path", required: true, schema: { type: "string", format: "uuid" } }],
|
|
1268
|
+
get: {
|
|
1269
|
+
tags: ["Clientes"],
|
|
1270
|
+
summary: "Faturas do cliente",
|
|
1271
|
+
operationId: "listCustomerInvoices",
|
|
1272
|
+
security: [{ ApiKeyAuth: ["customers:read", "invoices:read"] }],
|
|
1273
|
+
parameters: PAGINATION_PARAMS,
|
|
1274
|
+
responses: {
|
|
1275
|
+
"200": {
|
|
1276
|
+
description: "Faturas do cliente",
|
|
1277
|
+
content: {
|
|
1278
|
+
"application/json": {
|
|
1279
|
+
schema: {
|
|
1280
|
+
type: "object",
|
|
1281
|
+
properties: {
|
|
1282
|
+
data: { type: "array", items: { type: "object" } },
|
|
1283
|
+
meta: { $ref: "#/components/schemas/PaginatedMeta" }
|
|
1284
|
+
}
|
|
1285
|
+
}
|
|
1286
|
+
}
|
|
1287
|
+
}
|
|
1288
|
+
},
|
|
1289
|
+
"404": errorResponse("Cliente n\xE3o encontrado"),
|
|
1290
|
+
...COMMON_ERRORS
|
|
1291
|
+
}
|
|
1292
|
+
}
|
|
1293
|
+
},
|
|
1294
|
+
"/customers/{id}/contracts": {
|
|
1295
|
+
parameters: [{ name: "id", in: "path", required: true, schema: { type: "string", format: "uuid" } }],
|
|
1296
|
+
get: {
|
|
1297
|
+
tags: ["Clientes"],
|
|
1298
|
+
summary: "Contratos do cliente",
|
|
1299
|
+
operationId: "listCustomerContracts",
|
|
1300
|
+
security: [{ ApiKeyAuth: ["customers:read", "contracts:read"] }],
|
|
1301
|
+
parameters: PAGINATION_PARAMS,
|
|
1302
|
+
responses: {
|
|
1303
|
+
"200": paginatedResponse("#/components/schemas/Contract"),
|
|
1304
|
+
"404": errorResponse("Cliente n\xE3o encontrado"),
|
|
1305
|
+
...COMMON_ERRORS
|
|
1306
|
+
}
|
|
1307
|
+
}
|
|
1308
|
+
},
|
|
1309
|
+
"/customers/{id}/proposals": {
|
|
1310
|
+
parameters: [{ name: "id", in: "path", required: true, schema: { type: "string", format: "uuid" } }],
|
|
1311
|
+
get: {
|
|
1312
|
+
tags: ["Clientes"],
|
|
1313
|
+
summary: "Propostas do cliente",
|
|
1314
|
+
operationId: "listCustomerProposals",
|
|
1315
|
+
security: [{ ApiKeyAuth: ["customers:read", "proposals:read"] }],
|
|
1316
|
+
parameters: PAGINATION_PARAMS,
|
|
1317
|
+
responses: {
|
|
1318
|
+
"200": paginatedResponse("#/components/schemas/Proposal"),
|
|
1319
|
+
"404": errorResponse("Cliente n\xE3o encontrado"),
|
|
1320
|
+
...COMMON_ERRORS
|
|
1321
|
+
}
|
|
1322
|
+
}
|
|
1323
|
+
},
|
|
1324
|
+
"/customers/{id}/addresses": {
|
|
1325
|
+
parameters: [{ name: "id", in: "path", required: true, schema: { type: "string", format: "uuid" } }],
|
|
1326
|
+
get: {
|
|
1327
|
+
tags: ["Clientes"],
|
|
1328
|
+
summary: "Listar endere\xE7os do cliente",
|
|
1329
|
+
operationId: "listCustomerAddresses",
|
|
1330
|
+
security: [{ ApiKeyAuth: ["customers:read"] }],
|
|
1331
|
+
responses: { "200": { description: "Endere\xE7os", content: { "application/json": { schema: { type: "object", properties: { data: { type: "array", items: { $ref: "#/components/schemas/CustomerAddress" } } } } } } }, "404": errorResponse("Cliente n\xE3o encontrado"), ...COMMON_ERRORS }
|
|
1332
|
+
},
|
|
1333
|
+
post: {
|
|
1334
|
+
tags: ["Clientes"],
|
|
1335
|
+
summary: "Adicionar endere\xE7o",
|
|
1336
|
+
operationId: "createCustomerAddress",
|
|
1337
|
+
security: [{ ApiKeyAuth: ["customers:write"] }],
|
|
1338
|
+
requestBody: { required: true, content: { "application/json": { schema: { $ref: "#/components/schemas/CustomerAddressCreate" } } } },
|
|
1339
|
+
responses: { "201": { description: "Criado", content: { "application/json": { schema: { $ref: "#/components/schemas/CustomerAddress" } } } }, "404": errorResponse("Cliente n\xE3o encontrado"), ...COMMON_ERRORS }
|
|
1340
|
+
}
|
|
1341
|
+
},
|
|
1342
|
+
"/customers/{id}/addresses/{addressId}": {
|
|
1343
|
+
parameters: [
|
|
1344
|
+
{ name: "id", in: "path", required: true, schema: { type: "string", format: "uuid" } },
|
|
1345
|
+
{ name: "addressId", in: "path", required: true, schema: { type: "string", format: "uuid" } }
|
|
1346
|
+
],
|
|
1347
|
+
patch: {
|
|
1348
|
+
tags: ["Clientes"],
|
|
1349
|
+
summary: "Atualizar endere\xE7o",
|
|
1350
|
+
operationId: "updateCustomerAddress",
|
|
1351
|
+
security: [{ ApiKeyAuth: ["customers:write"] }],
|
|
1352
|
+
requestBody: { required: true, content: { "application/json": { schema: { $ref: "#/components/schemas/CustomerAddressCreate" } } } },
|
|
1353
|
+
responses: { "200": { description: "Atualizado", content: { "application/json": { schema: { $ref: "#/components/schemas/CustomerAddress" } } } }, "404": errorResponse("N\xE3o encontrado"), ...COMMON_ERRORS }
|
|
1354
|
+
},
|
|
1355
|
+
delete: {
|
|
1356
|
+
tags: ["Clientes"],
|
|
1357
|
+
summary: "Excluir endere\xE7o",
|
|
1358
|
+
operationId: "deleteCustomerAddress",
|
|
1359
|
+
security: [{ ApiKeyAuth: ["customers:delete"] }],
|
|
1360
|
+
responses: { "204": { description: "Exclu\xEDdo" }, "404": errorResponse("N\xE3o encontrado"), "409": errorResponse("H\xE1 registros vinculados que impedem a exclus\xE3o"), ...COMMON_ERRORS }
|
|
1361
|
+
}
|
|
1362
|
+
},
|
|
1363
|
+
"/customers/{id}/contacts": {
|
|
1364
|
+
parameters: [{ name: "id", in: "path", required: true, schema: { type: "string", format: "uuid" } }],
|
|
1365
|
+
get: {
|
|
1366
|
+
tags: ["Clientes"],
|
|
1367
|
+
summary: "Listar contatos do cliente",
|
|
1368
|
+
operationId: "listCustomerContacts",
|
|
1369
|
+
security: [{ ApiKeyAuth: ["customers:read"] }],
|
|
1370
|
+
responses: { "200": { description: "Contatos", content: { "application/json": { schema: { type: "object", properties: { data: { type: "array", items: { $ref: "#/components/schemas/CustomerContact" } } } } } } }, "404": errorResponse("Cliente n\xE3o encontrado"), ...COMMON_ERRORS }
|
|
1371
|
+
},
|
|
1372
|
+
post: {
|
|
1373
|
+
tags: ["Clientes"],
|
|
1374
|
+
summary: "Adicionar contato",
|
|
1375
|
+
operationId: "createCustomerContact",
|
|
1376
|
+
security: [{ ApiKeyAuth: ["customers:write"] }],
|
|
1377
|
+
requestBody: { required: true, content: { "application/json": { schema: { $ref: "#/components/schemas/CustomerContactCreate" } } } },
|
|
1378
|
+
responses: { "201": { description: "Criado", content: { "application/json": { schema: { $ref: "#/components/schemas/CustomerContact" } } } }, "400": errorResponse("name obrigat\xF3rio"), "404": errorResponse("Cliente n\xE3o encontrado"), ...COMMON_ERRORS }
|
|
1379
|
+
}
|
|
1380
|
+
},
|
|
1381
|
+
"/customers/{id}/contacts/{contactId}": {
|
|
1382
|
+
parameters: [
|
|
1383
|
+
{ name: "id", in: "path", required: true, schema: { type: "string", format: "uuid" } },
|
|
1384
|
+
{ name: "contactId", in: "path", required: true, schema: { type: "string", format: "uuid" } }
|
|
1385
|
+
],
|
|
1386
|
+
patch: {
|
|
1387
|
+
tags: ["Clientes"],
|
|
1388
|
+
summary: "Atualizar contato",
|
|
1389
|
+
operationId: "updateCustomerContact",
|
|
1390
|
+
security: [{ ApiKeyAuth: ["customers:write"] }],
|
|
1391
|
+
requestBody: { required: true, content: { "application/json": { schema: { $ref: "#/components/schemas/CustomerContactCreate" } } } },
|
|
1392
|
+
responses: { "200": { description: "Atualizado", content: { "application/json": { schema: { $ref: "#/components/schemas/CustomerContact" } } } }, "404": errorResponse("N\xE3o encontrado"), ...COMMON_ERRORS }
|
|
1393
|
+
},
|
|
1394
|
+
delete: {
|
|
1395
|
+
tags: ["Clientes"],
|
|
1396
|
+
summary: "Excluir contato",
|
|
1397
|
+
operationId: "deleteCustomerContact",
|
|
1398
|
+
security: [{ ApiKeyAuth: ["customers:delete"] }],
|
|
1399
|
+
responses: { "204": { description: "Exclu\xEDdo" }, "404": errorResponse("N\xE3o encontrado"), "409": errorResponse("H\xE1 registros vinculados que impedem a exclus\xE3o"), ...COMMON_ERRORS }
|
|
1400
|
+
}
|
|
1401
|
+
},
|
|
1402
|
+
// -----------------------------------------------------------------------
|
|
1403
|
+
// Proposals
|
|
1404
|
+
// -----------------------------------------------------------------------
|
|
1405
|
+
"/proposals": {
|
|
1406
|
+
get: {
|
|
1407
|
+
tags: ["Propostas"],
|
|
1408
|
+
summary: "Listar propostas",
|
|
1409
|
+
operationId: "listProposals",
|
|
1410
|
+
security: [{ ApiKeyAuth: ["proposals:read"] }],
|
|
1411
|
+
parameters: [
|
|
1412
|
+
...PAGINATION_PARAMS,
|
|
1413
|
+
{ name: "status", in: "query", schema: { type: "string", enum: ["rascunho", "enviada", "aceita", "recusada", "cancelada", "faturada"] }, description: "Filtrar por status" },
|
|
1414
|
+
{ name: "customer_id", in: "query", schema: { type: "string", format: "uuid" }, description: "Filtrar por cliente" }
|
|
1415
|
+
],
|
|
1416
|
+
responses: {
|
|
1417
|
+
"200": paginatedResponse("#/components/schemas/Proposal"),
|
|
1418
|
+
...COMMON_ERRORS
|
|
1419
|
+
}
|
|
1420
|
+
},
|
|
1421
|
+
post: {
|
|
1422
|
+
tags: ["Propostas"],
|
|
1423
|
+
summary: "Criar proposta",
|
|
1424
|
+
operationId: "createProposal",
|
|
1425
|
+
security: [{ ApiKeyAuth: ["proposals:write"] }],
|
|
1426
|
+
requestBody: { required: true, content: { "application/json": { schema: { $ref: "#/components/schemas/ProposalCreate" } } } },
|
|
1427
|
+
responses: { "201": { description: "Proposta criada", content: { "application/json": { schema: { $ref: "#/components/schemas/Proposal" } } } }, "400": errorResponse("Dados inv\xE1lidos"), "404": errorResponse("Cliente n\xE3o encontrado"), ...COMMON_ERRORS }
|
|
1428
|
+
}
|
|
1429
|
+
},
|
|
1430
|
+
"/proposals/{id}": {
|
|
1431
|
+
parameters: [{ name: "id", in: "path", required: true, schema: { type: "string", format: "uuid" } }],
|
|
1432
|
+
get: {
|
|
1433
|
+
tags: ["Propostas"],
|
|
1434
|
+
summary: "Obter proposta",
|
|
1435
|
+
operationId: "getProposal",
|
|
1436
|
+
security: [{ ApiKeyAuth: ["proposals:read"] }],
|
|
1437
|
+
responses: {
|
|
1438
|
+
"200": { description: "Proposta com itens", content: { "application/json": { schema: { $ref: "#/components/schemas/ProposalDetail" } } } },
|
|
1439
|
+
"404": errorResponse("Proposta n\xE3o encontrada"),
|
|
1440
|
+
...COMMON_ERRORS
|
|
1441
|
+
}
|
|
1442
|
+
},
|
|
1443
|
+
patch: {
|
|
1444
|
+
tags: ["Propostas"],
|
|
1445
|
+
summary: "Atualizar proposta",
|
|
1446
|
+
operationId: "updateProposal",
|
|
1447
|
+
security: [{ ApiKeyAuth: ["proposals:write"] }],
|
|
1448
|
+
requestBody: { required: true, content: { "application/json": { schema: { $ref: "#/components/schemas/ProposalCreate" } } } },
|
|
1449
|
+
responses: { "200": { description: "Proposta atualizada", content: { "application/json": { schema: { $ref: "#/components/schemas/Proposal" } } } }, "404": errorResponse("Proposta n\xE3o encontrada"), ...COMMON_ERRORS }
|
|
1450
|
+
},
|
|
1451
|
+
delete: {
|
|
1452
|
+
tags: ["Propostas"],
|
|
1453
|
+
summary: "Excluir proposta",
|
|
1454
|
+
operationId: "deleteProposal",
|
|
1455
|
+
security: [{ ApiKeyAuth: ["proposals:delete"] }],
|
|
1456
|
+
responses: { "204": { description: "Exclu\xEDda" }, "404": errorResponse("Proposta n\xE3o encontrada"), "409": errorResponse("H\xE1 registros vinculados que impedem a exclus\xE3o"), ...COMMON_ERRORS }
|
|
1457
|
+
}
|
|
1458
|
+
},
|
|
1459
|
+
"/proposals/{id}/send": {
|
|
1460
|
+
parameters: [{ name: "id", in: "path", required: true, schema: { type: "string", format: "uuid" } }],
|
|
1461
|
+
post: {
|
|
1462
|
+
tags: ["Propostas"],
|
|
1463
|
+
summary: "Enviar proposta",
|
|
1464
|
+
operationId: "sendProposal",
|
|
1465
|
+
description: "Marca a proposta como enviada.",
|
|
1466
|
+
security: [{ ApiKeyAuth: ["proposals:send"] }],
|
|
1467
|
+
responses: { "200": { description: "Proposta enviada", content: { "application/json": { schema: { $ref: "#/components/schemas/Proposal" } } } }, "404": errorResponse("Proposta n\xE3o encontrada"), "409": errorResponse("Proposta cancelada"), ...COMMON_ERRORS }
|
|
1468
|
+
}
|
|
1469
|
+
},
|
|
1470
|
+
// -----------------------------------------------------------------------
|
|
1471
|
+
// Contracts
|
|
1472
|
+
// -----------------------------------------------------------------------
|
|
1473
|
+
"/contracts": {
|
|
1474
|
+
get: {
|
|
1475
|
+
tags: ["Contratos"],
|
|
1476
|
+
summary: "Listar contratos",
|
|
1477
|
+
operationId: "listContracts",
|
|
1478
|
+
security: [{ ApiKeyAuth: ["contracts:read"] }],
|
|
1479
|
+
parameters: [
|
|
1480
|
+
...PAGINATION_PARAMS,
|
|
1481
|
+
{ name: "search", in: "query", schema: { type: "string" }, description: "Busca por t\xEDtulo ou notas" },
|
|
1482
|
+
{ name: "status", in: "query", schema: { type: "string", enum: ["ativo", "suspenso", "cancelado", "finalizado"] } },
|
|
1483
|
+
{ name: "frequency", in: "query", schema: { type: "string", enum: ["semanal", "quinzenal", "mensal", "bimestral", "trimestral", "semestral", "anual"] } },
|
|
1484
|
+
{ name: "customer_id", in: "query", schema: { type: "string", format: "uuid" } }
|
|
1485
|
+
],
|
|
1486
|
+
responses: {
|
|
1487
|
+
"200": paginatedResponse("#/components/schemas/Contract"),
|
|
1488
|
+
...COMMON_ERRORS
|
|
1489
|
+
}
|
|
1490
|
+
},
|
|
1491
|
+
post: {
|
|
1492
|
+
tags: ["Contratos"],
|
|
1493
|
+
summary: "Criar contrato",
|
|
1494
|
+
operationId: "createContract",
|
|
1495
|
+
security: [{ ApiKeyAuth: ["contracts:write"] }],
|
|
1496
|
+
requestBody: { required: true, content: { "application/json": { schema: { $ref: "#/components/schemas/ContractCreate" } } } },
|
|
1497
|
+
responses: { "201": { description: "Contrato criado", content: { "application/json": { schema: { $ref: "#/components/schemas/Contract" } } } }, "400": errorResponse("Dados inv\xE1lidos"), "404": errorResponse("Cliente n\xE3o encontrado"), ...COMMON_ERRORS }
|
|
1498
|
+
}
|
|
1499
|
+
},
|
|
1500
|
+
"/contracts/{id}": {
|
|
1501
|
+
parameters: [{ name: "id", in: "path", required: true, schema: { type: "string", format: "uuid" } }],
|
|
1502
|
+
get: {
|
|
1503
|
+
tags: ["Contratos"],
|
|
1504
|
+
summary: "Obter contrato",
|
|
1505
|
+
operationId: "getContract",
|
|
1506
|
+
security: [{ ApiKeyAuth: ["contracts:read"] }],
|
|
1507
|
+
responses: {
|
|
1508
|
+
"200": { description: "Contrato com itens e se\xE7\xF5es", content: { "application/json": { schema: { $ref: "#/components/schemas/ContractDetail" } } } },
|
|
1509
|
+
"404": errorResponse("Contrato n\xE3o encontrado"),
|
|
1510
|
+
...COMMON_ERRORS
|
|
1511
|
+
}
|
|
1512
|
+
},
|
|
1513
|
+
patch: {
|
|
1514
|
+
tags: ["Contratos"],
|
|
1515
|
+
summary: "Atualizar contrato",
|
|
1516
|
+
operationId: "updateContract",
|
|
1517
|
+
security: [{ ApiKeyAuth: ["contracts:write"] }],
|
|
1518
|
+
requestBody: { required: true, content: { "application/json": { schema: { $ref: "#/components/schemas/ContractCreate" } } } },
|
|
1519
|
+
responses: { "200": { description: "Contrato atualizado", content: { "application/json": { schema: { $ref: "#/components/schemas/Contract" } } } }, "404": errorResponse("Contrato n\xE3o encontrado"), ...COMMON_ERRORS }
|
|
1520
|
+
},
|
|
1521
|
+
delete: {
|
|
1522
|
+
tags: ["Contratos"],
|
|
1523
|
+
summary: "Excluir contrato",
|
|
1524
|
+
operationId: "deleteContract",
|
|
1525
|
+
security: [{ ApiKeyAuth: ["contracts:delete"] }],
|
|
1526
|
+
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
|
+
}
|
|
1528
|
+
},
|
|
1529
|
+
// -----------------------------------------------------------------------
|
|
1530
|
+
// Invoices
|
|
1531
|
+
// -----------------------------------------------------------------------
|
|
1532
|
+
"/invoices": {
|
|
1533
|
+
get: {
|
|
1534
|
+
tags: ["Faturas"],
|
|
1535
|
+
summary: "Listar faturas",
|
|
1536
|
+
operationId: "listInvoices",
|
|
1537
|
+
security: [{ ApiKeyAuth: ["invoices:read"] }],
|
|
1538
|
+
parameters: [
|
|
1539
|
+
...PAGINATION_PARAMS,
|
|
1540
|
+
{ name: "search", in: "query", schema: { type: "string" }, description: "Busca por n\xFAmero ou t\xEDtulo" },
|
|
1541
|
+
{ name: "status", in: "query", schema: { type: "string", enum: ["rascunho", "enviada", "aceita", "cancelada"] } },
|
|
1542
|
+
{ name: "payment_status", in: "query", schema: { type: "string", enum: ["pendente", "parcial", "pago", "vencido"] } },
|
|
1543
|
+
{ name: "customer_id", in: "query", schema: { type: "string", format: "uuid" } },
|
|
1544
|
+
{ name: "due_date_from", in: "query", schema: { type: "string", format: "date" }, description: "Vencimento a partir de (YYYY-MM-DD)" },
|
|
1545
|
+
{ name: "due_date_to", in: "query", schema: { type: "string", format: "date" }, description: "Vencimento at\xE9 (YYYY-MM-DD)" }
|
|
1546
|
+
],
|
|
1547
|
+
responses: {
|
|
1548
|
+
"200": paginatedResponse("#/components/schemas/Invoice"),
|
|
1549
|
+
...COMMON_ERRORS
|
|
1550
|
+
}
|
|
1551
|
+
},
|
|
1552
|
+
post: {
|
|
1553
|
+
tags: ["Faturas"],
|
|
1554
|
+
summary: "Criar fatura",
|
|
1555
|
+
operationId: "createInvoice",
|
|
1556
|
+
description: "Cria uma fatura. Se 'items' for enviado, o valor \xE9 calculado a partir deles.",
|
|
1557
|
+
security: [{ ApiKeyAuth: ["invoices:create"] }],
|
|
1558
|
+
requestBody: { required: true, content: { "application/json": { schema: { $ref: "#/components/schemas/InvoiceCreate" } } } },
|
|
1559
|
+
responses: { "201": { description: "Fatura criada", content: { "application/json": { schema: { $ref: "#/components/schemas/Invoice" } } } }, "400": errorResponse("Dados inv\xE1lidos"), "404": errorResponse("Cliente n\xE3o encontrado"), ...COMMON_ERRORS }
|
|
1560
|
+
}
|
|
1561
|
+
},
|
|
1562
|
+
"/invoices/{id}": {
|
|
1563
|
+
parameters: [{ name: "id", in: "path", required: true, schema: { type: "string", format: "uuid" } }],
|
|
1564
|
+
get: {
|
|
1565
|
+
tags: ["Faturas"],
|
|
1566
|
+
summary: "Obter fatura",
|
|
1567
|
+
operationId: "getInvoice",
|
|
1568
|
+
security: [{ ApiKeyAuth: ["invoices:read"] }],
|
|
1569
|
+
responses: {
|
|
1570
|
+
"200": { description: "Fatura com itens e cobran\xE7as", content: { "application/json": { schema: { $ref: "#/components/schemas/InvoiceDetail" } } } },
|
|
1571
|
+
"404": errorResponse("Fatura n\xE3o encontrada"),
|
|
1572
|
+
...COMMON_ERRORS
|
|
1573
|
+
}
|
|
1574
|
+
}
|
|
1575
|
+
},
|
|
1576
|
+
"/invoices/{id}/cancel": {
|
|
1577
|
+
parameters: [{ name: "id", in: "path", required: true, schema: { type: "string", format: "uuid" } }],
|
|
1578
|
+
patch: {
|
|
1579
|
+
tags: ["Faturas"],
|
|
1580
|
+
summary: "Cancelar fatura",
|
|
1581
|
+
operationId: "cancelInvoice",
|
|
1582
|
+
security: [{ ApiKeyAuth: ["invoices:cancel"] }],
|
|
1583
|
+
responses: {
|
|
1584
|
+
"200": {
|
|
1585
|
+
description: "Fatura cancelada",
|
|
1586
|
+
content: {
|
|
1587
|
+
"application/json": {
|
|
1588
|
+
schema: {
|
|
1589
|
+
type: "object",
|
|
1590
|
+
properties: {
|
|
1591
|
+
id: { type: "string", format: "uuid" },
|
|
1592
|
+
invoice_number: { type: ["string", "null"] },
|
|
1593
|
+
title: { type: ["string", "null"] },
|
|
1594
|
+
status: { type: "string", enum: ["cancelada"] },
|
|
1595
|
+
payment_status: { type: "string" },
|
|
1596
|
+
amount: { type: "number" },
|
|
1597
|
+
updated_at: { type: "string", format: "date-time" }
|
|
1598
|
+
}
|
|
1599
|
+
}
|
|
1600
|
+
}
|
|
1601
|
+
}
|
|
1602
|
+
},
|
|
1603
|
+
"404": errorResponse("Fatura n\xE3o encontrada"),
|
|
1604
|
+
"409": errorResponse("Fatura j\xE1 est\xE1 cancelada"),
|
|
1605
|
+
...COMMON_ERRORS
|
|
1606
|
+
}
|
|
1607
|
+
}
|
|
1608
|
+
},
|
|
1609
|
+
// -----------------------------------------------------------------------
|
|
1610
|
+
// Finance
|
|
1611
|
+
// -----------------------------------------------------------------------
|
|
1612
|
+
"/finance/ledger": {
|
|
1613
|
+
get: {
|
|
1614
|
+
tags: ["Financeiro"],
|
|
1615
|
+
summary: "Raz\xE3o financeiro",
|
|
1616
|
+
operationId: "getFinanceLedger",
|
|
1617
|
+
description: "Retorna entradas e sa\xEDdas consolidadas: recebimentos de clientes, pagamentos a fornecedores e despesas.",
|
|
1618
|
+
security: [{ ApiKeyAuth: ["finance:read"] }],
|
|
1619
|
+
parameters: [
|
|
1620
|
+
...PAGINATION_PARAMS,
|
|
1621
|
+
{ name: "start_date", in: "query", schema: { type: "string", format: "date" }, description: "Data inicial (YYYY-MM-DD)" },
|
|
1622
|
+
{ name: "end_date", in: "query", schema: { type: "string", format: "date" }, description: "Data final (YYYY-MM-DD)" },
|
|
1623
|
+
{ name: "direction", in: "query", schema: { type: "string", enum: ["all", "entrada", "saida"], default: "all" } }
|
|
1624
|
+
],
|
|
1625
|
+
responses: {
|
|
1626
|
+
"200": paginatedResponse("#/components/schemas/FinanceLedgerEntry"),
|
|
1627
|
+
...COMMON_ERRORS
|
|
1628
|
+
}
|
|
1629
|
+
}
|
|
1630
|
+
},
|
|
1631
|
+
"/finance/movements": {
|
|
1632
|
+
post: {
|
|
1633
|
+
tags: ["Financeiro"],
|
|
1634
|
+
summary: "Lan\xE7ar movimenta\xE7\xE3o manual",
|
|
1635
|
+
operationId: "createFinancialMovement",
|
|
1636
|
+
security: [{ ApiKeyAuth: ["finance:write"] }],
|
|
1637
|
+
requestBody: { required: true, content: { "application/json": { schema: { $ref: "#/components/schemas/FinancialMovementCreate" } } } },
|
|
1638
|
+
responses: { "201": { description: "Movimenta\xE7\xE3o criada", content: { "application/json": { schema: { $ref: "#/components/schemas/FinancialMovement" } } } }, "400": errorResponse("Dados inv\xE1lidos"), "404": errorResponse("Natureza financeira n\xE3o encontrada"), ...COMMON_ERRORS }
|
|
1639
|
+
}
|
|
1640
|
+
},
|
|
1641
|
+
"/finance/movements/{id}": {
|
|
1642
|
+
parameters: [{ name: "id", in: "path", required: true, schema: { type: "string", format: "uuid" } }],
|
|
1643
|
+
delete: {
|
|
1644
|
+
tags: ["Financeiro"],
|
|
1645
|
+
summary: "Excluir movimenta\xE7\xE3o manual",
|
|
1646
|
+
operationId: "deleteFinancialMovement",
|
|
1647
|
+
security: [{ ApiKeyAuth: ["finance:delete"] }],
|
|
1648
|
+
responses: { "204": { description: "Exclu\xEDda" }, "404": errorResponse("Movimenta\xE7\xE3o n\xE3o encontrada"), "409": errorResponse("Apenas movimenta\xE7\xF5es manuais podem ser exclu\xEDdas"), ...COMMON_ERRORS }
|
|
1649
|
+
}
|
|
1650
|
+
},
|
|
1651
|
+
"/finance/natures": {
|
|
1652
|
+
get: {
|
|
1653
|
+
tags: ["Cat\xE1logos"],
|
|
1654
|
+
summary: "Listar naturezas financeiras",
|
|
1655
|
+
operationId: "listFinancialNatures",
|
|
1656
|
+
description: "IDs usados em POST /v1/finance/movements (nature_id).",
|
|
1657
|
+
security: [{ ApiKeyAuth: ["finance:read", "finance:write"] }],
|
|
1658
|
+
parameters: [...PAGINATION_PARAMS, { name: "is_active", in: "query", schema: { type: "string", enum: ["true", "false"] } }, { name: "direction", in: "query", schema: { type: "string", enum: ["credit", "debit", "both"] } }],
|
|
1659
|
+
responses: { "200": paginatedResponse("#/components/schemas/FinancialNature"), ...COMMON_ERRORS }
|
|
1660
|
+
}
|
|
1661
|
+
},
|
|
1662
|
+
"/cost-centers": {
|
|
1663
|
+
get: {
|
|
1664
|
+
tags: ["Cat\xE1logos"],
|
|
1665
|
+
summary: "Listar centros de custo",
|
|
1666
|
+
operationId: "listCostCenters",
|
|
1667
|
+
description: "IDs usados em despesas (category_id).",
|
|
1668
|
+
security: [{ ApiKeyAuth: ["expenses:read", "expenses:write", "finance:read"] }],
|
|
1669
|
+
parameters: [...PAGINATION_PARAMS, { name: "active", in: "query", schema: { type: "string", enum: ["true", "false"] } }],
|
|
1670
|
+
responses: { "200": paginatedResponse("#/components/schemas/CostCenter"), ...COMMON_ERRORS }
|
|
1671
|
+
}
|
|
1672
|
+
},
|
|
1673
|
+
"/payment-conditions": {
|
|
1674
|
+
get: {
|
|
1675
|
+
tags: ["Cat\xE1logos"],
|
|
1676
|
+
summary: "Listar condi\xE7\xF5es de pagamento",
|
|
1677
|
+
operationId: "listPaymentConditions",
|
|
1678
|
+
security: [{ ApiKeyAuth: ["invoices:read", "contracts:read"] }],
|
|
1679
|
+
parameters: [...PAGINATION_PARAMS, { name: "active", in: "query", schema: { type: "string", enum: ["true", "false"] } }],
|
|
1680
|
+
responses: { "200": paginatedResponse("#/components/schemas/PaymentCondition"), ...COMMON_ERRORS }
|
|
1681
|
+
}
|
|
1682
|
+
},
|
|
1683
|
+
"/service-units": {
|
|
1684
|
+
get: {
|
|
1685
|
+
tags: ["Cat\xE1logos"],
|
|
1686
|
+
summary: "Listar unidades de servi\xE7o",
|
|
1687
|
+
operationId: "listServiceUnits",
|
|
1688
|
+
security: [{ ApiKeyAuth: ["services:read", "services:write"] }],
|
|
1689
|
+
parameters: [...PAGINATION_PARAMS],
|
|
1690
|
+
responses: { "200": paginatedResponse("#/components/schemas/ServiceUnit"), ...COMMON_ERRORS }
|
|
1691
|
+
}
|
|
1692
|
+
},
|
|
1693
|
+
// -----------------------------------------------------------------------
|
|
1694
|
+
// NFS-e
|
|
1695
|
+
// -----------------------------------------------------------------------
|
|
1696
|
+
"/nfse": {
|
|
1697
|
+
get: {
|
|
1698
|
+
tags: ["NFS-e"],
|
|
1699
|
+
summary: "Listar NFS-e",
|
|
1700
|
+
operationId: "listNfse",
|
|
1701
|
+
security: [{ ApiKeyAuth: ["nfse:read"] }],
|
|
1702
|
+
parameters: [
|
|
1703
|
+
...PAGINATION_PARAMS,
|
|
1704
|
+
{ name: "status", in: "query", schema: { type: "string", enum: ["rascunho", "transmitindo", "autorizada", "rejeitada", "cancelada"] } },
|
|
1705
|
+
{ name: "invoice_id", in: "query", schema: { type: "string", format: "uuid" }, description: "Filtrar por fatura" }
|
|
1706
|
+
],
|
|
1707
|
+
responses: {
|
|
1708
|
+
"200": paginatedResponse("#/components/schemas/NfseHistory"),
|
|
1709
|
+
...COMMON_ERRORS
|
|
1710
|
+
}
|
|
1711
|
+
},
|
|
1712
|
+
post: {
|
|
1713
|
+
tags: ["NFS-e"],
|
|
1714
|
+
summary: "Emitir NFS-e",
|
|
1715
|
+
operationId: "emitNfse",
|
|
1716
|
+
description: "Emite uma NFS-e a partir de uma fatura. O m\xE9todo (certificado/portal) vem da configura\xE7\xE3o da empresa. Pode levar alguns segundos.",
|
|
1717
|
+
security: [{ ApiKeyAuth: ["nfse:emitir"] }],
|
|
1718
|
+
requestBody: { required: true, content: { "application/json": { schema: { $ref: "#/components/schemas/NfseEmit" } } } },
|
|
1719
|
+
responses: { "201": { description: "Emiss\xE3o solicitada", content: { "application/json": { schema: { type: "object", properties: { invoice_id: { type: "string" }, status: { type: "string" }, numero_nfse: { type: ["string", "null"] }, chave_acesso: { type: ["string", "null"] }, history_id: { type: ["string", "null"] } } } } } }, "400": errorResponse("invoice_id ausente"), "404": errorResponse("Fatura n\xE3o encontrada"), "422": errorResponse("NFS-e n\xE3o configurada"), "502": errorResponse("Erro do provedor de NFS-e"), ...COMMON_ERRORS }
|
|
1720
|
+
}
|
|
1721
|
+
},
|
|
1722
|
+
"/nfse/{id}/cancel": {
|
|
1723
|
+
parameters: [{ name: "id", in: "path", required: true, schema: { type: "string", format: "uuid" } }],
|
|
1724
|
+
patch: {
|
|
1725
|
+
tags: ["NFS-e"],
|
|
1726
|
+
summary: "Cancelar NFS-e",
|
|
1727
|
+
operationId: "cancelNfse",
|
|
1728
|
+
security: [{ ApiKeyAuth: ["nfse:cancelar"] }],
|
|
1729
|
+
requestBody: { required: true, content: { "application/json": { schema: { $ref: "#/components/schemas/NfseCancel" } } } },
|
|
1730
|
+
responses: { "200": { description: "Cancelamento solicitado", content: { "application/json": { schema: { type: "object", properties: { id: { type: "string" }, status: { type: "string" }, cancel_protocolo: { type: ["string", "null"] } } } } } }, "400": errorResponse("motivo/justificativa inv\xE1lidos"), "404": errorResponse("NFS-e n\xE3o encontrada"), "409": errorResponse("NFS-e n\xE3o est\xE1 autorizada"), "502": errorResponse("Erro do provedor de NFS-e"), ...COMMON_ERRORS }
|
|
1731
|
+
}
|
|
1732
|
+
},
|
|
1733
|
+
"/nfse/{id}": {
|
|
1734
|
+
parameters: [{ name: "id", in: "path", required: true, schema: { type: "string", format: "uuid" } }],
|
|
1735
|
+
get: {
|
|
1736
|
+
tags: ["NFS-e"],
|
|
1737
|
+
summary: "Obter NFS-e",
|
|
1738
|
+
operationId: "getNfse",
|
|
1739
|
+
security: [{ ApiKeyAuth: ["nfse:read"] }],
|
|
1740
|
+
responses: {
|
|
1741
|
+
"200": { description: "NFS-e com detalhes de cancelamento", content: { "application/json": { schema: { $ref: "#/components/schemas/NfseHistoryDetail" } } } },
|
|
1742
|
+
"404": errorResponse("NFS-e n\xE3o encontrada"),
|
|
1743
|
+
...COMMON_ERRORS
|
|
1744
|
+
}
|
|
1745
|
+
}
|
|
1746
|
+
},
|
|
1747
|
+
// -----------------------------------------------------------------------
|
|
1748
|
+
// Fornecedores
|
|
1749
|
+
// -----------------------------------------------------------------------
|
|
1750
|
+
"/suppliers": {
|
|
1751
|
+
get: {
|
|
1752
|
+
tags: ["Fornecedores"],
|
|
1753
|
+
summary: "Listar fornecedores",
|
|
1754
|
+
operationId: "listSuppliers",
|
|
1755
|
+
security: [{ ApiKeyAuth: ["suppliers:read"] }],
|
|
1756
|
+
parameters: [
|
|
1757
|
+
...PAGINATION_PARAMS,
|
|
1758
|
+
{ name: "search", in: "query", schema: { type: "string" }, description: "Busca por nome, e-mail ou documento" },
|
|
1759
|
+
{ name: "status", in: "query", schema: { type: "string", enum: ["ativo", "inativo"] } },
|
|
1760
|
+
{ name: "type", in: "query", schema: { type: "string", enum: ["fisica", "juridica", "estrangeira"] } }
|
|
1761
|
+
],
|
|
1762
|
+
responses: { "200": paginatedResponse("#/components/schemas/Supplier"), ...COMMON_ERRORS }
|
|
1763
|
+
},
|
|
1764
|
+
post: {
|
|
1765
|
+
tags: ["Fornecedores"],
|
|
1766
|
+
summary: "Criar fornecedor",
|
|
1767
|
+
operationId: "createSupplier",
|
|
1768
|
+
security: [{ ApiKeyAuth: ["suppliers:write"] }],
|
|
1769
|
+
requestBody: { required: true, content: { "application/json": { schema: { $ref: "#/components/schemas/SupplierCreate" } } } },
|
|
1770
|
+
responses: {
|
|
1771
|
+
"201": { description: "Fornecedor criado", content: { "application/json": { schema: { $ref: "#/components/schemas/Supplier" } } } },
|
|
1772
|
+
"400": errorResponse("Dados inv\xE1lidos"),
|
|
1773
|
+
...COMMON_ERRORS
|
|
1774
|
+
}
|
|
1775
|
+
}
|
|
1776
|
+
},
|
|
1777
|
+
"/suppliers/{id}": {
|
|
1778
|
+
parameters: [{ name: "id", in: "path", required: true, schema: { type: "string", format: "uuid" } }],
|
|
1779
|
+
get: {
|
|
1780
|
+
tags: ["Fornecedores"],
|
|
1781
|
+
summary: "Obter fornecedor",
|
|
1782
|
+
operationId: "getSupplier",
|
|
1783
|
+
security: [{ ApiKeyAuth: ["suppliers:read"] }],
|
|
1784
|
+
responses: { "200": { description: "Fornecedor", content: { "application/json": { schema: { $ref: "#/components/schemas/Supplier" } } } }, "404": errorResponse("Fornecedor n\xE3o encontrado"), ...COMMON_ERRORS }
|
|
1785
|
+
},
|
|
1786
|
+
patch: {
|
|
1787
|
+
tags: ["Fornecedores"],
|
|
1788
|
+
summary: "Atualizar fornecedor",
|
|
1789
|
+
operationId: "updateSupplier",
|
|
1790
|
+
security: [{ ApiKeyAuth: ["suppliers:write"] }],
|
|
1791
|
+
requestBody: { required: true, content: { "application/json": { schema: { $ref: "#/components/schemas/SupplierCreate" } } } },
|
|
1792
|
+
responses: { "200": { description: "Fornecedor atualizado", content: { "application/json": { schema: { $ref: "#/components/schemas/Supplier" } } } }, "404": errorResponse("Fornecedor n\xE3o encontrado"), ...COMMON_ERRORS }
|
|
1793
|
+
},
|
|
1794
|
+
delete: {
|
|
1795
|
+
tags: ["Fornecedores"],
|
|
1796
|
+
summary: "Excluir fornecedor",
|
|
1797
|
+
operationId: "deleteSupplier",
|
|
1798
|
+
security: [{ ApiKeyAuth: ["suppliers:delete"] }],
|
|
1799
|
+
responses: { "204": { description: "Exclu\xEDdo" }, "404": errorResponse("Fornecedor n\xE3o encontrado"), "409": errorResponse("H\xE1 registros vinculados (contas a pagar, despesas, etc.) que impedem a exclus\xE3o"), ...COMMON_ERRORS }
|
|
1800
|
+
}
|
|
1801
|
+
},
|
|
1802
|
+
// -----------------------------------------------------------------------
|
|
1803
|
+
// Serviços
|
|
1804
|
+
// -----------------------------------------------------------------------
|
|
1805
|
+
"/services": {
|
|
1806
|
+
get: {
|
|
1807
|
+
tags: ["Servi\xE7os"],
|
|
1808
|
+
summary: "Listar servi\xE7os",
|
|
1809
|
+
operationId: "listServices",
|
|
1810
|
+
security: [{ ApiKeyAuth: ["services:read"] }],
|
|
1811
|
+
parameters: [
|
|
1812
|
+
...PAGINATION_PARAMS,
|
|
1813
|
+
{ name: "search", in: "query", schema: { type: "string" }, description: "Busca por nome ou descri\xE7\xE3o" },
|
|
1814
|
+
{ name: "active", in: "query", schema: { type: "string", enum: ["true", "false"] } }
|
|
1815
|
+
],
|
|
1816
|
+
responses: { "200": paginatedResponse("#/components/schemas/Service"), ...COMMON_ERRORS }
|
|
1817
|
+
},
|
|
1818
|
+
post: {
|
|
1819
|
+
tags: ["Servi\xE7os"],
|
|
1820
|
+
summary: "Criar servi\xE7o",
|
|
1821
|
+
operationId: "createService",
|
|
1822
|
+
security: [{ ApiKeyAuth: ["services:write"] }],
|
|
1823
|
+
requestBody: { required: true, content: { "application/json": { schema: { $ref: "#/components/schemas/ServiceCreate" } } } },
|
|
1824
|
+
responses: { "201": { description: "Servi\xE7o criado", content: { "application/json": { schema: { $ref: "#/components/schemas/Service" } } } }, "400": errorResponse("Dados inv\xE1lidos"), ...COMMON_ERRORS }
|
|
1825
|
+
}
|
|
1826
|
+
},
|
|
1827
|
+
"/services/{id}": {
|
|
1828
|
+
parameters: [{ name: "id", in: "path", required: true, schema: { type: "string", format: "uuid" } }],
|
|
1829
|
+
get: {
|
|
1830
|
+
tags: ["Servi\xE7os"],
|
|
1831
|
+
summary: "Obter servi\xE7o",
|
|
1832
|
+
operationId: "getService",
|
|
1833
|
+
security: [{ ApiKeyAuth: ["services:read"] }],
|
|
1834
|
+
responses: { "200": { description: "Servi\xE7o", content: { "application/json": { schema: { $ref: "#/components/schemas/Service" } } } }, "404": errorResponse("Servi\xE7o n\xE3o encontrado"), ...COMMON_ERRORS }
|
|
1835
|
+
},
|
|
1836
|
+
patch: {
|
|
1837
|
+
tags: ["Servi\xE7os"],
|
|
1838
|
+
summary: "Atualizar servi\xE7o",
|
|
1839
|
+
operationId: "updateService",
|
|
1840
|
+
security: [{ ApiKeyAuth: ["services:write"] }],
|
|
1841
|
+
requestBody: { required: true, content: { "application/json": { schema: { $ref: "#/components/schemas/ServiceCreate" } } } },
|
|
1842
|
+
responses: { "200": { description: "Servi\xE7o atualizado", content: { "application/json": { schema: { $ref: "#/components/schemas/Service" } } } }, "404": errorResponse("Servi\xE7o n\xE3o encontrado"), ...COMMON_ERRORS }
|
|
1843
|
+
},
|
|
1844
|
+
delete: {
|
|
1845
|
+
tags: ["Servi\xE7os"],
|
|
1846
|
+
summary: "Excluir servi\xE7o",
|
|
1847
|
+
operationId: "deleteService",
|
|
1848
|
+
security: [{ ApiKeyAuth: ["services:delete"] }],
|
|
1849
|
+
responses: { "204": { description: "Exclu\xEDdo" }, "404": errorResponse("Servi\xE7o n\xE3o encontrado"), "409": errorResponse("H\xE1 registros vinculados que impedem a exclus\xE3o"), ...COMMON_ERRORS }
|
|
1850
|
+
}
|
|
1851
|
+
},
|
|
1852
|
+
// -----------------------------------------------------------------------
|
|
1853
|
+
// Despesas
|
|
1854
|
+
// -----------------------------------------------------------------------
|
|
1855
|
+
"/expenses": {
|
|
1856
|
+
get: {
|
|
1857
|
+
tags: ["Despesas"],
|
|
1858
|
+
summary: "Listar despesas",
|
|
1859
|
+
operationId: "listExpenses",
|
|
1860
|
+
security: [{ ApiKeyAuth: ["expenses:read"] }],
|
|
1861
|
+
parameters: [
|
|
1862
|
+
...PAGINATION_PARAMS,
|
|
1863
|
+
{ name: "status", in: "query", schema: { type: "string", enum: ["pendente", "pago", "cancelado"] } },
|
|
1864
|
+
{ name: "supplier_id", in: "query", schema: { type: "string", format: "uuid" } },
|
|
1865
|
+
{ name: "category_id", in: "query", schema: { type: "string", format: "uuid" } },
|
|
1866
|
+
{ name: "expense_date_from", in: "query", schema: { type: "string", format: "date" } },
|
|
1867
|
+
{ name: "expense_date_to", in: "query", schema: { type: "string", format: "date" } }
|
|
1868
|
+
],
|
|
1869
|
+
responses: { "200": paginatedResponse("#/components/schemas/Expense"), ...COMMON_ERRORS }
|
|
1870
|
+
},
|
|
1871
|
+
post: {
|
|
1872
|
+
tags: ["Despesas"],
|
|
1873
|
+
summary: "Criar despesa",
|
|
1874
|
+
operationId: "createExpense",
|
|
1875
|
+
security: [{ ApiKeyAuth: ["expenses:write"] }],
|
|
1876
|
+
requestBody: { required: true, content: { "application/json": { schema: { $ref: "#/components/schemas/ExpenseCreate" } } } },
|
|
1877
|
+
responses: { "201": { description: "Despesa criada", content: { "application/json": { schema: { $ref: "#/components/schemas/Expense" } } } }, "400": errorResponse("Dados inv\xE1lidos"), "404": errorResponse("Fornecedor n\xE3o encontrado"), ...COMMON_ERRORS }
|
|
1878
|
+
}
|
|
1879
|
+
},
|
|
1880
|
+
"/expenses/{id}": {
|
|
1881
|
+
parameters: [{ name: "id", in: "path", required: true, schema: { type: "string", format: "uuid" } }],
|
|
1882
|
+
get: {
|
|
1883
|
+
tags: ["Despesas"],
|
|
1884
|
+
summary: "Obter despesa",
|
|
1885
|
+
operationId: "getExpense",
|
|
1886
|
+
security: [{ ApiKeyAuth: ["expenses:read"] }],
|
|
1887
|
+
responses: { "200": { description: "Despesa", content: { "application/json": { schema: { $ref: "#/components/schemas/Expense" } } } }, "404": errorResponse("Despesa n\xE3o encontrada"), ...COMMON_ERRORS }
|
|
1888
|
+
},
|
|
1889
|
+
patch: {
|
|
1890
|
+
tags: ["Despesas"],
|
|
1891
|
+
summary: "Atualizar despesa",
|
|
1892
|
+
operationId: "updateExpense",
|
|
1893
|
+
security: [{ ApiKeyAuth: ["expenses:write"] }],
|
|
1894
|
+
requestBody: { required: true, content: { "application/json": { schema: { $ref: "#/components/schemas/ExpenseCreate" } } } },
|
|
1895
|
+
responses: { "200": { description: "Despesa atualizada", content: { "application/json": { schema: { $ref: "#/components/schemas/Expense" } } } }, "404": errorResponse("Despesa n\xE3o encontrada"), ...COMMON_ERRORS }
|
|
1896
|
+
},
|
|
1897
|
+
delete: {
|
|
1898
|
+
tags: ["Despesas"],
|
|
1899
|
+
summary: "Excluir despesa",
|
|
1900
|
+
operationId: "deleteExpense",
|
|
1901
|
+
security: [{ ApiKeyAuth: ["expenses:delete"] }],
|
|
1902
|
+
responses: { "204": { description: "Exclu\xEDda" }, "404": errorResponse("Despesa n\xE3o encontrada"), "409": errorResponse("H\xE1 registros vinculados que impedem a exclus\xE3o"), ...COMMON_ERRORS }
|
|
1903
|
+
}
|
|
1904
|
+
},
|
|
1905
|
+
// -----------------------------------------------------------------------
|
|
1906
|
+
// Contas a Pagar
|
|
1907
|
+
// -----------------------------------------------------------------------
|
|
1908
|
+
"/purchase-invoices": {
|
|
1909
|
+
get: {
|
|
1910
|
+
tags: ["Contas a Pagar"],
|
|
1911
|
+
summary: "Listar contas a pagar",
|
|
1912
|
+
operationId: "listPurchaseInvoices",
|
|
1913
|
+
security: [{ ApiKeyAuth: ["purchase_invoices:read"] }],
|
|
1914
|
+
parameters: [
|
|
1915
|
+
...PAGINATION_PARAMS,
|
|
1916
|
+
{ name: "status", in: "query", schema: { type: "string", enum: ["rascunho", "recebida", "aprovada", "cancelada"] } },
|
|
1917
|
+
{ name: "payment_status", in: "query", schema: { type: "string", enum: ["pendente", "parcial", "pago", "vencido"] } },
|
|
1918
|
+
{ name: "supplier_id", in: "query", schema: { type: "string", format: "uuid" } },
|
|
1919
|
+
{ name: "invoice_number", in: "query", schema: { type: "string" } },
|
|
1920
|
+
{ name: "due_date_from", in: "query", schema: { type: "string", format: "date" } },
|
|
1921
|
+
{ name: "due_date_to", in: "query", schema: { type: "string", format: "date" } }
|
|
1922
|
+
],
|
|
1923
|
+
responses: { "200": paginatedResponse("#/components/schemas/PurchaseInvoice"), ...COMMON_ERRORS }
|
|
1924
|
+
},
|
|
1925
|
+
post: {
|
|
1926
|
+
tags: ["Contas a Pagar"],
|
|
1927
|
+
summary: "Criar conta a pagar",
|
|
1928
|
+
operationId: "createPurchaseInvoice",
|
|
1929
|
+
security: [{ ApiKeyAuth: ["purchase_invoices:create"] }],
|
|
1930
|
+
requestBody: { required: true, content: { "application/json": { schema: { $ref: "#/components/schemas/PurchaseInvoiceCreate" } } } },
|
|
1931
|
+
responses: { "201": { description: "Conta a pagar criada", content: { "application/json": { schema: { $ref: "#/components/schemas/PurchaseInvoice" } } } }, "400": errorResponse("Dados inv\xE1lidos"), "404": errorResponse("Fornecedor n\xE3o encontrado"), ...COMMON_ERRORS }
|
|
1932
|
+
}
|
|
1933
|
+
},
|
|
1934
|
+
"/purchase-invoices/{id}": {
|
|
1935
|
+
parameters: [{ name: "id", in: "path", required: true, schema: { type: "string", format: "uuid" } }],
|
|
1936
|
+
get: {
|
|
1937
|
+
tags: ["Contas a Pagar"],
|
|
1938
|
+
summary: "Obter conta a pagar (com itens e parcelas)",
|
|
1939
|
+
operationId: "getPurchaseInvoice",
|
|
1940
|
+
security: [{ ApiKeyAuth: ["purchase_invoices:read"] }],
|
|
1941
|
+
responses: { "200": { description: "Conta a pagar", content: { "application/json": { schema: { $ref: "#/components/schemas/PurchaseInvoice" } } } }, "404": errorResponse("Conta a pagar n\xE3o encontrada"), ...COMMON_ERRORS }
|
|
1942
|
+
}
|
|
1943
|
+
},
|
|
1944
|
+
"/purchase-invoices/{id}/cancel": {
|
|
1945
|
+
parameters: [{ name: "id", in: "path", required: true, schema: { type: "string", format: "uuid" } }],
|
|
1946
|
+
patch: {
|
|
1947
|
+
tags: ["Contas a Pagar"],
|
|
1948
|
+
summary: "Cancelar conta a pagar",
|
|
1949
|
+
operationId: "cancelPurchaseInvoice",
|
|
1950
|
+
security: [{ ApiKeyAuth: ["purchase_invoices:cancel"] }],
|
|
1951
|
+
responses: { "200": { description: "Cancelada", content: { "application/json": { schema: { $ref: "#/components/schemas/PurchaseInvoice" } } } }, "404": errorResponse("Conta a pagar n\xE3o encontrada"), "409": errorResponse("J\xE1 cancelada"), ...COMMON_ERRORS }
|
|
1952
|
+
}
|
|
1953
|
+
},
|
|
1954
|
+
// -----------------------------------------------------------------------
|
|
1955
|
+
// Cobranças (Gateway)
|
|
1956
|
+
// -----------------------------------------------------------------------
|
|
1957
|
+
"/charges": {
|
|
1958
|
+
get: {
|
|
1959
|
+
tags: ["Cobran\xE7as"],
|
|
1960
|
+
summary: "Listar cobran\xE7as",
|
|
1961
|
+
operationId: "listCharges",
|
|
1962
|
+
security: [{ ApiKeyAuth: ["charges:read"] }],
|
|
1963
|
+
parameters: [
|
|
1964
|
+
...PAGINATION_PARAMS,
|
|
1965
|
+
{ 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"] } },
|
|
1967
|
+
{ name: "customer_id", in: "query", schema: { type: "string", format: "uuid" } },
|
|
1968
|
+
{ name: "invoice_id", in: "query", schema: { type: "string", format: "uuid" } }
|
|
1969
|
+
],
|
|
1970
|
+
responses: { "200": paginatedResponse("#/components/schemas/Charge"), ...COMMON_ERRORS }
|
|
1971
|
+
},
|
|
1972
|
+
post: {
|
|
1973
|
+
tags: ["Cobran\xE7as"],
|
|
1974
|
+
summary: "Criar cobran\xE7a (Pix, boleto ou checkout)",
|
|
1975
|
+
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.",
|
|
1977
|
+
security: [{ ApiKeyAuth: ["charges:create"] }],
|
|
1978
|
+
requestBody: { required: true, content: { "application/json": { schema: { $ref: "#/components/schemas/ChargeCreate" } } } },
|
|
1979
|
+
responses: {
|
|
1980
|
+
"201": { description: "Cobran\xE7a criada", content: { "application/json": { schema: { $ref: "#/components/schemas/Charge" } } } },
|
|
1981
|
+
"400": errorResponse("Dados inv\xE1lidos"),
|
|
1982
|
+
"409": errorResponse("Fatura j\xE1 paga"),
|
|
1983
|
+
"422": errorResponse("Integra\xE7\xE3o banc\xE1ria n\xE3o configurada"),
|
|
1984
|
+
...COMMON_ERRORS
|
|
1985
|
+
}
|
|
1986
|
+
}
|
|
1987
|
+
},
|
|
1988
|
+
"/charges/{id}": {
|
|
1989
|
+
parameters: [{ name: "id", in: "path", required: true, schema: { type: "string", format: "uuid" } }],
|
|
1990
|
+
get: {
|
|
1991
|
+
tags: ["Cobran\xE7as"],
|
|
1992
|
+
summary: "Obter cobran\xE7a",
|
|
1993
|
+
operationId: "getCharge",
|
|
1994
|
+
security: [{ ApiKeyAuth: ["charges:read"] }],
|
|
1995
|
+
responses: { "200": { description: "Cobran\xE7a", content: { "application/json": { schema: { $ref: "#/components/schemas/Charge" } } } }, "404": errorResponse("Cobran\xE7a n\xE3o encontrada"), ...COMMON_ERRORS }
|
|
1996
|
+
},
|
|
1997
|
+
delete: {
|
|
1998
|
+
tags: ["Cobran\xE7as"],
|
|
1999
|
+
summary: "Cancelar cobran\xE7a",
|
|
2000
|
+
operationId: "cancelCharge",
|
|
2001
|
+
security: [{ ApiKeyAuth: ["charges:cancel"] }],
|
|
2002
|
+
responses: { "200": { description: "Cancelamento solicitado" }, "404": errorResponse("Cobran\xE7a n\xE3o encontrada"), "409": errorResponse("Cobran\xE7a n\xE3o pode ser cancelada no estado atual"), ...COMMON_ERRORS }
|
|
2003
|
+
}
|
|
2004
|
+
},
|
|
2005
|
+
"/charges/{id}/refund": {
|
|
2006
|
+
parameters: [{ name: "id", in: "path", required: true, schema: { type: "string", format: "uuid" } }],
|
|
2007
|
+
post: {
|
|
2008
|
+
tags: ["Cobran\xE7as"],
|
|
2009
|
+
summary: "Estornar cobran\xE7a (devolu\xE7\xE3o Pix)",
|
|
2010
|
+
operationId: "refundCharge",
|
|
2011
|
+
description: "Estorna (devolve) uma cobran\xE7a Pix paga. Dispon\xEDvel apenas para Pix \u2014 boleto e checkout retornam 422. Requer que o endToEndId do pagamento tenha sido capturado.",
|
|
2012
|
+
security: [{ ApiKeyAuth: ["charges:refund"] }],
|
|
2013
|
+
responses: {
|
|
2014
|
+
"200": { description: "Devolu\xE7\xE3o solicitada", content: { "application/json": { schema: { type: "object", properties: { id: { type: "string" }, status: { type: "string" }, provider: { type: "string" }, amount: { type: "number" }, message: { type: "string" } } } } } },
|
|
2015
|
+
"404": errorResponse("Cobran\xE7a n\xE3o encontrada"),
|
|
2016
|
+
"409": errorResponse("Cobran\xE7a n\xE3o est\xE1 paga ou j\xE1 estornada"),
|
|
2017
|
+
"422": errorResponse("M\xE9todo n\xE3o suportado (apenas Pix) ou endToEndId indispon\xEDvel"),
|
|
2018
|
+
...COMMON_ERRORS
|
|
2019
|
+
}
|
|
2020
|
+
}
|
|
2021
|
+
},
|
|
2022
|
+
"/charges/{id}/confirm": {
|
|
2023
|
+
parameters: [{ name: "id", in: "path", required: true, schema: { type: "string", format: "uuid" } }],
|
|
2024
|
+
post: {
|
|
2025
|
+
tags: ["Cobran\xE7as"],
|
|
2026
|
+
summary: "Confirmar pagamento (Pix est\xE1tico/offline)",
|
|
2027
|
+
operationId: "confirmCharge",
|
|
2028
|
+
description: "Marca manualmente uma cobran\xE7a Pix est\xE1tico (provider 'pix_offline') como paga e dispara o webhook charge.paid. Para Inter/C6 a baixa vem do banco (n\xE3o use este endpoint).",
|
|
2029
|
+
security: [{ ApiKeyAuth: ["charges:create"] }],
|
|
2030
|
+
responses: {
|
|
2031
|
+
"200": { description: "Cobran\xE7a confirmada (paga)", content: { "application/json": { schema: { $ref: "#/components/schemas/Charge" } } } },
|
|
2032
|
+
"404": errorResponse("Cobran\xE7a n\xE3o encontrada"),
|
|
2033
|
+
"409": errorResponse("Cobran\xE7a j\xE1 paga ou em estado terminal"),
|
|
2034
|
+
"422": errorResponse("Confirma\xE7\xE3o manual s\xF3 vale para Pix est\xE1tico/offline"),
|
|
2035
|
+
...COMMON_ERRORS
|
|
2036
|
+
}
|
|
2037
|
+
}
|
|
2038
|
+
},
|
|
2039
|
+
// -----------------------------------------------------------------------
|
|
2040
|
+
// Webhooks
|
|
2041
|
+
// -----------------------------------------------------------------------
|
|
2042
|
+
"/webhooks": {
|
|
2043
|
+
get: {
|
|
2044
|
+
tags: ["Webhooks"],
|
|
2045
|
+
summary: "Listar webhooks da empresa",
|
|
2046
|
+
operationId: "listWebhooks",
|
|
2047
|
+
description: "Lista todos os webhooks da empresa. Webhooks s\xE3o por empresa (n\xE3o por API key) e voc\xEA pode ter v\xE1rios, cada um com seus eventos.",
|
|
2048
|
+
security: [{ ApiKeyAuth: ["webhooks:manage"] }],
|
|
2049
|
+
responses: { "200": { description: "Lista", content: { "application/json": { schema: { type: "object", properties: { data: { type: "array", items: { $ref: "#/components/schemas/Webhook" } } } } } } }, ...COMMON_ERRORS }
|
|
2050
|
+
},
|
|
2051
|
+
post: {
|
|
2052
|
+
tags: ["Webhooks"],
|
|
2053
|
+
summary: "Criar webhook",
|
|
2054
|
+
operationId: "createWebhook",
|
|
2055
|
+
description: "Cria um webhook. O secret HMAC-SHA256 \xE9 retornado apenas na cria\xE7\xE3o (guarde-o).",
|
|
2056
|
+
security: [{ ApiKeyAuth: ["webhooks:manage"] }],
|
|
2057
|
+
requestBody: { required: true, content: { "application/json": { schema: { $ref: "#/components/schemas/WebhookCreate" } } } },
|
|
2058
|
+
responses: {
|
|
2059
|
+
"201": { description: "Webhook criado (inclui secret \xFAnico)", content: { "application/json": { schema: { type: "object", properties: { webhook: { $ref: "#/components/schemas/Webhook" }, secret: { type: "string" } } } } } },
|
|
2060
|
+
"400": errorResponse("Dados inv\xE1lidos"),
|
|
2061
|
+
...COMMON_ERRORS
|
|
2062
|
+
}
|
|
2063
|
+
}
|
|
2064
|
+
},
|
|
2065
|
+
"/webhooks/{id}": {
|
|
2066
|
+
parameters: [{ name: "id", in: "path", required: true, schema: { type: "string", format: "uuid" } }],
|
|
2067
|
+
get: {
|
|
2068
|
+
tags: ["Webhooks"],
|
|
2069
|
+
summary: "Obter webhook",
|
|
2070
|
+
operationId: "getWebhookById",
|
|
2071
|
+
security: [{ ApiKeyAuth: ["webhooks:manage"] }],
|
|
2072
|
+
responses: { "200": { description: "Webhook", content: { "application/json": { schema: { $ref: "#/components/schemas/Webhook" } } } }, "404": errorResponse("N\xE3o encontrado"), ...COMMON_ERRORS }
|
|
2073
|
+
},
|
|
2074
|
+
patch: {
|
|
2075
|
+
tags: ["Webhooks"],
|
|
2076
|
+
summary: "Atualizar webhook",
|
|
2077
|
+
operationId: "updateWebhook",
|
|
2078
|
+
security: [{ ApiKeyAuth: ["webhooks:manage"] }],
|
|
2079
|
+
requestBody: { required: true, content: { "application/json": { schema: { $ref: "#/components/schemas/WebhookCreate" } } } },
|
|
2080
|
+
responses: { "200": { description: "Atualizado", content: { "application/json": { schema: { $ref: "#/components/schemas/Webhook" } } } }, "404": errorResponse("N\xE3o encontrado"), ...COMMON_ERRORS }
|
|
2081
|
+
},
|
|
2082
|
+
delete: {
|
|
2083
|
+
tags: ["Webhooks"],
|
|
2084
|
+
summary: "Excluir webhook",
|
|
2085
|
+
operationId: "deleteWebhook",
|
|
2086
|
+
security: [{ ApiKeyAuth: ["webhooks:manage"] }],
|
|
2087
|
+
responses: { "204": { description: "Exclu\xEDdo" }, "404": errorResponse("N\xE3o encontrado"), ...COMMON_ERRORS }
|
|
2088
|
+
}
|
|
2089
|
+
},
|
|
2090
|
+
"/webhooks/events": {
|
|
2091
|
+
get: {
|
|
2092
|
+
tags: ["Webhooks"],
|
|
2093
|
+
summary: "Cat\xE1logo de eventos dispon\xEDveis",
|
|
2094
|
+
operationId: "listWebhookEvents",
|
|
2095
|
+
description: "Lista todos os eventos que um webhook pode assinar (key, label, group).",
|
|
2096
|
+
security: [{ ApiKeyAuth: ["webhooks:manage"] }],
|
|
2097
|
+
responses: { "200": { description: "Cat\xE1logo", content: { "application/json": { schema: { type: "object", properties: { data: { type: "array", items: { type: "object", properties: { key: { type: "string" }, label: { type: "string" }, group: { type: "string" } } } } } } } } }, ...COMMON_ERRORS }
|
|
2098
|
+
}
|
|
2099
|
+
},
|
|
2100
|
+
"/webhooks/{id}/test": {
|
|
2101
|
+
parameters: [{ name: "id", in: "path", required: true, schema: { type: "string", format: "uuid" } }],
|
|
2102
|
+
post: {
|
|
2103
|
+
tags: ["Webhooks"],
|
|
2104
|
+
summary: "Enviar evento de teste",
|
|
2105
|
+
operationId: "testWebhook",
|
|
2106
|
+
description: "Enfileira um evento `webhook.test` direcionado apenas a este webhook (para validar a URL e a verifica\xE7\xE3o de assinatura).",
|
|
2107
|
+
security: [{ ApiKeyAuth: ["webhooks:manage"] }],
|
|
2108
|
+
responses: { "202": { description: "Teste enfileirado", content: { "application/json": { schema: { type: "object", properties: { message: { type: "string" }, delivery: { type: "object" } } } } } }, "404": errorResponse("Webhook n\xE3o encontrado"), ...COMMON_ERRORS }
|
|
2109
|
+
}
|
|
2110
|
+
},
|
|
2111
|
+
"/webhooks/payments": {
|
|
2112
|
+
get: {
|
|
2113
|
+
tags: ["Webhooks"],
|
|
2114
|
+
summary: "Obter configura\xE7\xE3o de webhook",
|
|
2115
|
+
operationId: "getWebhook",
|
|
2116
|
+
security: [{ ApiKeyAuth: ["webhooks:manage"] }],
|
|
2117
|
+
responses: { "200": { description: "Configura\xE7\xE3o atual", content: { "application/json": { schema: { type: "object", properties: { webhook: { oneOf: [{ $ref: "#/components/schemas/Webhook" }, { type: "null" }] } } } } } }, ...COMMON_ERRORS }
|
|
2118
|
+
},
|
|
2119
|
+
put: {
|
|
2120
|
+
tags: ["Webhooks"],
|
|
2121
|
+
summary: "Registrar/atualizar webhook",
|
|
2122
|
+
operationId: "upsertWebhook",
|
|
2123
|
+
description: "Cria ou atualiza a URL de callback. O secret HMAC-SHA256 \xE9 retornado apenas na cria\xE7\xE3o.",
|
|
2124
|
+
security: [{ ApiKeyAuth: ["webhooks:manage"] }],
|
|
2125
|
+
requestBody: { required: true, content: { "application/json": { schema: { $ref: "#/components/schemas/WebhookCreate" } } } },
|
|
2126
|
+
responses: {
|
|
2127
|
+
"200": { description: "Webhook atualizado", content: { "application/json": { schema: { type: "object", properties: { webhook: { $ref: "#/components/schemas/Webhook" } } } } } },
|
|
2128
|
+
"201": { description: "Webhook criado (inclui secret \xFAnico)", content: { "application/json": { schema: { type: "object", properties: { webhook: { $ref: "#/components/schemas/Webhook" }, secret: { type: "string" } } } } } },
|
|
2129
|
+
"400": errorResponse("URL inv\xE1lida ou eventos inv\xE1lidos"),
|
|
2130
|
+
...COMMON_ERRORS
|
|
2131
|
+
}
|
|
2132
|
+
},
|
|
2133
|
+
delete: {
|
|
2134
|
+
tags: ["Webhooks"],
|
|
2135
|
+
summary: "Remover webhook",
|
|
2136
|
+
operationId: "deleteWebhook",
|
|
2137
|
+
security: [{ ApiKeyAuth: ["webhooks:manage"] }],
|
|
2138
|
+
responses: { "200": { description: "Removido" }, "404": errorResponse("Nenhum webhook configurado"), ...COMMON_ERRORS }
|
|
2139
|
+
}
|
|
2140
|
+
},
|
|
2141
|
+
"/webhooks/deliveries": {
|
|
2142
|
+
get: {
|
|
2143
|
+
tags: ["Webhooks"],
|
|
2144
|
+
summary: "Listar entregas de webhook (log)",
|
|
2145
|
+
operationId: "listWebhookDeliveries",
|
|
2146
|
+
description: "Hist\xF3rico de entregas com status, tentativas e erro. Entregas s\xE3o reprocessadas automaticamente com backoff.",
|
|
2147
|
+
security: [{ ApiKeyAuth: ["webhooks:manage"] }],
|
|
2148
|
+
parameters: [...PAGINATION_PARAMS, { name: "status", in: "query", schema: { type: "string", enum: ["pending", "delivering", "delivered", "failed"] } }, { name: "event", in: "query", schema: { type: "string" } }],
|
|
2149
|
+
responses: { "200": paginatedResponse("#/components/schemas/WebhookDelivery"), ...COMMON_ERRORS }
|
|
2150
|
+
}
|
|
2151
|
+
},
|
|
2152
|
+
"/webhooks/deliveries/{id}/redeliver": {
|
|
2153
|
+
parameters: [{ name: "id", in: "path", required: true, schema: { type: "string", format: "uuid" } }],
|
|
2154
|
+
post: {
|
|
2155
|
+
tags: ["Webhooks"],
|
|
2156
|
+
summary: "Reenviar entrega",
|
|
2157
|
+
operationId: "redeliverWebhook",
|
|
2158
|
+
security: [{ ApiKeyAuth: ["webhooks:manage"] }],
|
|
2159
|
+
responses: { "200": { description: "Re-enfileirada", content: { "application/json": { schema: { $ref: "#/components/schemas/WebhookDelivery" } } } }, "404": errorResponse("Entrega n\xE3o encontrada"), ...COMMON_ERRORS }
|
|
2160
|
+
}
|
|
2161
|
+
},
|
|
2162
|
+
// -----------------------------------------------------------------------
|
|
2163
|
+
// Contas bancárias (read-only)
|
|
2164
|
+
// -----------------------------------------------------------------------
|
|
2165
|
+
"/bank-accounts": {
|
|
2166
|
+
get: {
|
|
2167
|
+
tags: ["Contas banc\xE1rias"],
|
|
2168
|
+
summary: "Listar contas banc\xE1rias",
|
|
2169
|
+
operationId: "listBankAccounts",
|
|
2170
|
+
security: [{ ApiKeyAuth: ["bank_accounts:read"] }],
|
|
2171
|
+
parameters: [
|
|
2172
|
+
...PAGINATION_PARAMS,
|
|
2173
|
+
{ name: "active", in: "query", schema: { type: "string", enum: ["true", "false"] } },
|
|
2174
|
+
{ name: "account_type", in: "query", schema: { type: "string" } }
|
|
2175
|
+
],
|
|
2176
|
+
responses: { "200": paginatedResponse("#/components/schemas/BankAccount"), ...COMMON_ERRORS }
|
|
2177
|
+
}
|
|
2178
|
+
},
|
|
2179
|
+
"/bank-accounts/{id}": {
|
|
2180
|
+
parameters: [{ name: "id", in: "path", required: true, schema: { type: "string", format: "uuid" } }],
|
|
2181
|
+
get: {
|
|
2182
|
+
tags: ["Contas banc\xE1rias"],
|
|
2183
|
+
summary: "Obter conta banc\xE1ria",
|
|
2184
|
+
operationId: "getBankAccount",
|
|
2185
|
+
security: [{ ApiKeyAuth: ["bank_accounts:read"] }],
|
|
2186
|
+
responses: { "200": { description: "Conta banc\xE1ria", content: { "application/json": { schema: { $ref: "#/components/schemas/BankAccount" } } } }, "404": errorResponse("Conta banc\xE1ria n\xE3o encontrada"), ...COMMON_ERRORS }
|
|
2187
|
+
}
|
|
2188
|
+
},
|
|
2189
|
+
// -----------------------------------------------------------------------
|
|
2190
|
+
// Pagamentos a Fornecedor (Payouts)
|
|
2191
|
+
// -----------------------------------------------------------------------
|
|
2192
|
+
"/payouts": {
|
|
2193
|
+
get: {
|
|
2194
|
+
tags: ["Pagamentos a Fornecedor"],
|
|
2195
|
+
summary: "Listar pagamentos a fornecedor",
|
|
2196
|
+
operationId: "listPayouts",
|
|
2197
|
+
security: [{ ApiKeyAuth: ["payouts:read"] }],
|
|
2198
|
+
parameters: [
|
|
2199
|
+
...PAGINATION_PARAMS,
|
|
2200
|
+
{ name: "status", in: "query", schema: { type: "string", enum: ["pending", "processing", "completed", "failed", "cancelled"] } },
|
|
2201
|
+
{ name: "provider", in: "query", schema: { type: "string", enum: ["inter", "c6bank"] } },
|
|
2202
|
+
{ name: "method", in: "query", schema: { type: "string", enum: ["pix", "boleto"] } },
|
|
2203
|
+
{ name: "bank_account_id", in: "query", schema: { type: "string", format: "uuid" } },
|
|
2204
|
+
{ name: "scheduled_from", in: "query", schema: { type: "string", format: "date" } },
|
|
2205
|
+
{ name: "scheduled_to", in: "query", schema: { type: "string", format: "date" } }
|
|
2206
|
+
],
|
|
2207
|
+
responses: { "200": paginatedResponse("#/components/schemas/Payout"), ...COMMON_ERRORS }
|
|
2208
|
+
},
|
|
2209
|
+
post: {
|
|
2210
|
+
tags: ["Pagamentos a Fornecedor"],
|
|
2211
|
+
summary: "Pagar ou agendar pagamento (Pix/boleto)",
|
|
2212
|
+
operationId: "createPayout",
|
|
2213
|
+
description: "Executa ou agenda um pagamento a fornecedor no provider ativo (Inter/C6). Informe o alvo via purchase_invoice_charge_id, supplier_payment_method_id, pix_key/pix_copia_e_cola ou boleto_barcode.",
|
|
2214
|
+
security: [{ ApiKeyAuth: ["payouts:create"] }],
|
|
2215
|
+
requestBody: { required: true, content: { "application/json": { schema: { $ref: "#/components/schemas/PayoutCreate" } } } },
|
|
2216
|
+
responses: {
|
|
2217
|
+
"201": { description: "Pagamento criado/executado", content: { "application/json": { schema: { $ref: "#/components/schemas/Payout" } } } },
|
|
2218
|
+
"400": errorResponse("Dados inv\xE1lidos / alvo ausente"),
|
|
2219
|
+
"404": errorResponse("Conta banc\xE1ria, parcela ou fornecedor n\xE3o encontrado"),
|
|
2220
|
+
"422": errorResponse("Integra\xE7\xE3o n\xE3o configurada ou provider amb\xEDguo"),
|
|
2221
|
+
"502": errorResponse("Erro retornado pelo banco"),
|
|
2222
|
+
...COMMON_ERRORS
|
|
2223
|
+
}
|
|
2224
|
+
}
|
|
2225
|
+
},
|
|
2226
|
+
"/payouts/{id}": {
|
|
2227
|
+
parameters: [{ name: "id", in: "path", required: true, schema: { type: "string", format: "uuid" } }],
|
|
2228
|
+
get: {
|
|
2229
|
+
tags: ["Pagamentos a Fornecedor"],
|
|
2230
|
+
summary: "Obter pagamento",
|
|
2231
|
+
operationId: "getPayout",
|
|
2232
|
+
security: [{ ApiKeyAuth: ["payouts:read"] }],
|
|
2233
|
+
responses: { "200": { description: "Pagamento", content: { "application/json": { schema: { $ref: "#/components/schemas/Payout" } } } }, "404": errorResponse("Pagamento n\xE3o encontrado"), ...COMMON_ERRORS }
|
|
2234
|
+
}
|
|
2235
|
+
},
|
|
2236
|
+
"/payouts/{id}/cancel": {
|
|
2237
|
+
parameters: [{ name: "id", in: "path", required: true, schema: { type: "string", format: "uuid" } }],
|
|
2238
|
+
post: {
|
|
2239
|
+
tags: ["Pagamentos a Fornecedor"],
|
|
2240
|
+
summary: "Cancelar pagamento agendado",
|
|
2241
|
+
operationId: "cancelPayout",
|
|
2242
|
+
description: "Cancela um pagamento agendado. Pix agendado no Inter n\xE3o \xE9 cancel\xE1vel pela API (retorna 422 \u2014 cancele no Internet Banking).",
|
|
2243
|
+
security: [{ ApiKeyAuth: ["payouts:cancel"] }],
|
|
2244
|
+
responses: { "200": { description: "Cancelado", content: { "application/json": { schema: { $ref: "#/components/schemas/Payout" } } } }, "404": errorResponse("Pagamento n\xE3o encontrado"), "409": errorResponse("N\xE3o pode ser cancelado no estado atual"), "422": errorResponse("Pix Inter \u2014 cancele no Internet Banking"), ...COMMON_ERRORS }
|
|
2245
|
+
}
|
|
2246
|
+
},
|
|
2247
|
+
"/payouts/{id}/sync": {
|
|
2248
|
+
parameters: [{ name: "id", in: "path", required: true, schema: { type: "string", format: "uuid" } }],
|
|
2249
|
+
post: {
|
|
2250
|
+
tags: ["Pagamentos a Fornecedor"],
|
|
2251
|
+
summary: "Sincronizar status com o banco",
|
|
2252
|
+
operationId: "syncPayout",
|
|
2253
|
+
security: [{ ApiKeyAuth: ["payouts:read"] }],
|
|
2254
|
+
responses: { "200": { description: "Status sincronizado", content: { "application/json": { schema: { $ref: "#/components/schemas/Payout" } } } }, "404": errorResponse("Pagamento n\xE3o encontrado"), ...COMMON_ERRORS }
|
|
2255
|
+
}
|
|
2256
|
+
},
|
|
2257
|
+
// -----------------------------------------------------------------------
|
|
2258
|
+
// Formas de pagamento do fornecedor
|
|
2259
|
+
// -----------------------------------------------------------------------
|
|
2260
|
+
"/suppliers/{id}/payment-methods": {
|
|
2261
|
+
parameters: [{ name: "id", in: "path", required: true, schema: { type: "string", format: "uuid" } }],
|
|
2262
|
+
get: {
|
|
2263
|
+
tags: ["Formas de pagamento do fornecedor"],
|
|
2264
|
+
summary: "Listar formas de pagamento do fornecedor",
|
|
2265
|
+
operationId: "listSupplierPaymentMethods",
|
|
2266
|
+
security: [{ ApiKeyAuth: ["suppliers:read"] }],
|
|
2267
|
+
responses: { "200": { description: "Formas de pagamento", content: { "application/json": { schema: { type: "object", properties: { data: { type: "array", items: { $ref: "#/components/schemas/SupplierPaymentMethod" } } } } } } }, "404": errorResponse("Fornecedor n\xE3o encontrado"), ...COMMON_ERRORS }
|
|
2268
|
+
},
|
|
2269
|
+
post: {
|
|
2270
|
+
tags: ["Formas de pagamento do fornecedor"],
|
|
2271
|
+
summary: "Cadastrar forma de pagamento",
|
|
2272
|
+
operationId: "createSupplierPaymentMethod",
|
|
2273
|
+
security: [{ ApiKeyAuth: ["suppliers:write"] }],
|
|
2274
|
+
requestBody: { required: true, content: { "application/json": { schema: { $ref: "#/components/schemas/SupplierPaymentMethodCreate" } } } },
|
|
2275
|
+
responses: { "201": { description: "Criada", content: { "application/json": { schema: { $ref: "#/components/schemas/SupplierPaymentMethod" } } } }, "400": errorResponse("Dados inv\xE1lidos"), "404": errorResponse("Fornecedor n\xE3o encontrado"), ...COMMON_ERRORS }
|
|
2276
|
+
}
|
|
2277
|
+
},
|
|
2278
|
+
"/suppliers/{id}/payment-methods/{methodId}": {
|
|
2279
|
+
parameters: [
|
|
2280
|
+
{ name: "id", in: "path", required: true, schema: { type: "string", format: "uuid" } },
|
|
2281
|
+
{ name: "methodId", in: "path", required: true, schema: { type: "string", format: "uuid" } }
|
|
2282
|
+
],
|
|
2283
|
+
patch: {
|
|
2284
|
+
tags: ["Formas de pagamento do fornecedor"],
|
|
2285
|
+
summary: "Atualizar forma de pagamento",
|
|
2286
|
+
operationId: "updateSupplierPaymentMethod",
|
|
2287
|
+
security: [{ ApiKeyAuth: ["suppliers:write"] }],
|
|
2288
|
+
requestBody: { required: true, content: { "application/json": { schema: { $ref: "#/components/schemas/SupplierPaymentMethodCreate" } } } },
|
|
2289
|
+
responses: { "200": { description: "Atualizada", content: { "application/json": { schema: { $ref: "#/components/schemas/SupplierPaymentMethod" } } } }, "404": errorResponse("N\xE3o encontrada"), ...COMMON_ERRORS }
|
|
2290
|
+
},
|
|
2291
|
+
delete: {
|
|
2292
|
+
tags: ["Formas de pagamento do fornecedor"],
|
|
2293
|
+
summary: "Excluir forma de pagamento",
|
|
2294
|
+
operationId: "deleteSupplierPaymentMethod",
|
|
2295
|
+
security: [{ ApiKeyAuth: ["suppliers:delete"] }],
|
|
2296
|
+
responses: { "204": { description: "Exclu\xEDda" }, "404": errorResponse("N\xE3o encontrada"), "409": errorResponse("H\xE1 registros vinculados que impedem a exclus\xE3o"), ...COMMON_ERRORS }
|
|
2297
|
+
}
|
|
2298
|
+
},
|
|
2299
|
+
// -----------------------------------------------------------------------
|
|
2300
|
+
// Métodos de pagamento (read-only — reusa charges:read)
|
|
2301
|
+
// -----------------------------------------------------------------------
|
|
2302
|
+
"/payment-methods": {
|
|
2303
|
+
get: {
|
|
2304
|
+
tags: ["M\xE9todos de pagamento"],
|
|
2305
|
+
summary: "Listar m\xE9todos de pagamento dispon\xEDveis",
|
|
2306
|
+
operationId: "listPaymentMethods",
|
|
2307
|
+
description: "Lista as formas de recebimento configuradas (Pix, boleto, checkout) por provider. \xDAtil antes de criar uma cobran\xE7a.",
|
|
2308
|
+
security: [{ ApiKeyAuth: ["charges:read"] }],
|
|
2309
|
+
parameters: [
|
|
2310
|
+
...PAGINATION_PARAMS,
|
|
2311
|
+
{ name: "active", in: "query", schema: { type: "string", enum: ["true", "false"] } },
|
|
2312
|
+
{ name: "provider", in: "query", schema: { type: "string", enum: ["inter", "c6bank"] } },
|
|
2313
|
+
{ name: "channel", in: "query", schema: { type: "string", enum: ["pix", "boleto", "checkout"] } }
|
|
2314
|
+
],
|
|
2315
|
+
responses: { "200": paginatedResponse("#/components/schemas/PaymentMethod"), ...COMMON_ERRORS }
|
|
2316
|
+
}
|
|
2317
|
+
},
|
|
2318
|
+
"/payment-methods/ap": {
|
|
2319
|
+
get: {
|
|
2320
|
+
tags: ["M\xE9todos de pagamento"],
|
|
2321
|
+
summary: "Listar m\xE9todos de pagamento a fornecedor (AP)",
|
|
2322
|
+
operationId: "listPaymentMethodsAp",
|
|
2323
|
+
description: "Formas de pagamento usadas em payouts (contas a pagar).",
|
|
2324
|
+
security: [{ ApiKeyAuth: ["payouts:read"] }],
|
|
2325
|
+
parameters: [
|
|
2326
|
+
...PAGINATION_PARAMS,
|
|
2327
|
+
{ name: "active", in: "query", schema: { type: "string", enum: ["true", "false"] } },
|
|
2328
|
+
{ name: "provider", in: "query", schema: { type: "string", enum: ["inter", "c6bank"] } }
|
|
2329
|
+
],
|
|
2330
|
+
responses: { "200": paginatedResponse("#/components/schemas/PaymentMethod"), ...COMMON_ERRORS }
|
|
2331
|
+
}
|
|
2332
|
+
}
|
|
2333
|
+
}
|
|
2334
|
+
};
|
|
2335
|
+
|
|
2336
|
+
// ../../src/lib/apiScopes.ts
|
|
2337
|
+
var API_MODULES = [
|
|
2338
|
+
{
|
|
2339
|
+
key: "customers",
|
|
2340
|
+
label: "Clientes",
|
|
2341
|
+
permissions: [
|
|
2342
|
+
{ key: "read", label: "Listar e visualizar", description: "Consultar clientes e contatos" },
|
|
2343
|
+
{ key: "write", label: "Criar e editar", description: "Criar novos clientes e editar dados" },
|
|
2344
|
+
{ key: "delete", label: "Excluir", description: "Excluir clientes permanentemente" }
|
|
2345
|
+
]
|
|
2346
|
+
},
|
|
2347
|
+
{
|
|
2348
|
+
key: "proposals",
|
|
2349
|
+
label: "Propostas",
|
|
2350
|
+
permissions: [
|
|
2351
|
+
{ key: "read", label: "Listar e visualizar", description: "Consultar propostas comerciais" },
|
|
2352
|
+
{ key: "write", label: "Criar e editar", description: "Criar e editar propostas" },
|
|
2353
|
+
{ key: "send", label: "Enviar", description: "Enviar propostas por e-mail ou WhatsApp" },
|
|
2354
|
+
{ key: "delete", label: "Excluir", description: "Excluir propostas" }
|
|
2355
|
+
]
|
|
2356
|
+
},
|
|
2357
|
+
{
|
|
2358
|
+
key: "invoices",
|
|
2359
|
+
label: "Faturas / Cobran\xE7as",
|
|
2360
|
+
permissions: [
|
|
2361
|
+
{ key: "read", label: "Listar e visualizar", description: "Consultar faturas e cobran\xE7as" },
|
|
2362
|
+
{ 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" }
|
|
2364
|
+
]
|
|
2365
|
+
},
|
|
2366
|
+
{
|
|
2367
|
+
key: "nfse",
|
|
2368
|
+
label: "NFS-e",
|
|
2369
|
+
permissions: [
|
|
2370
|
+
{ key: "read", label: "Consultar notas", description: "Listar e visualizar notas fiscais" },
|
|
2371
|
+
{ key: "emitir", label: "Emitir nota", description: "Emitir notas fiscais de servi\xE7o" },
|
|
2372
|
+
{ key: "cancelar", label: "Cancelar nota", description: "Cancelar notas fiscais emitidas" }
|
|
2373
|
+
]
|
|
2374
|
+
},
|
|
2375
|
+
{
|
|
2376
|
+
key: "finance",
|
|
2377
|
+
label: "Financeiro",
|
|
2378
|
+
permissions: [
|
|
2379
|
+
{ key: "read", label: "Listar e visualizar", description: "Consultar lan\xE7amentos e extratos" },
|
|
2380
|
+
{ key: "write", label: "Criar e editar", description: "Lan\xE7ar e editar movimenta\xE7\xF5es" },
|
|
2381
|
+
{ key: "delete", label: "Excluir", description: "Excluir lan\xE7amentos" }
|
|
2382
|
+
]
|
|
2383
|
+
},
|
|
2384
|
+
{
|
|
2385
|
+
key: "contracts",
|
|
2386
|
+
label: "Contratos",
|
|
2387
|
+
permissions: [
|
|
2388
|
+
{ key: "read", label: "Listar e visualizar", description: "Consultar contratos" },
|
|
2389
|
+
{ key: "write", label: "Criar e editar", description: "Criar e editar contratos" },
|
|
2390
|
+
{ key: "delete", label: "Excluir", description: "Excluir contratos" }
|
|
2391
|
+
]
|
|
2392
|
+
},
|
|
2393
|
+
{
|
|
2394
|
+
key: "suppliers",
|
|
2395
|
+
label: "Fornecedores",
|
|
2396
|
+
permissions: [
|
|
2397
|
+
{ key: "read", label: "Listar e visualizar", description: "Consultar fornecedores" },
|
|
2398
|
+
{ key: "write", label: "Criar e editar", description: "Criar e editar fornecedores" },
|
|
2399
|
+
{ key: "delete", label: "Excluir", description: "Excluir fornecedores" }
|
|
2400
|
+
]
|
|
2401
|
+
},
|
|
2402
|
+
{
|
|
2403
|
+
key: "services",
|
|
2404
|
+
label: "Servi\xE7os",
|
|
2405
|
+
permissions: [
|
|
2406
|
+
{ key: "read", label: "Listar e visualizar", description: "Consultar o cat\xE1logo de servi\xE7os" },
|
|
2407
|
+
{ key: "write", label: "Criar e editar", description: "Criar e editar servi\xE7os" },
|
|
2408
|
+
{ key: "delete", label: "Excluir", description: "Excluir servi\xE7os" }
|
|
2409
|
+
]
|
|
2410
|
+
},
|
|
2411
|
+
{
|
|
2412
|
+
key: "expenses",
|
|
2413
|
+
label: "Despesas",
|
|
2414
|
+
permissions: [
|
|
2415
|
+
{ key: "read", label: "Listar e visualizar", description: "Consultar despesas" },
|
|
2416
|
+
{ key: "write", label: "Criar e editar", description: "Lan\xE7ar e editar despesas" },
|
|
2417
|
+
{ key: "delete", label: "Excluir", description: "Excluir despesas" }
|
|
2418
|
+
]
|
|
2419
|
+
},
|
|
2420
|
+
{
|
|
2421
|
+
key: "purchase_invoices",
|
|
2422
|
+
label: "Contas a Pagar",
|
|
2423
|
+
permissions: [
|
|
2424
|
+
{ key: "read", label: "Listar e visualizar", description: "Consultar contas a pagar" },
|
|
2425
|
+
{ key: "create", label: "Criar", description: "Lan\xE7ar contas a pagar" },
|
|
2426
|
+
{ key: "cancel", label: "Cancelar", description: "Cancelar contas a pagar" }
|
|
2427
|
+
]
|
|
2428
|
+
},
|
|
2429
|
+
{
|
|
2430
|
+
key: "charges",
|
|
2431
|
+
label: "Cobran\xE7as / Gateway",
|
|
2432
|
+
permissions: [
|
|
2433
|
+
{ key: "read", label: "Consultar cobran\xE7as", description: "Listar e visualizar cobran\xE7as geradas via API" },
|
|
2434
|
+
{ key: "create", label: "Criar cobran\xE7a", description: "Gerar Pix, boleto ou checkout de pagamento" },
|
|
2435
|
+
{ key: "cancel", label: "Cancelar cobran\xE7a", description: "Cancelar cobran\xE7as em aberto" },
|
|
2436
|
+
{ key: "refund", label: "Estornar cobran\xE7a", description: "Devolver (estornar) cobran\xE7as Pix pagas" }
|
|
2437
|
+
]
|
|
2438
|
+
},
|
|
2439
|
+
{
|
|
2440
|
+
key: "webhooks",
|
|
2441
|
+
label: "Webhooks",
|
|
2442
|
+
permissions: [
|
|
2443
|
+
{ key: "manage", label: "Gerenciar webhooks", description: "Registrar e configurar URLs de callback para eventos de pagamento" }
|
|
2444
|
+
]
|
|
2445
|
+
},
|
|
2446
|
+
{
|
|
2447
|
+
key: "bank_accounts",
|
|
2448
|
+
label: "Contas banc\xE1rias",
|
|
2449
|
+
permissions: [
|
|
2450
|
+
{ key: "read", label: "Listar e visualizar", description: "Consultar contas banc\xE1rias (somente leitura, sem dados sens\xEDveis)" }
|
|
2451
|
+
]
|
|
2452
|
+
},
|
|
2453
|
+
{
|
|
2454
|
+
key: "payouts",
|
|
2455
|
+
label: "Pagamentos a Fornecedor",
|
|
2456
|
+
permissions: [
|
|
2457
|
+
{ key: "read", label: "Consultar pagamentos", description: "Listar e visualizar pagamentos a fornecedores" },
|
|
2458
|
+
{ key: "create", label: "Pagar / agendar", description: "Executar ou agendar pagamentos Pix e boleto a fornecedores" },
|
|
2459
|
+
{ key: "cancel", label: "Cancelar agendamento", description: "Cancelar pagamentos agendados" }
|
|
2460
|
+
]
|
|
2461
|
+
}
|
|
2462
|
+
];
|
|
2463
|
+
var ALL_SCOPES = API_MODULES.flatMap(
|
|
2464
|
+
(m) => m.permissions.map((p) => `${m.key}:${p.key}`)
|
|
2465
|
+
);
|
|
2466
|
+
|
|
2467
|
+
// src/spec.ts
|
|
2468
|
+
var spec = OPENAPI_SPEC;
|
|
2469
|
+
var HTTP_METHODS = ["get", "post", "patch", "put", "delete"];
|
|
2470
|
+
function indexByOperationId() {
|
|
2471
|
+
const map = /* @__PURE__ */ new Map();
|
|
2472
|
+
for (const [path, methods] of Object.entries(spec.paths)) {
|
|
2473
|
+
for (const method of HTTP_METHODS) {
|
|
2474
|
+
const operation = methods[method];
|
|
2475
|
+
if (!operation?.operationId) continue;
|
|
2476
|
+
if (!map.has(operation.operationId)) {
|
|
2477
|
+
map.set(operation.operationId, { method: method.toUpperCase(), path, operation });
|
|
2478
|
+
}
|
|
2479
|
+
}
|
|
2480
|
+
}
|
|
2481
|
+
return map;
|
|
2482
|
+
}
|
|
2483
|
+
|
|
2484
|
+
// src/schema-from-spec.ts
|
|
2485
|
+
var SCHEMA_REF_PREFIX = "#/components/schemas/";
|
|
2486
|
+
function resolveRef(ref) {
|
|
2487
|
+
if (!ref.startsWith(SCHEMA_REF_PREFIX)) {
|
|
2488
|
+
throw new Error(`Ref n\xE3o suportado: ${ref}`);
|
|
2489
|
+
}
|
|
2490
|
+
const name = ref.slice(SCHEMA_REF_PREFIX.length);
|
|
2491
|
+
const schema = spec.components.schemas[name];
|
|
2492
|
+
if (!schema) throw new Error(`Schema n\xE3o encontrado em components: ${name}`);
|
|
2493
|
+
return schema;
|
|
2494
|
+
}
|
|
2495
|
+
function extractScopes(operation) {
|
|
2496
|
+
const sec = operation.security;
|
|
2497
|
+
if (!Array.isArray(sec) || sec.length === 0) return [];
|
|
2498
|
+
const first = sec[0];
|
|
2499
|
+
const scopes = first?.ApiKeyAuth;
|
|
2500
|
+
return Array.isArray(scopes) ? scopes.filter(Boolean) : [];
|
|
2501
|
+
}
|
|
2502
|
+
function describeOperation(operationId) {
|
|
2503
|
+
const idx = indexByOperationId();
|
|
2504
|
+
const found = idx.get(operationId);
|
|
2505
|
+
if (!found) throw new Error(`operationId n\xE3o encontrado no spec: ${operationId}`);
|
|
2506
|
+
const { method, path, operation } = found;
|
|
2507
|
+
const properties = {};
|
|
2508
|
+
const required = [];
|
|
2509
|
+
const pathParams = [];
|
|
2510
|
+
const queryParams = [];
|
|
2511
|
+
const pathItem = spec.paths[path];
|
|
2512
|
+
const declared = [
|
|
2513
|
+
...(Array.isArray(pathItem.parameters) ? pathItem.parameters : []) ?? [],
|
|
2514
|
+
...operation.parameters ?? []
|
|
2515
|
+
];
|
|
2516
|
+
const declaredByName = new Map(declared.map((p) => [p.name, p]));
|
|
2517
|
+
for (const m of path.matchAll(/\{([^}]+)\}/g)) {
|
|
2518
|
+
const name = m[1];
|
|
2519
|
+
if (pathParams.includes(name)) continue;
|
|
2520
|
+
pathParams.push(name);
|
|
2521
|
+
const d = declaredByName.get(name);
|
|
2522
|
+
properties[name] = {
|
|
2523
|
+
...d?.schema ?? { type: "string" },
|
|
2524
|
+
description: d?.description ?? `Identificador (${name}).`
|
|
2525
|
+
};
|
|
2526
|
+
required.push(name);
|
|
2527
|
+
}
|
|
2528
|
+
for (const p of declared) {
|
|
2529
|
+
if (p.in !== "query" || queryParams.includes(p.name)) continue;
|
|
2530
|
+
queryParams.push(p.name);
|
|
2531
|
+
properties[p.name] = { ...p.schema, ...p.description ? { description: p.description } : {} };
|
|
2532
|
+
}
|
|
2533
|
+
let hasBody = false;
|
|
2534
|
+
const rb = operation.requestBody;
|
|
2535
|
+
const bodySchemaRef = rb?.content?.["application/json"]?.schema;
|
|
2536
|
+
if (bodySchemaRef) {
|
|
2537
|
+
hasBody = true;
|
|
2538
|
+
let bodySchema;
|
|
2539
|
+
if (bodySchemaRef.$ref) {
|
|
2540
|
+
bodySchema = resolveRef(bodySchemaRef.$ref);
|
|
2541
|
+
} else {
|
|
2542
|
+
bodySchema = bodySchemaRef;
|
|
2543
|
+
}
|
|
2544
|
+
properties.body = {
|
|
2545
|
+
...bodySchema,
|
|
2546
|
+
description: "Corpo da requisi\xE7\xE3o (JSON)."
|
|
2547
|
+
};
|
|
2548
|
+
if (rb?.required) required.push("body");
|
|
2549
|
+
}
|
|
2550
|
+
const inputSchema = {
|
|
2551
|
+
type: "object",
|
|
2552
|
+
properties,
|
|
2553
|
+
...required.length ? { required } : {}
|
|
2554
|
+
};
|
|
2555
|
+
return {
|
|
2556
|
+
operationId,
|
|
2557
|
+
method,
|
|
2558
|
+
pathTemplate: path,
|
|
2559
|
+
pathParams,
|
|
2560
|
+
queryParams,
|
|
2561
|
+
hasBody,
|
|
2562
|
+
scopes: extractScopes(operation),
|
|
2563
|
+
inputSchema,
|
|
2564
|
+
summary: operation.summary,
|
|
2565
|
+
description: operation.description
|
|
2566
|
+
};
|
|
2567
|
+
}
|
|
2568
|
+
function buildPath(desc, args) {
|
|
2569
|
+
let path = desc.pathTemplate;
|
|
2570
|
+
for (const name of desc.pathParams) {
|
|
2571
|
+
const val = args[name];
|
|
2572
|
+
if (val === void 0 || val === null || val === "") {
|
|
2573
|
+
throw new Error(`Par\xE2metro de path obrigat\xF3rio ausente: ${name}`);
|
|
2574
|
+
}
|
|
2575
|
+
path = path.replace(`{${name}}`, encodeURIComponent(String(val)));
|
|
2576
|
+
}
|
|
2577
|
+
const query = [];
|
|
2578
|
+
for (const name of desc.queryParams) {
|
|
2579
|
+
const val = args[name];
|
|
2580
|
+
if (val !== void 0 && val !== null && val !== "") {
|
|
2581
|
+
query.push(`${encodeURIComponent(name)}=${encodeURIComponent(String(val))}`);
|
|
2582
|
+
}
|
|
2583
|
+
}
|
|
2584
|
+
return query.length ? `${path}?${query.join("&")}` : path;
|
|
2585
|
+
}
|
|
2586
|
+
|
|
2587
|
+
// src/safety.ts
|
|
2588
|
+
function ok(payload) {
|
|
2589
|
+
return { content: [{ type: "text", text: JSON.stringify(payload, null, 2) }] };
|
|
2590
|
+
}
|
|
2591
|
+
function fail(message) {
|
|
2592
|
+
return { content: [{ type: "text", text: message }], isError: true };
|
|
2593
|
+
}
|
|
2594
|
+
function errorResult(err) {
|
|
2595
|
+
if (err instanceof ComandoApiError) {
|
|
2596
|
+
const payload = { error: true, status: err.status, body: err.body };
|
|
2597
|
+
if (err.status === 429) {
|
|
2598
|
+
payload.hint = "Rate limit excedido (60 req/min). Aguarde a janela reabrir antes de tentar de novo.";
|
|
2599
|
+
}
|
|
2600
|
+
if (err.status === 403) {
|
|
2601
|
+
payload.hint = "Acesso negado: a chave de API n\xE3o tem o scope necess\xE1rio para esta opera\xE7\xE3o.";
|
|
2602
|
+
}
|
|
2603
|
+
return { content: [{ type: "text", text: JSON.stringify(payload, null, 2) }], isError: true };
|
|
2604
|
+
}
|
|
2605
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
2606
|
+
return fail(message);
|
|
2607
|
+
}
|
|
2608
|
+
function augmentInputSchema(schema, opts) {
|
|
2609
|
+
const properties = { ...schema.properties };
|
|
2610
|
+
if (!properties.company_id) {
|
|
2611
|
+
properties.company_id = {
|
|
2612
|
+
type: "string",
|
|
2613
|
+
description: "Opcional: UUID da empresa para esta chamada (sobrescreve a empresa padr\xE3o)."
|
|
2614
|
+
};
|
|
2615
|
+
}
|
|
2616
|
+
if (opts.write) {
|
|
2617
|
+
properties.idempotency_key = {
|
|
2618
|
+
type: "string",
|
|
2619
|
+
description: "Opcional: chave de idempot\xEAncia para evitar duplica\xE7\xE3o em retentativas."
|
|
2620
|
+
};
|
|
2621
|
+
properties.dry_run = {
|
|
2622
|
+
type: "boolean",
|
|
2623
|
+
description: "Se true, n\xE3o executa \u2014 apenas retorna o m\xE9todo, path e corpo que seriam enviados."
|
|
2624
|
+
};
|
|
2625
|
+
}
|
|
2626
|
+
if (opts.destructive) {
|
|
2627
|
+
properties.confirm = {
|
|
2628
|
+
type: "boolean",
|
|
2629
|
+
description: "OBRIGAT\xD3RIO ser true para executar esta a\xE7\xE3o destrutiva. Sem isso, a chamada \xE9 recusada."
|
|
2630
|
+
};
|
|
2631
|
+
}
|
|
2632
|
+
return { ...schema, properties };
|
|
2633
|
+
}
|
|
2634
|
+
function destructiveBlocked(args) {
|
|
2635
|
+
if (args.confirm === true) return null;
|
|
2636
|
+
return fail(
|
|
2637
|
+
"A\xE7\xE3o destrutiva bloqueada. Passe confirm: true para executar, ou dry_run: true para ver o que seria enviado sem executar."
|
|
2638
|
+
);
|
|
2639
|
+
}
|
|
2640
|
+
|
|
2641
|
+
// src/tool-def.ts
|
|
2642
|
+
function asInputSchema(schema) {
|
|
2643
|
+
return schema;
|
|
2644
|
+
}
|
|
2645
|
+
|
|
2646
|
+
// src/tools/curated.ts
|
|
2647
|
+
function buildCuratedTools(api, heldScopes) {
|
|
2648
|
+
const tools = [];
|
|
2649
|
+
const skipped = [];
|
|
2650
|
+
for (const entry of MANIFEST) {
|
|
2651
|
+
let desc;
|
|
2652
|
+
try {
|
|
2653
|
+
desc = describeOperation(entry.operationId);
|
|
2654
|
+
} catch (err) {
|
|
2655
|
+
process.stderr.write(`[comando-mcp] aviso: ${entry.operationId} n\xE3o est\xE1 no spec (${String(err)})
|
|
2656
|
+
`);
|
|
2657
|
+
continue;
|
|
2658
|
+
}
|
|
2659
|
+
const missing = desc.scopes.filter((s) => !heldScopes.has(s));
|
|
2660
|
+
if (missing.length > 0) {
|
|
2661
|
+
skipped.push({ tool: entry.tool, missingScopes: missing });
|
|
2662
|
+
continue;
|
|
2663
|
+
}
|
|
2664
|
+
const inputSchema = augmentInputSchema(desc.inputSchema, {
|
|
2665
|
+
write: entry.write,
|
|
2666
|
+
destructive: entry.destructive
|
|
2667
|
+
});
|
|
2668
|
+
const scopeNote = desc.scopes.length ? ` Scopes: ${desc.scopes.join(", ")}.` : "";
|
|
2669
|
+
const prefix = entry.destructive ? "[DESTRUTIVA] " : "";
|
|
2670
|
+
const description = `${prefix}${desc.summary ?? entry.operationId}.${scopeNote}`;
|
|
2671
|
+
tools.push({
|
|
2672
|
+
name: entry.tool,
|
|
2673
|
+
description,
|
|
2674
|
+
inputSchema: asInputSchema(inputSchema),
|
|
2675
|
+
handler: async (args) => {
|
|
2676
|
+
try {
|
|
2677
|
+
if (entry.destructive) {
|
|
2678
|
+
const blocked = destructiveBlocked(args);
|
|
2679
|
+
if (blocked && args.dry_run !== true) return blocked;
|
|
2680
|
+
}
|
|
2681
|
+
const path = buildPath(desc, args);
|
|
2682
|
+
const body = desc.hasBody ? args.body : void 0;
|
|
2683
|
+
if (args.dry_run === true) {
|
|
2684
|
+
return ok({
|
|
2685
|
+
dry_run: true,
|
|
2686
|
+
method: desc.method,
|
|
2687
|
+
path,
|
|
2688
|
+
body: body ?? null
|
|
2689
|
+
});
|
|
2690
|
+
}
|
|
2691
|
+
const result = await api.request(desc.method, path, {
|
|
2692
|
+
body,
|
|
2693
|
+
companyId: typeof args.company_id === "string" ? args.company_id : void 0,
|
|
2694
|
+
idempotencyKey: typeof args.idempotency_key === "string" ? args.idempotency_key : void 0
|
|
2695
|
+
});
|
|
2696
|
+
return ok(result ?? { ok: true });
|
|
2697
|
+
} catch (err) {
|
|
2698
|
+
return errorResult(err);
|
|
2699
|
+
}
|
|
2700
|
+
}
|
|
2701
|
+
});
|
|
2702
|
+
}
|
|
2703
|
+
return { tools, skipped };
|
|
2704
|
+
}
|
|
2705
|
+
|
|
2706
|
+
// src/tools/request.ts
|
|
2707
|
+
var METHODS = ["GET", "POST", "PATCH", "PUT", "DELETE"];
|
|
2708
|
+
function buildRequestTool(api) {
|
|
2709
|
+
return {
|
|
2710
|
+
name: "comando_request",
|
|
2711
|
+
description: "Chamada gen\xE9rica \xE0 API do Comando.One (cobre qualquer endpoint /v1/*). Use quando n\xE3o houver uma tool espec\xEDfica. Ex.: method=GET, path=/webhooks/deliveries. Os scopes da chave s\xE3o validados pelo servidor.",
|
|
2712
|
+
inputSchema: {
|
|
2713
|
+
type: "object",
|
|
2714
|
+
required: ["method", "path"],
|
|
2715
|
+
properties: {
|
|
2716
|
+
method: { type: "string", enum: [...METHODS], description: "M\xE9todo HTTP." },
|
|
2717
|
+
path: {
|
|
2718
|
+
type: "string",
|
|
2719
|
+
description: "Path relativo iniciando em /, ex.: /customers ou /charges/uuid. N\xC3O inclua /v1."
|
|
2720
|
+
},
|
|
2721
|
+
query: {
|
|
2722
|
+
type: "object",
|
|
2723
|
+
description: "Par\xE2metros de query (pares chave/valor). Ex.: { page: 1, per_page: 20 }.",
|
|
2724
|
+
additionalProperties: true
|
|
2725
|
+
},
|
|
2726
|
+
body: { type: "object", description: "Corpo JSON (para POST/PATCH/PUT).", additionalProperties: true },
|
|
2727
|
+
company_id: { type: "string", description: "Opcional: UUID da empresa (header X-Company-Id)." },
|
|
2728
|
+
idempotency_key: { type: "string", description: "Opcional: chave de idempot\xEAncia (POST)." },
|
|
2729
|
+
dry_run: { type: "boolean", description: "Se true, n\xE3o executa \u2014 s\xF3 mostra o que seria enviado." }
|
|
2730
|
+
}
|
|
2731
|
+
},
|
|
2732
|
+
handler: async (args) => {
|
|
2733
|
+
try {
|
|
2734
|
+
const method = String(args.method ?? "").toUpperCase();
|
|
2735
|
+
if (!METHODS.includes(method)) {
|
|
2736
|
+
return fail(`M\xE9todo inv\xE1lido: ${args.method}. Use um de: ${METHODS.join(", ")}.`);
|
|
2737
|
+
}
|
|
2738
|
+
let path = String(args.path ?? "");
|
|
2739
|
+
if (!path.startsWith("/")) return fail("path deve come\xE7ar com / (ex.: /customers).");
|
|
2740
|
+
if (args.query && typeof args.query === "object") {
|
|
2741
|
+
const u = new URLSearchParams();
|
|
2742
|
+
for (const [k, v] of Object.entries(args.query)) {
|
|
2743
|
+
if (v !== void 0 && v !== null && v !== "") u.set(k, String(v));
|
|
2744
|
+
}
|
|
2745
|
+
const s = u.toString();
|
|
2746
|
+
if (s) path += (path.includes("?") ? "&" : "?") + s;
|
|
2747
|
+
}
|
|
2748
|
+
const body = args.body && typeof args.body === "object" ? args.body : void 0;
|
|
2749
|
+
if (args.dry_run === true) {
|
|
2750
|
+
return ok({ dry_run: true, method, path, body: body ?? null });
|
|
2751
|
+
}
|
|
2752
|
+
const result = await api.request(method, path, {
|
|
2753
|
+
body,
|
|
2754
|
+
companyId: typeof args.company_id === "string" ? args.company_id : void 0,
|
|
2755
|
+
idempotencyKey: typeof args.idempotency_key === "string" ? args.idempotency_key : void 0
|
|
2756
|
+
});
|
|
2757
|
+
return ok(result ?? { ok: true });
|
|
2758
|
+
} catch (err) {
|
|
2759
|
+
return errorResult(err);
|
|
2760
|
+
}
|
|
2761
|
+
}
|
|
2762
|
+
};
|
|
2763
|
+
}
|
|
2764
|
+
|
|
2765
|
+
// src/tools/lookups.ts
|
|
2766
|
+
var KINDS = {
|
|
2767
|
+
"cost-centers": "/cost-centers",
|
|
2768
|
+
"payment-conditions": "/payment-conditions",
|
|
2769
|
+
"service-units": "/service-units",
|
|
2770
|
+
"payment-methods": "/payment-methods",
|
|
2771
|
+
"payment-methods-ap": "/payment-methods/ap",
|
|
2772
|
+
natures: "/finance/natures",
|
|
2773
|
+
"bank-accounts": "/bank-accounts"
|
|
2774
|
+
};
|
|
2775
|
+
function buildLookupsTool(api) {
|
|
2776
|
+
return {
|
|
2777
|
+
name: "lookups",
|
|
2778
|
+
description: "Consulta cat\xE1logos read-only do ERP: centros de custo, condi\xE7\xF5es/m\xE9todos de pagamento, unidades de servi\xE7o, naturezas financeiras e contas banc\xE1rias.",
|
|
2779
|
+
inputSchema: {
|
|
2780
|
+
type: "object",
|
|
2781
|
+
required: ["kind"],
|
|
2782
|
+
properties: {
|
|
2783
|
+
kind: {
|
|
2784
|
+
type: "string",
|
|
2785
|
+
enum: Object.keys(KINDS),
|
|
2786
|
+
description: "Qual cat\xE1logo consultar."
|
|
2787
|
+
},
|
|
2788
|
+
page: { type: "integer", minimum: 1, description: "P\xE1gina (default 1)." },
|
|
2789
|
+
per_page: { type: "integer", minimum: 1, maximum: 100, description: "Itens por p\xE1gina (default 20)." },
|
|
2790
|
+
company_id: { type: "string", description: "Opcional: UUID da empresa (X-Company-Id)." }
|
|
2791
|
+
}
|
|
2792
|
+
},
|
|
2793
|
+
handler: async (args) => {
|
|
2794
|
+
try {
|
|
2795
|
+
const kind = String(args.kind ?? "");
|
|
2796
|
+
const base = KINDS[kind];
|
|
2797
|
+
if (!base) return fail(`kind inv\xE1lido: ${kind}. Use um de: ${Object.keys(KINDS).join(", ")}.`);
|
|
2798
|
+
const u = new URLSearchParams();
|
|
2799
|
+
if (args.page) u.set("page", String(args.page));
|
|
2800
|
+
if (args.per_page) u.set("per_page", String(args.per_page));
|
|
2801
|
+
const q = u.toString();
|
|
2802
|
+
const path = q ? `${base}?${q}` : base;
|
|
2803
|
+
const result = await api.get(path, {
|
|
2804
|
+
companyId: typeof args.company_id === "string" ? args.company_id : void 0
|
|
2805
|
+
});
|
|
2806
|
+
return ok(result);
|
|
2807
|
+
} catch (err) {
|
|
2808
|
+
return errorResult(err);
|
|
2809
|
+
}
|
|
2810
|
+
}
|
|
2811
|
+
};
|
|
2812
|
+
}
|
|
2813
|
+
|
|
2814
|
+
// src/tools/whoami.ts
|
|
2815
|
+
function buildWhoamiTool(api) {
|
|
2816
|
+
return {
|
|
2817
|
+
name: "whoami",
|
|
2818
|
+
description: "Retorna a identidade da chave de API: empresa atual, empresas acess\xEDveis, scopes concedidos e se \xE9 multi-empresa.",
|
|
2819
|
+
inputSchema: { type: "object", properties: {} },
|
|
2820
|
+
handler: async () => {
|
|
2821
|
+
try {
|
|
2822
|
+
return ok(await api.me());
|
|
2823
|
+
} catch (err) {
|
|
2824
|
+
return errorResult(err);
|
|
2825
|
+
}
|
|
2826
|
+
}
|
|
2827
|
+
};
|
|
2828
|
+
}
|
|
2829
|
+
|
|
2830
|
+
// src/index.ts
|
|
2831
|
+
function loadDotEnv() {
|
|
2832
|
+
try {
|
|
2833
|
+
const raw = readFileSync(new URL("../.env", import.meta.url), "utf8");
|
|
2834
|
+
for (const line of raw.split("\n")) {
|
|
2835
|
+
const m = line.match(/^\s*([\w.-]+)\s*=\s*(.*)\s*$/);
|
|
2836
|
+
if (!m) continue;
|
|
2837
|
+
const key = m[1];
|
|
2838
|
+
let val = m[2];
|
|
2839
|
+
if (val.startsWith('"') && val.endsWith('"') || val.startsWith("'") && val.endsWith("'")) {
|
|
2840
|
+
val = val.slice(1, -1);
|
|
2841
|
+
}
|
|
2842
|
+
if (process.env[key] === void 0) process.env[key] = val;
|
|
2843
|
+
}
|
|
2844
|
+
} catch {
|
|
2845
|
+
}
|
|
2846
|
+
}
|
|
2847
|
+
function die(msg) {
|
|
2848
|
+
process.stderr.write(`[comando-mcp] ${msg}
|
|
2849
|
+
`);
|
|
2850
|
+
process.exit(1);
|
|
2851
|
+
}
|
|
2852
|
+
async function main() {
|
|
2853
|
+
loadDotEnv();
|
|
2854
|
+
const apiKey = process.env.COMANDO_API_KEY;
|
|
2855
|
+
const baseUrl = process.env.COMANDO_BASE_URL || "https://api.comando.one/v1";
|
|
2856
|
+
const companyId = process.env.COMANDO_COMPANY_ID || void 0;
|
|
2857
|
+
if (!apiKey) {
|
|
2858
|
+
die("COMANDO_API_KEY ausente. Defina a vari\xE1vel de ambiente com sua chave cmd_live_...");
|
|
2859
|
+
}
|
|
2860
|
+
const api = new ComandoApi({ apiKey, baseUrl, companyId, autoIdempotency: true });
|
|
2861
|
+
let heldScopes = /* @__PURE__ */ new Set();
|
|
2862
|
+
let companyName = "?";
|
|
2863
|
+
try {
|
|
2864
|
+
const me = await api.me();
|
|
2865
|
+
heldScopes = new Set(me.api_key?.scopes ?? []);
|
|
2866
|
+
companyName = me.company?.name ?? "?";
|
|
2867
|
+
} catch (err) {
|
|
2868
|
+
die(`Falha ao validar a chave em ${baseUrl}/me \u2014 ${err instanceof Error ? err.message : String(err)}`);
|
|
2869
|
+
}
|
|
2870
|
+
const tools = [];
|
|
2871
|
+
tools.push(buildWhoamiTool(api));
|
|
2872
|
+
const { tools: curated, skipped } = buildCuratedTools(api, heldScopes);
|
|
2873
|
+
tools.push(...curated);
|
|
2874
|
+
tools.push(buildLookupsTool(api));
|
|
2875
|
+
tools.push(buildRequestTool(api));
|
|
2876
|
+
const byName = new Map(tools.map((t) => [t.name, t]));
|
|
2877
|
+
process.stderr.write(
|
|
2878
|
+
`[comando-mcp] empresa="${companyName}" scopes=${heldScopes.size} tools=${tools.length} (curadas=${curated.length}, ocultas-por-scope=${skipped.length})
|
|
2879
|
+
`
|
|
2880
|
+
);
|
|
2881
|
+
const server = new Server(
|
|
2882
|
+
{ name: "comando-one", version: "0.1.0" },
|
|
2883
|
+
{ capabilities: { tools: {} } }
|
|
2884
|
+
);
|
|
2885
|
+
server.setRequestHandler(ListToolsRequestSchema, async () => ({
|
|
2886
|
+
tools: tools.map((t) => ({ name: t.name, description: t.description, inputSchema: t.inputSchema }))
|
|
2887
|
+
}));
|
|
2888
|
+
server.setRequestHandler(CallToolRequestSchema, async (req) => {
|
|
2889
|
+
const tool = byName.get(req.params.name);
|
|
2890
|
+
if (!tool) {
|
|
2891
|
+
return { content: [{ type: "text", text: `Tool desconhecida: ${req.params.name}` }], isError: true };
|
|
2892
|
+
}
|
|
2893
|
+
const args = req.params.arguments ?? {};
|
|
2894
|
+
const result = await tool.handler(args);
|
|
2895
|
+
return result;
|
|
2896
|
+
});
|
|
2897
|
+
const transport = new StdioServerTransport();
|
|
2898
|
+
await server.connect(transport);
|
|
2899
|
+
process.stderr.write("[comando-mcp] pronto (stdio).\n");
|
|
2900
|
+
}
|
|
2901
|
+
main().catch((err) => die(err instanceof Error ? err.message : String(err)));
|