sgp-sdk 1.2.0 → 2.0.0-beta.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (100) hide show
  1. package/CHANGELOG.md +234 -0
  2. package/COMPATIBILITY.md +231 -0
  3. package/MIGRATION.md +344 -0
  4. package/README.md +464 -265
  5. package/dist/address.d.ts +46 -0
  6. package/dist/annotation-selection.d.ts +32 -0
  7. package/dist/budget.d.ts +29 -0
  8. package/dist/classify.d.ts +15 -0
  9. package/dist/client.d.ts +938 -165
  10. package/dist/config.d.ts +115 -0
  11. package/dist/constants.d.ts +85 -0
  12. package/dist/document.d.ts +11 -0
  13. package/dist/effect.d.ts +22 -0
  14. package/dist/executor.d.ts +9 -0
  15. package/dist/exposure.d.ts +21 -0
  16. package/dist/guards.d.ts +2 -0
  17. package/dist/hooks.d.ts +16 -0
  18. package/dist/ids.d.ts +19 -0
  19. package/dist/index.d.ts +55 -49
  20. package/dist/index.js +3750 -1293
  21. package/dist/normalize.d.ts +9 -0
  22. package/dist/operation-sensitivity.d.ts +729 -0
  23. package/dist/operation.d.ts +145 -0
  24. package/dist/operations/catalogs-list-billing-profiles.d.ts +16 -0
  25. package/dist/operations/catalogs-list-nas.d.ts +25 -0
  26. package/dist/operations/catalogs-list-pops.d.ts +14 -0
  27. package/dist/operations/contracts-check-connection.d.ts +56 -0
  28. package/dist/operations/contracts-list-services.d.ts +103 -0
  29. package/dist/operations/contracts-list-status-reasons.d.ts +15 -0
  30. package/dist/operations/contracts-list.d.ts +52 -0
  31. package/dist/operations/contracts-update-status.d.ts +41 -0
  32. package/dist/operations/contracts-update.d.ts +39 -0
  33. package/dist/operations/coverage-check-address.d.ts +46 -0
  34. package/dist/operations/coverage-check.d.ts +43 -0
  35. package/dist/operations/coverage-list-gateways.d.ts +16 -0
  36. package/dist/operations/crm-contracts-create-by-cpf-cnpj.d.ts +97 -0
  37. package/dist/operations/crm-contracts-create.d.ts +221 -0
  38. package/dist/operations/crm-contracts-list.d.ts +50 -0
  39. package/dist/operations/crm-customers-create.d.ts +165 -0
  40. package/dist/operations/crm-customers-update-status.d.ts +41 -0
  41. package/dist/operations/customers-list.d.ts +104 -0
  42. package/dist/{endpoints/ura/lookup-customer.d.ts → operations/customers-search.d.ts} +56 -46
  43. package/dist/operations/documents-add.d.ts +29 -0
  44. package/dist/operations/documents-list.d.ts +31 -0
  45. package/dist/operations/experimental-annotations-list.d.ts +67 -0
  46. package/dist/operations/invoices-list.d.ts +148 -0
  47. package/dist/operations/maintenance-list.d.ts +35 -0
  48. package/dist/operations/occurrences-create.d.ts +125 -0
  49. package/dist/operations/occurrences-list-methods.d.ts +14 -0
  50. package/dist/operations/occurrences-list-types.d.ts +20 -0
  51. package/dist/operations/occurrences-list.d.ts +127 -0
  52. package/dist/{endpoints/ura/list-plans.d.ts → operations/plans-list.d.ts} +33 -23
  53. package/dist/operations/pre-registrations-create.d.ts +276 -0
  54. package/dist/operations/pre-registrations-list-due-days.d.ts +15 -0
  55. package/dist/operations/pre-registrations-list-plans.d.ts +24 -0
  56. package/dist/operations/pre-registrations-list-sellers.d.ts +16 -0
  57. package/dist/operations/services-add-generic.d.ts +52 -0
  58. package/dist/operations/services-add-tv.d.ts +47 -0
  59. package/dist/operations/services-change-plan.d.ts +40 -0
  60. package/dist/operations/services-remove-generic.d.ts +28 -0
  61. package/dist/operations/services-remove-tv.d.ts +29 -0
  62. package/dist/operations/work-orders-get.d.ts +99 -0
  63. package/dist/operations/work-orders-list-comments.d.ts +34 -0
  64. package/dist/operations/work-orders-list-reasons.d.ts +20 -0
  65. package/dist/operations/work-orders-list.d.ts +81 -0
  66. package/dist/path.d.ts +13 -0
  67. package/dist/raw-request.d.ts +26 -0
  68. package/dist/request.d.ts +28 -0
  69. package/dist/result.d.ts +113 -41
  70. package/dist/retry.d.ts +34 -0
  71. package/dist/sensitivity.d.ts +89 -4
  72. package/dist/tolerant.d.ts +21 -0
  73. package/dist/validation.d.ts +3 -0
  74. package/package.json +6 -3
  75. package/dist/endpoint.d.ts +0 -66
  76. package/dist/endpoints/crm/address.d.ts +0 -20
  77. package/dist/endpoints/crm/create-contract.d.ts +0 -109
  78. package/dist/endpoints/crm/create-customer.d.ts +0 -65
  79. package/dist/endpoints/crm/update-customer-status.d.ts +0 -43
  80. package/dist/endpoints/os/list-occurrence-reasons.d.ts +0 -24
  81. package/dist/endpoints/os/list-occurrence-types.d.ts +0 -25
  82. package/dist/endpoints/precadastro/list-due-days.d.ts +0 -19
  83. package/dist/endpoints/precadastro/list-sellers.d.ts +0 -21
  84. package/dist/endpoints/suporte/add-customer-document.d.ts +0 -24
  85. package/dist/endpoints/suporte/list-customer-documents.d.ts +0 -25
  86. package/dist/endpoints/ura/check-coverage.d.ts +0 -46
  87. package/dist/endpoints/ura/list-annotations.d.ts +0 -32
  88. package/dist/endpoints/ura/list-clients.d.ts +0 -58
  89. package/dist/endpoints/ura/list-contracts.d.ts +0 -45
  90. package/dist/endpoints/ura/list-invoices.d.ts +0 -107
  91. package/dist/endpoints/ura/list-nas.d.ts +0 -29
  92. package/dist/endpoints/ura/list-occurrence-methods.d.ts +0 -19
  93. package/dist/endpoints/ura/list-payment-carriers.d.ts +0 -20
  94. package/dist/endpoints/ura/list-pops.d.ts +0 -19
  95. package/dist/endpoints/ura/list-service-orders.d.ts +0 -64
  96. package/dist/endpoints/ura/open-ticket.d.ts +0 -81
  97. package/dist/errors.d.ts +0 -59
  98. package/dist/schema/parse.d.ts +0 -19
  99. package/dist/schema/paths.d.ts +0 -38
  100. package/dist/transport.d.ts +0 -65
package/dist/client.d.ts CHANGED
@@ -1,228 +1,1001 @@
1
- import { type CreateContractParams, type CreateContractResponse } from "./endpoints/crm/create-contract.js";
2
- import { type CreateCompanyCustomerParams, type CreateCustomerResponse, type CreateIndividualCustomerParams } from "./endpoints/crm/create-customer.js";
3
- import { type UpdateCustomerStatusParams, type UpdateCustomerStatusResponse } from "./endpoints/crm/update-customer-status.js";
4
- import { type ListOccurrenceReasonsResponse } from "./endpoints/os/list-occurrence-reasons.js";
5
- import { type ListOccurrenceTypesResponse } from "./endpoints/os/list-occurrence-types.js";
6
- import { type ListDueDaysResponse } from "./endpoints/precadastro/list-due-days.js";
7
- import { type ListSellersResponse } from "./endpoints/precadastro/list-sellers.js";
8
- import { type AddCustomerDocumentParams, type AddCustomerDocumentResponse } from "./endpoints/suporte/add-customer-document.js";
9
- import { type ListCustomerDocumentsResponse } from "./endpoints/suporte/list-customer-documents.js";
10
- import { type CheckCoverageParams, type CheckCoverageResponse } from "./endpoints/ura/check-coverage.js";
11
- import { type ListAnnotationsParams, type ListAnnotationsResponse } from "./endpoints/ura/list-annotations.js";
12
- import { type ListClientsParams, type ListClientsResponse } from "./endpoints/ura/list-clients.js";
13
- import { type ListContractsParams, type ListContractsResponse } from "./endpoints/ura/list-contracts.js";
14
- import { type ListInvoicesParams, type ListInvoicesResponse } from "./endpoints/ura/list-invoices.js";
15
- import { type ListNasResponse } from "./endpoints/ura/list-nas.js";
16
- import { type ListOccurrenceMethodsResponse } from "./endpoints/ura/list-occurrence-methods.js";
17
- import { type ListPaymentCarriersResponse } from "./endpoints/ura/list-payment-carriers.js";
18
- import { type ListPlansResponse } from "./endpoints/ura/list-plans.js";
19
- import { type ListPopsResponse } from "./endpoints/ura/list-pops.js";
20
- import { type ListServiceOrdersParams, type ListServiceOrdersResponse } from "./endpoints/ura/list-service-orders.js";
21
- import { type LookupCustomerParams, type LookupCustomerResponse } from "./endpoints/ura/lookup-customer.js";
22
- import { type OpenTicketParams, type OpenTicketResponse } from "./endpoints/ura/open-ticket.js";
23
- import type { SgpResult, SgpWriteResult } from "./result.js";
24
- import type { SgpClientConfig, SgpFile } from "./transport.js";
25
- /** Methods that hit the `/api/ura/` routes. All are reads, except `openTicket`: a write that returns an {@link SgpWriteResult}. */
26
- export interface UraClient {
27
- /**
28
- * @experimental Lists annotations: `GET /api/ura/cliente/anotacao/list/`, with local identity selection.
29
- * Requires positive safe-integer `cliente_id` and/or `contrato_id`; both mean AND.
30
- * Returns matching notes present in one SGP response; source completeness is not guaranteed while this method is experimental.
31
- * The bulk upstream body enters SDK memory but is never returned, logged or cached by the SDK.
32
- * Use only on a trusted server; authorize requested IDs. Injected fetch/tracing must not capture
33
- * the upstream body. Omit note text/staff identity with `annotationPersonalKeys` before logging.
34
- * The public API and local validation/selection remain when upstream filtering is fixed.
1
+ import { type CallOptions, type ClientOptions } from "./config.js";
2
+ import { type CatalogsListBillingProfilesData } from "./operations/catalogs-list-billing-profiles.js";
3
+ import { type CatalogsListNasData } from "./operations/catalogs-list-nas.js";
4
+ import { type CatalogsListPopsData } from "./operations/catalogs-list-pops.js";
5
+ import { type ContractsCheckConnectionData, type ContractsCheckConnectionInput } from "./operations/contracts-check-connection.js";
6
+ import { type ContractsListData, type ContractsListInput } from "./operations/contracts-list.js";
7
+ import { type ContractsListServicesData, type ContractsListServicesInput } from "./operations/contracts-list-services.js";
8
+ import { type ContractsListStatusReasonsData } from "./operations/contracts-list-status-reasons.js";
9
+ import { type ContractUpdateData, type ContractUpdateInput } from "./operations/contracts-update.js";
10
+ import { type ContractUpdateStatusData, type ContractUpdateStatusInput } from "./operations/contracts-update-status.js";
11
+ import { type CoverageCheckData, type CoverageCheckInput } from "./operations/coverage-check.js";
12
+ import { type CoverageCheckAddressData, type CoverageCheckAddressInput } from "./operations/coverage-check-address.js";
13
+ import { type CoverageListGatewaysData } from "./operations/coverage-list-gateways.js";
14
+ import { type CrmContractCreateData, type CrmContractCreateInput } from "./operations/crm-contracts-create.js";
15
+ import { type CrmContractCreateByCpfCnpjData, type CrmContractCreateByCpfCnpjInput } from "./operations/crm-contracts-create-by-cpf-cnpj.js";
16
+ import { type CrmContractsListData, type CrmContractsListInput } from "./operations/crm-contracts-list.js";
17
+ import { type CrmCustomerCreateData, type CrmCustomerCreateInput } from "./operations/crm-customers-create.js";
18
+ import { type CrmCustomerUpdateStatusData, type CrmCustomerUpdateStatusInput } from "./operations/crm-customers-update-status.js";
19
+ import { type CustomersListData, type CustomersListInput } from "./operations/customers-list.js";
20
+ import { type CustomersSearchData, type CustomersSearchInput } from "./operations/customers-search.js";
21
+ import { type DocumentAddInput } from "./operations/documents-add.js";
22
+ import { type DocumentsListData, type DocumentsListInput } from "./operations/documents-list.js";
23
+ import { type ExperimentalAnnotationsListData, type ExperimentalAnnotationsListInput } from "./operations/experimental-annotations-list.js";
24
+ import { type InvoicesListData, type InvoicesListInput } from "./operations/invoices-list.js";
25
+ import { type MaintenanceListData } from "./operations/maintenance-list.js";
26
+ import { type OccurrenceCreateData, type OccurrenceCreateInput } from "./operations/occurrences-create.js";
27
+ import { type OccurrencesListData, type OccurrencesListInput } from "./operations/occurrences-list.js";
28
+ import { type OccurrencesListMethodsData } from "./operations/occurrences-list-methods.js";
29
+ import { type OccurrencesListTypesData } from "./operations/occurrences-list-types.js";
30
+ import { type PlansListData } from "./operations/plans-list.js";
31
+ import { type PreRegistrationCreateData, type PreRegistrationCreateInput } from "./operations/pre-registrations-create.js";
32
+ import { type PreRegistrationsListDueDaysData } from "./operations/pre-registrations-list-due-days.js";
33
+ import { type PreRegistrationsListPlansData } from "./operations/pre-registrations-list-plans.js";
34
+ import { type PreRegistrationsListSellersData } from "./operations/pre-registrations-list-sellers.js";
35
+ import { type ServiceAddGenericData, type ServiceAddGenericInput } from "./operations/services-add-generic.js";
36
+ import { type ServiceAddTvData, type ServiceAddTvInput } from "./operations/services-add-tv.js";
37
+ import { type ServiceChangePlanData, type ServiceChangePlanInput } from "./operations/services-change-plan.js";
38
+ import { type ServiceRemoveGenericData, type ServiceRemoveGenericInput } from "./operations/services-remove-generic.js";
39
+ import { type ServiceRemoveTvData, type ServiceRemoveTvInput } from "./operations/services-remove-tv.js";
40
+ import { type WorkOrdersGetData, type WorkOrdersGetInput } from "./operations/work-orders-get.js";
41
+ import { type WorkOrdersListData, type WorkOrdersListInput } from "./operations/work-orders-list.js";
42
+ import { type WorkOrdersListCommentsData, type WorkOrdersListCommentsInput } from "./operations/work-orders-list-comments.js";
43
+ import { type WorkOrdersListReasonsData } from "./operations/work-orders-list-reasons.js";
44
+ import { type RawRequestInput } from "./raw-request.js";
45
+ import type { SgpResult } from "./result.js";
46
+ /** Operations on catalogs of the provider's own setup (POPs, NAS, billing profiles). */
47
+ export interface CatalogsClient {
48
+ /**
49
+ * Lists the POPs (points of presence): `POST /api/ura/pops/`, JSON, no input. The route is not
50
+ * paginated, so the result is SGP's own bare array: no page envelope, no total. Unknown fields
51
+ * reach `data` unchanged. Only the `id` of each POP must be a number (an element that is not an
52
+ * object fails the response too: `INVALID_RESPONSE`); any other field of the wrong type is left
53
+ * out of `data` and reported in `warnings` (the original stays in `response`). A read: the opt-in
54
+ * `maxRetries` may retry it.
35
55
  */
36
- listAnnotations: (params: ListAnnotationsParams) => Promise<SgpResult<ListAnnotationsResponse>>;
56
+ listPops: (options?: CallOptions) => Promise<SgpResult<CatalogsListPopsData>>;
37
57
  /**
38
- * Lists clients, one page at a time: `POST /api/ura/clientes/`.
58
+ * Lists the NAS (network access servers) and the POPs each one serves: `POST /api/ura/nas/list/`,
59
+ * JSON, no input. The route is not paginated, so the result is SGP's own bare array: no page
60
+ * envelope, no total. Unknown fields reach `data` unchanged at every level. Only the `id` of each
61
+ * NAS must be a number (an element that is not an object fails the response too:
62
+ * `INVALID_RESPONSE`); any other field of the wrong type is left out of `data` and reported in
63
+ * `warnings` (the original stays in `response`).
39
64
  *
40
- * Filter with `cliente_id`, `cpfcnpj` or `cliente_nome`; page with `offset` and `limit`.
65
+ * The IP address of a NAS (`endereco_ip`) is a secret: see `getSensitivity("catalogs.listNas")`
66
+ * and project with `pick` before logging or handing it on. A read: the opt-in `maxRetries` may
67
+ * retry it.
41
68
  */
42
- listClients: (params?: ListClientsParams) => Promise<SgpResult<ListClientsResponse>>;
69
+ listNas: (options?: CallOptions) => Promise<SgpResult<CatalogsListNasData>>;
43
70
  /**
44
- * Looks up a customer and its contracts: `POST /api/ura/consultacliente/`.
71
+ * Lists the billing profiles (SGP "portadores", who issues and collects the invoices):
72
+ * `GET /api/ura/portador/`, credentials in the query string, no input. The route is not
73
+ * paginated, so the result is SGP's own bare array: no page envelope, no total. Unknown fields
74
+ * reach `data` unchanged. Only the `id` of each billing profile must be a number (an element that
75
+ * is not an object fails the response too: `INVALID_RESPONSE`); any other field of the wrong type
76
+ * is left out of `data` and reported in `warnings` (the original stays in `response`). The
77
+ * `portador` filter of `invoices.list` takes these ids. A read: the opt-in `maxRetries` may retry
78
+ * it.
79
+ */
80
+ listBillingProfiles: (options?: CallOptions) => Promise<SgpResult<CatalogsListBillingProfilesData>>;
81
+ }
82
+ /** Operations on the CRM funnel's customers (SGP "clientes CRM"). */
83
+ export interface CrmCustomersClient {
84
+ /**
85
+ * Creates a CRM customer: `POST /api/crm/cliente/F` or `/J`, picked by `input.personType`, JSON
86
+ * with the address nested (`endereco`) and also as loose fields, as SGP reads both. Never retried.
87
+ *
88
+ * SGP refuses a document that is already registered: HTTP 400 with `errors.cpfcnpj`, which is
89
+ * `REJECTED` with `error.reason === "DOCUMENT_ALREADY_REGISTERED"` (the same reason as
90
+ * `preRegistrations.create`) and effect `"none"`; any other field error keeps no reason. The
91
+ * check holds for every customer, at any status (status 6, "Contrato realizado no SGP",
92
+ * included), with one observed exception: a customer whose document was stored UNFORMATTED (for
93
+ * example a pré-cadastro created with digits only, which SGP stores as sent) was not
94
+ * detected, and a duplicate was created (live: both customers were listed by `customers.list`).
95
+ * A duplicate breaks every lookup by document. So a rejection is NOT a complete guard: ALWAYS read
96
+ * `customers.list({ cpfcnpj })` first and decide in your own code whether a second customer is
97
+ * acceptable. A CRM customer is an ordinary customer: its `cliente_id` is the `CustomerId` that
98
+ * `customers.list` shows.
45
99
  *
46
- * Requires at least one of `cpfcnpj`, `contrato`, `nome`, `login` or `telefone`. Each contract
47
- * carries secrets (Central and PPPoE credentials, Wi-Fi, MACs, payoff link) and personal data;
48
- * strip them with `omitSensitive` and the exported key tuples before logging or forwarding.
100
+ * `cpfcnpj` goes out in the canonical mask the base holds: a CPF (`/F`) as `999.999.999-99`, a
101
+ * CNPJ (`/J`, alphanumeric included, uppercased) as `AA.AAA.AAA/AAAA-99`, whether you give it
102
+ * with or without punctuation. A document in any other format, or of the other kind than the
103
+ * route, is refused locally (`INVALID_INPUT`, `error.issues` `["cpfcnpj: expected ..."]`, nothing
104
+ * sent, effect `"none"`). Format only: the SDK does not verify the check digits, but SGP does for
105
+ * a CPF: a CPF with wrong digits is refused with HTTP 400 `errors.cpfcnpj` "CPF inválido.", which
106
+ * is `REJECTED` with `error.reason === "DOCUMENT_INVALID"` and effect `"none"` (observed live on
107
+ * `/F`, and a read-back showed nothing created). The check digits of a CNPJ were never tested.
108
+ *
109
+ * A success carries the new `cliente_id` (a `CustomerId`, required: a 2xx without it is
110
+ * `INVALID_RESPONSE`) and SGP's `message`, which echoes the customer's name and document. Only
111
+ * `/F` was exercised; `/J` follows the vendor's documentation. Other person types (`E`, `EJ`) are
112
+ * reachable through `request()`.
113
+ *
114
+ * SGP's field validation (HTTP 400, `errors` as an object keyed by field, e.g. `nome` refused for
115
+ * containing digits) is `REJECTED` with effect `"none"`. Other failures carry `error.effect` by
116
+ * the usual rules: `"none"` only when the SDK can affirm nothing was applied (refused locally,
117
+ * cancelled before send, or SGP refused with a field/business error such as `errors` as an
118
+ * object, `error` or `detail`); `"unknown"` after a timeout, network failure, cancellation after
119
+ * send, an HTTP 5xx or 3xx, SGP's generic `errors` array, or a 2xx outside the contract. On
120
+ * `"unknown"`, search for the document before sending again: a second call may create a duplicate.
49
121
  */
50
- lookupCustomer: (params: LookupCustomerParams) => Promise<SgpResult<LookupCustomerResponse>>;
122
+ create: (input: CrmCustomerCreateInput, options?: CallOptions) => Promise<SgpResult<CrmCustomerCreateData>>;
51
123
  /**
52
- * Lists contract summaries: `POST /api/ura/listacontrato/`.
124
+ * Changes the status of a CRM customer: `POST /api/crm/cliente/{cliente_id}/status/` (trailing
125
+ * slash), JSON. Never retried. Status codes are in `CRM_STATUS` (6 is "Contrato realizado no
126
+ * SGP"), but any number is sent and SGP decides; only 6 was exercised.
53
127
  *
54
- * Filter with `contrato`, `plano`, `tipo` or `status`. Without any filter the response may
55
- * carry the whole contract base. Results contain personal data (name, CPF/CNPJ, e-mail, phone,
56
- * status reason); strip it with `omitSensitive` and the exported key tuples before logging or
57
- * forwarding.
128
+ * A success carries `cliente_id` and `novo_status.codigo`, both required, and SGP's `message`
129
+ * (which echoes the customer's name). A customer that already left the CRM (or a repeated status
130
+ * 6) answers HTTP 404 `{ "error": "Cadastro não encontrado" }`: `NOT_FOUND`, effect `"none"`
131
+ * (a 1.x capture). This route has no other known rejection: a customer that never
132
+ * was in the CRM answers with SGP's generic `errors` array, which stays `"unknown"`;
133
+ * field/business errors (`errors` as an object, `error`, `detail`) are `"none"`. On `"unknown"`,
134
+ * read the customer before sending again.
58
135
  */
59
- listContracts: (params?: ListContractsParams) => Promise<SgpResult<ListContractsResponse>>;
136
+ updateStatus: (input: CrmCustomerUpdateStatusInput, options?: CallOptions) => Promise<SgpResult<CrmCustomerUpdateStatusData>>;
137
+ }
138
+ /** Operations on the contracts of CRM customers. */
139
+ export interface CrmContractsClient {
60
140
  /**
61
- * Lists service orders (OS), one page at a time: `POST /api/ura/ordemservico/list/`.
141
+ * Creates a contract for a CRM customer, by customer id: `POST
142
+ * /api/crm/cliente/{cliente_id}/contratos/` (trailing slash), JSON with both addresses nested
143
+ * and the installation address also as loose fields. Never retried. It works only for a customer
144
+ * that is still in the CRM funnel: a definitive customer (such as one created by
145
+ * `preRegistrations.create` with `precadastro_ativar`) is refused.
146
+ *
147
+ * SGP's refusal of a customer outside the CRM, HTTP 400
148
+ * `{ errors: ["Ocorreu um erro: Não encontrado cliente CRM com ID <n>"] }`, is `REJECTED` with
149
+ * `error.reason === "CUSTOMER_NOT_IN_CRM"` and effect `"none"` (read-backs showed no contract
150
+ * added). Any other `errors` array is SGP's generic wrapper and stays `"unknown"`.
62
151
  *
63
- * Filter with `ordem_servico`, `status`, `pop`, `motivo` or `contrato`; page with `offset` and
64
- * `limit`. Results contain personal data (customer name, free-text content); strip it with
65
- * `omitSensitive` and the exported key tuples before logging or forwarding.
152
+ * `plano_id` is a `PlanId` from the URA catalog (`plans.list`). For an Internet service the
153
+ * vendor's documentation also requires `login`, `senha` and `modoaquisicao`, and SGP requires
154
+ * `nas` (a NAS name); it answers 400 with `errors` as an object, `"none"`, when one is missing.
155
+ * Only the missing-`nas` 400 was observed; the other three come from the vendor's documentation. `modoaquisicao` takes
156
+ * `ACQUISITION_MODE` (0 or 1): the vendor's documentation lists 1 and 2, but SGP refused 2 live.
157
+ *
158
+ * A success (HTTP 200) carries the new `clientecontrato` (the contract id, required), SGP's
159
+ * `message` and `cliente`, which echoes the customer's name and CPF (personal data: see
160
+ * `getSensitivity`). Other failures carry `error.effect` by the same
161
+ * rules as `crm.customers.create`. On `"unknown"`, read the customer's contracts before sending
162
+ * again: a second call may create a duplicate contract.
66
163
  */
67
- listServiceOrders: (params?: ListServiceOrdersParams) => Promise<SgpResult<ListServiceOrdersResponse>>;
68
- /** Lists the plan catalog: `GET /api/ura/consultaplano/`. Takes no parameters. */
69
- listPlans: () => Promise<SgpResult<ListPlansResponse>>;
70
- /** Lists the occurrence methods: `GET /api/ura/ocorrencia/metodo/list/`. Takes no parameters. */
71
- listOccurrenceMethods: () => Promise<SgpResult<ListOccurrenceMethodsResponse>>;
164
+ create: (input: CrmContractCreateInput, options?: CallOptions) => Promise<SgpResult<CrmContractCreateData>>;
72
165
  /**
73
- * Lists invoices (titulos), one page at a time: `POST /api/ura/titulos/`.
166
+ * Creates a contract for a CRM customer, by the customer's document: `POST
167
+ * /api/crm/cliente/contratos/?cpfcnpj=<document>` (trailing slash). The document goes in the
168
+ * QUERY string of the POST, as in the live capture; the body is the same JSON contract as
169
+ * `create` (both addresses nested, the installation one also loose) with the credentials, and
170
+ * has no `cliente_id`. Never retried.
171
+ *
172
+ * `cpfcnpj` is SGP's single field: the API decides whether it is a CPF or a CNPJ. Only a CPF was
173
+ * ever exercised; a CNPJ is accepted by the field's name and was never tried. Send it as you
174
+ * hold it (digits or formatted). It works only for a customer still in the CRM funnel.
175
+ *
176
+ * SGP's refusal of a document that is not a CRM customer, HTTP 400
177
+ * `{ errors: ["Ocorreu um erro: Não encontrado cliente CRM com documento <formatted document>"] }`
178
+ * (the document comes back formatted), is `REJECTED` with `error.reason === "CUSTOMER_NOT_IN_CRM"`
179
+ * and effect `"none"` (the read-back showed no contract added). The matcher covers numeric
180
+ * documents (CPF or CNPJ digits, dots, dashes, slashes); an alphanumeric CNPJ, or any other `errors`
181
+ * array (SGP's generic wrapper), stays `"unknown"` without a reason.
182
+ *
183
+ * When several customers share a document (SGP allows duplicates, see `crm.customers.create`),
184
+ * which CRM customer receives the contract is unverified.
74
185
  *
75
- * Filter with `contrato`, `cliente_id`, `cpfcnpj`, `titulo_id`, `status`, `portador` or the date
76
- * ranges; order with `ordenar` and `ordenar_ordem`; page with `offset` and `limit`. Results
77
- * contain personal data (customer name, CPF/CNPJ, statement text) and payment links and PIX
78
- * codes that may resolve to the debtor; strip them with `omitSensitive` and the exported key
79
- * tuples before logging or forwarding.
186
+ * NOT OBSERVED: no success was ever seen on this route, so NO input field reached a success here
187
+ * (the "Exercised" markers of `CrmContractCreateInput` come from the by-id route) (the only live call was that refusal). The
188
+ * success shape is assumed to be that of `create` (HTTP 200 with the new `clientecontrato`,
189
+ * required, SGP's `message` and `cliente`, which echoes the customer's name and is personal
190
+ * data); a 2xx without a numeric `clientecontrato` is `INVALID_RESPONSE` with effect `"unknown"`.
191
+ * Other failures carry `error.effect` by the same rules as `create`. On `"unknown"`, read the
192
+ * customer's contracts (`crm.contracts.list`) before sending again: a second call may create a
193
+ * duplicate contract.
80
194
  */
81
- listInvoices: (params?: ListInvoicesParams) => Promise<SgpResult<ListInvoicesResponse>>;
82
- /** Lists the POPs (points of presence): `POST /api/ura/pops/`. Takes no parameters. */
83
- listPops: () => Promise<SgpResult<ListPopsResponse>>;
195
+ createByCpfCnpj: (input: CrmContractCreateByCpfCnpjInput, options?: CallOptions) => Promise<SgpResult<CrmContractCreateByCpfCnpjData>>;
84
196
  /**
85
- * Lists the NAS (network access servers) and the POPs each serves: `POST /api/ura/nas/list/`.
86
- * Takes no parameters.
197
+ * Lists the contracts of a CRM customer, by the customer's document: `GET
198
+ * /api/crm/cliente/contratos/?cpfcnpj=<document>` (trailing slash), credentials in the query
199
+ * string. A repeatable read. `cpfcnpj` is SGP's single field: the API decides whether it is a CPF
200
+ * or a CNPJ; only a CPF was ever exercised. Send it as you hold it (digits or formatted). When
201
+ * several customers share the document (SGP allows duplicates), which one's contracts are
202
+ * listed is unverified.
87
203
  *
88
- * `endereco_ip` is network infrastructure; strip it with `omitSensitive` and `nasSecretKeys`
89
- * before logging or forwarding.
204
+ * A success is SGP's own object: `cliente` and `cpf_cnpj` (personal data) and `contratos`, one
205
+ * summary per contract, an empty array when the CRM customer has none. Each contract must carry a
206
+ * numeric `cliente_contrato_id` and `contratos` must be an array, or the call is
207
+ * `INVALID_RESPONSE`; everything else is optional and tolerant (a field of the wrong type is
208
+ * dropped with a warning, and unknown keys reach `data` as received). `data_cadastro` and
209
+ * `data_status` stay `DD/MM/AAAA` strings. `endereco`, `motivo_status`, `vendedor` and each
210
+ * service's `login` (a PPPoE secret) are sensitive: see `getSensitivity`.
211
+ *
212
+ * A document that is not a CRM customer answers HTTP 400
213
+ * `{ errors: ["Ocorreu um erro: Não encontrado cliente CRM com documento <formatted document>"] }`:
214
+ * `REJECTED`, with no `reason` and no `effect` (a read applies nothing).
90
215
  */
91
- listNas: () => Promise<SgpResult<ListNasResponse>>;
92
- /** Lists the payment carriers (portadores): `GET /api/ura/portador/`. Takes no parameters. */
93
- listPaymentCarriers: () => Promise<SgpResult<ListPaymentCarriersResponse>>;
216
+ list: (input: CrmContractsListInput, options?: CallOptions) => Promise<SgpResult<CrmContractsListData>>;
217
+ }
218
+ /** Operations of the CRM funnel (SGP "CRM"). */
219
+ export interface CrmClient {
220
+ /** Operations on CRM customers. */
221
+ customers: CrmCustomersClient;
222
+ /** Operations on the contracts of CRM customers. */
223
+ contracts: CrmContractsClient;
224
+ }
225
+ /** Operations on customers' documents (SGP "documentos" of the support area). */
226
+ export interface DocumentsClient {
94
227
  /**
95
- * Checks installation viability around a coordinate: `GET /api/ura/viabilidadeinstalacao`.
228
+ * Attaches a file to a customer: `PUT /api/suporte/cliente/{cliente_id}/documento/add/`
229
+ * (trailing slash), `multipart/form-data` with the file as the part `file` (and `descricao` as a
230
+ * text field when given). Never retried: a second call may attach the file twice.
96
231
  *
97
- * The SDK does not geocode: the consumer supplies `coordenada` (`"lat,lng"`), the map `gateway`
98
- * ID (from `/api/ura/listgatewaymapa`) and the `raio` in meters. The answer is keyed by the gateway's name and
99
- * holds the CTOs within the radius, or `"Localização inviável"` when there are none.
232
+ * A success is a 2xx with an EMPTY body: `data` is `null`, and nothing identifies the new
233
+ * document. Any other 2xx body is `INVALID_RESPONSE` with effect `"unknown"` (the upload may have
234
+ * been stored): read the customer's documents before sending again.
100
235
  *
101
- * A malformed gateway answer (an entry that is neither CTOs nor a message) is `SCHEMA_MISMATCH`.
236
+ * Failures carry `error.effect` by the same rules as `crm.customers.create`; this route has no
237
+ * known rejection. The file and its description are the customer's documents: personal data.
102
238
  */
103
- checkCoverage: (params: CheckCoverageParams) => Promise<SgpResult<CheckCoverageResponse>>;
239
+ add: (input: DocumentAddInput, options?: CallOptions) => Promise<SgpResult<null>>;
104
240
  /**
105
- * Opens a ticket on a contract: `POST /api/ura/chamado/`. Opens an occurrence and, unless
106
- * `desativa_os: 1`, a service order; `data_hora_agendamento` (`"AAAA-MM-DD HH:MM"`) schedules it.
241
+ * Lists the documents attached to a customer: `GET /api/suporte/cliente/{cliente_id}/documento/list/`
242
+ * (trailing slash), credentials in the query string. The route is not paginated, so the result is
243
+ * SGP's own bare array: no page envelope, no total. An empty array means the customer has no
244
+ * document. `cliente_id` is a `CustomerId` (never the id of a contract) and must be a positive
245
+ * integer, or the call is refused locally (`INVALID_INPUT`, nothing sent); the `cliente_id` of
246
+ * each row is a `CustomerId` too.
107
247
  *
108
- * Requires `contrato`. To schedule an installation, send `motivoos` with your instance's
109
- * installation reason code (see `os.listOccurrenceReasons`) and `data_hora_agendamento`. Success is `status` 1 with a `protocolo`; the response carries the
110
- * customer's name and CPF/CNPJ: strip them with `omitSensitive` and `ticketOpenedPersonalKeys`
111
- * before logging or forwarding. `contato_nome` and `contato_telefone` in the params are personal
112
- * data.
248
+ * Unknown fields reach `data` unchanged. Only the `id` and the `cliente_id` of each document must
249
+ * be numbers (an element that is not an object fails the response too: `INVALID_RESPONSE`); any
250
+ * other field of the wrong type is left out of `data` and reported in `warnings` (the original
251
+ * stays in `response`).
113
252
  *
114
- * Never retried by the SDK. With `outcome: "unknown"`, check the state in SGP before repeating.
253
+ * Each document carries the file name or link (`arquivo`), its description and the operator:
254
+ * personal data, see `getSensitivity("documents.list")` and project with `pick` before logging or
255
+ * handing it on. A read: the opt-in `maxRetries` may retry it.
115
256
  */
116
- openTicket: (params: OpenTicketParams) => Promise<SgpWriteResult<OpenTicketResponse>>;
257
+ list: (input: DocumentsListInput, options?: CallOptions) => Promise<SgpResult<DocumentsListData>>;
117
258
  }
118
- /** Methods that hit the `/api/os/` routes. */
119
- export interface OsClient {
120
- /** Lists the occurrence types of service orders (OS): `GET /api/os/ocorrencia/tipo/list/`. Takes no parameters. */
121
- listOccurrenceTypes: () => Promise<SgpResult<ListOccurrenceTypesResponse>>;
122
- /** Lists the occurrence reasons of service orders (OS): `GET /api/os/ocorrencia/motivo/list/`. Takes no parameters. */
123
- listOccurrenceReasons: () => Promise<SgpResult<ListOccurrenceReasonsResponse>>;
259
+ /** Operations on occurrences (SGP "ocorrências", the support tickets or "chamados"). */
260
+ export interface OccurrencesClient {
261
+ /**
262
+ * Opens an occurrence (a support ticket) for a contract: `POST /api/ura/chamado/` (trailing
263
+ * slash), JSON. Never retried: a second call opens a second ticket. Unless `desativa_os` is `1`,
264
+ * SGP opens a work order with it.
265
+ *
266
+ * A success returns `id` (the ID of the OCCURRENCE) and `protocolo` (its protocol number), both
267
+ * required. It never carries the ID of the work order: read it with `occurrences.list({ contrato })`,
268
+ * whose `ordens_servicos[].id` is the work order id (observed once; the occurrence's `numero`
269
+ * equals the work order's `ocorrencia`). That the `protocolo` returned here equals that `numero`
270
+ * was not compared in a raw capture, so check the work order before relying on it. `motivoos` is the `codigo` of a reason of the work order,
271
+ * from `workOrders.listReasons` (each SGP instance has its own).
272
+ *
273
+ * SGP answers some refusals with HTTP 200 and `status: 0` (and a `msg`): that is `REJECTED` with
274
+ * effect `"unknown"`, since nothing says whether anything was created. Read the contract's
275
+ * occurrences before sending again. The exception is `data_hora_agendamento` with seconds
276
+ * (`AAAA-MM-DD HH:MM:SS`), which SGP refuses with `msg` "Data e hora de agendamento inválida,
277
+ * formato esperado: AAAA-MM-DD HH:MM": `reason: "INVALID_SCHEDULE"` and effect `"none"` (the
278
+ * contract's occurrences were read back and nothing had been created; observed once). The SDK
279
+ * sends the date as given: SGP decides what is valid. Other failures carry `error.effect` by the
280
+ * same rules as `crm.customers.create`.
281
+ *
282
+ * Observed live: an occurrence WITHOUT `motivoos` is accepted and SGP still creates a work order;
283
+ * `status_encerrado: 1` closes both the occurrence and the work order; closing an installation work
284
+ * order (`motivoos` 10) did not change the contract status (it stayed inactive; observed once).
285
+ */
286
+ create: (input: OccurrenceCreateInput, options?: CallOptions) => Promise<SgpResult<OccurrenceCreateData>>;
287
+ /**
288
+ * Lists one page of occurrences with their work orders: `POST /api/ura/ocorrencia/list/`
289
+ * (trailing slash), `multipart/form-data` without files; every filter is optional (the vendor
290
+ * marks none as required).
291
+ *
292
+ * AT LEAST ONE FILTER IS REQUIRED: WITHOUT ONE, SGP LISTS THE OCCURRENCES OF EVERY CUSTOMER (up to
293
+ * 1000 per call, with names and free text). A call with no filter is refused locally
294
+ * (`INVALID_INPUT`, `attempts` 0, nothing sent); `offset` and `limit` are paging and do not count.
295
+ * Filter by `contrato` whenever you can. A filter that is present must say something: `contrato: 0`
296
+ * or an empty text filter is refused locally too, since SGP could read it as "no filter". Only `contrato` with `limit` was exercised; the other filters follow the
297
+ * vendor's collection.
298
+ *
299
+ * This is how to find the work order a `occurrences.create` opened: each occurrence carries
300
+ * `ordens_servicos[]`, whose `id` is the work order id (observed once, with the same
301
+ * `numero` as the work order's `ocorrencia`). Read the work order with `workOrders.get`.
302
+ *
303
+ * Returns ONE page with SGP's own `paginacao` as received: `offset` (index of the first
304
+ * occurrence, from 0), `limit` (the page size SGP applied), `parcial` (occurrences on this page)
305
+ * and `total` (occurrences matching the filters across all pages). The SDK never computes
306
+ * `total`: a page without a numeric `paginacao.total` is `INVALID_RESPONSE`. It never fetches the
307
+ * next page either: ask for it with `offset`. A contract with no occurrence is a success with
308
+ * `ocorrencias: []` and `total: 0`.
309
+ *
310
+ * Unknown fields reach `data` unchanged at every level. Only `paginacao.total`, `ocorrencias`,
311
+ * the `id` of each occurrence and the `id` of each of its work orders must have the expected type
312
+ * (an element that is not an object fails the response too: `INVALID_RESPONSE`); any other field
313
+ * of the wrong type is left out of `data` and reported in `warnings` (the original stays in
314
+ * `response`). The occurrence `numero` is text and stays text. Before the route was in the
315
+ * token's whitelist SGP answered 401 (`UNAUTHORIZED`), not the 403 of the other support reads.
316
+ *
317
+ * Each occurrence carries the customer's name, free text and the people involved: see
318
+ * `getSensitivity("occurrences.list")` and project with `pick` before logging or handing it on. A
319
+ * read: the opt-in `maxRetries` may retry it.
320
+ */
321
+ list: (input?: OccurrencesListInput, options?: CallOptions) => Promise<SgpResult<OccurrencesListData>>;
322
+ /**
323
+ * Lists the occurrence types: `GET /api/os/ocorrencia/tipo/list/`, credentials in the query
324
+ * string, no input. The route is not paginated, so the result is SGP's own bare array: no page
325
+ * envelope, no total. Each type has two identifiers, `id` and `codigo`, both numbers and kept
326
+ * apart as SGP sends them: `occurrences.create` takes the `codigo` as `ocorrenciatipo` (the
327
+ * vendor's collection says "Código"). Unknown fields
328
+ * reach `data` unchanged. Only `id` and `codigo` of each type must be numbers (an element that is
329
+ * not an object fails the response too: `INVALID_RESPONSE`); any other field of the wrong type is
330
+ * left out of `data` and reported in `warnings` (the original stays in `response`).
331
+ * `classificacoes` and `setores` were always empty in the captures: their content is untyped. A
332
+ * read: the opt-in `maxRetries` may retry it.
333
+ */
334
+ listTypes: (options?: CallOptions) => Promise<SgpResult<OccurrencesListTypesData>>;
335
+ /**
336
+ * Lists the occurrence methods: `GET /api/ura/ocorrencia/metodo/list/`, credentials in the query
337
+ * string, no input. The route is not paginated, so the result is SGP's own bare array: no page
338
+ * envelope, no total. Unknown fields reach `data` unchanged. Only the `codigo` of each method
339
+ * must be a number (an element that is not an object fails the response too:
340
+ * `INVALID_RESPONSE`); any other field of the wrong type is left out of `data` and reported in
341
+ * `warnings` (the original stays in `response`). A read: the opt-in `maxRetries` may retry it.
342
+ */
343
+ listMethods: (options?: CallOptions) => Promise<SgpResult<OccurrencesListMethodsData>>;
124
344
  }
125
- /** Methods that hit the `/api/precadastro/` routes. */
126
- export interface PrecadastroClient {
127
- /** Lists the due days offered at pre-registration: `POST /api/precadastro/vencimento/list`. Takes no parameters. */
128
- listDueDays: () => Promise<SgpResult<ListDueDaysResponse>>;
345
+ /** Operations on contracts (SGP "contratos"). */
346
+ export interface ContractsClient {
347
+ /**
348
+ * Lists contracts: `POST /api/ura/listacontrato/`, JSON; every filter is optional. The route is
349
+ * not paginated, so the result is SGP's own bare array with one summary per matching contract: no
350
+ * page envelope, no total. Without any filter SGP may answer with the whole contract base, so
351
+ * filter whenever you can. An empty array means no contract matched.
352
+ *
353
+ * Unknown fields reach `data` unchanged (the address SGP adds with `exibir_endereco` is one: it
354
+ * was never captured, so it is untyped and personal data; see `getSensitivity` and `pick`). Only
355
+ * each `id_contrato` and `id_cliente` must be numbers, and every element must be an object
356
+ * (`INVALID_RESPONSE` otherwise); any other field of the wrong type is left out of `data` and
357
+ * reported in `warnings` (the original stays in `response`).
358
+ *
359
+ * `plano` is a `PlanId` from `plans.list`, never an id of `preRegistrations.listPlans`. A read:
360
+ * the opt-in `maxRetries` may retry it.
361
+ */
362
+ list: (input?: ContractsListInput, options?: CallOptions) => Promise<SgpResult<ContractsListData>>;
363
+ /**
364
+ * Lists the services of a contract with their online state and session: `POST
365
+ * /api/suporte/contrato/list/` (note the trailing slash), multipart form. The technical support
366
+ * read: is the customer online now (`servico_online`), since when (`rad_dataconexao`, `rad_tempo`),
367
+ * on which IP, MAC and NAS. SGP's own bare array with ONE ROW PER SERVICE (internet and TV), each
368
+ * repeating the customer, contract, address and plan; `[]` when nothing matches. A row of an
369
+ * online internet service also carries the RADIUS session (`rad_*`); an offline one has none.
370
+ * Filter by `contrato_id` (exercised) or `cliente_id` (exercised); `cliente_nome`,
371
+ * `cliente_cpfcnpj` and `servico_login` follow the vendor's documentation and were never sent.
372
+ *
373
+ * At least one filter is required: without one SGP lists the services of EVERY customer, with
374
+ * plaintext service passwords, so a call with no filter is refused locally (`INVALID_INPUT`,
375
+ * `attempts` 0, nothing sent). An empty text or a 0 id in a filter is refused locally too.
376
+ *
377
+ * Type normalization: `servico_id`, `contrato_id`, `contrato_status_id` and
378
+ * `contrato_pop_id` are numbers (SGP sends text), the RADIUS counters and ids are numbers,
379
+ * `contrato_status` is trimmed (SGP pads it: `" Ativo "`). Each row needs a numeric `servico_id`
380
+ * (`INVALID_RESPONSE` otherwise); any other field of the wrong type is left out of `data` and
381
+ * reported in `warnings` (the original stays in `response`).
382
+ *
383
+ * The rows hold PLAINTEXT SERVICE PASSWORDS and network identifiers (login, MACs, IPs, NAS, IPv6
384
+ * prefixes, session ids), and the customer's name, contact and address. Read
385
+ * `getSensitivity("contracts.listServices")` and project with `pick`; never log or hand the result
386
+ * on whole. A read: the opt-in `maxRetries` may retry it.
387
+ *
388
+ * Online rows were never captured from a synthetic contract: their `rad_*` fields follow the
389
+ * masked shape of a real contract (types only).
390
+ */
391
+ listServices: (input?: ContractsListServicesInput, options?: CallOptions) => Promise<SgpResult<ContractsListServicesData>>;
392
+ /**
393
+ * Asks SGP for its verdict on a contract's connection: `POST /api/ura/verificaacesso/` (note the
394
+ * trailing slash), multipart form. Online (`status` 1), offline (2), under maintenance (9) or not
395
+ * checked (0): see `CONNECTION_STATUS`. Pass `contrato` (exercised) or `telefone` (documented,
396
+ * never sent); `status_all: 1` includes the contracts the default filter leaves out (a suspended
397
+ * contract answered `[]` without it). `protocolo_ura` is not offered: it asks SGP to open an
398
+ * occurrence, which is `occurrences.create`'s job.
399
+ *
400
+ * THIS IS DECLARED A WRITE, although it only looks like a check. The vendor documents that, under
401
+ * an active maintenance, SGP opens an occurrence by default, even without `protocolo_ura`. That
402
+ * was not tested here (the exercised calls ran with no active maintenance, and the occurrence
403
+ * counts before and after were equal). So: it is NEVER retried, whatever `maxRetries` says; every
404
+ * failure after the request was sent carries `error.effect`, usually `"unknown"` (an occurrence may
405
+ * have been opened: read `occurrences.list({ contrato })` before sending again); and it is never
406
+ * part of a sweep or a health poll. Call `maintenance.list()` first: with an active maintenance
407
+ * covering the customer, you already know the answer and avoid the side effect.
408
+ *
409
+ * The data is ALWAYS an array with one item per internet service, whatever SGP sent: SGP answers
410
+ * an array with `status_all`, ONE bare object (wrapped by the SDK) for an active contract without
411
+ * it, and `[]` when the contract is outside its default filter. `[]` is no verdict, not "offline".
412
+ * Each item needs a numeric `status`; the rest (`msg`, `servico_id`, `contratoId`, `login`,
413
+ * `razaoSocial`, `cpfCnpj`) is read tolerantly. `login` is a secret and `razaoSocial` and `cpfCnpj`
414
+ * are personal: see `getSensitivity("contracts.checkConnection")` and project with `pick`.
415
+ */
416
+ checkConnection: (input: ContractsCheckConnectionInput, options?: CallOptions) => Promise<SgpResult<ContractsCheckConnectionData>>;
417
+ /**
418
+ * Changes the status of a contract: `POST /api/ura/contrato/status/edit/`, JSON. Never retried.
419
+ * Activating a contract starts its billing, so a status change is a billing event.
420
+ *
421
+ * SGP decides which transitions it allows; the SDK keeps no transition table. Evidence by
422
+ * transition: Suspenso to Ativo and Ativo to Suspenso returned 200 with the `resposta` body
423
+ * captured raw (`resposta.contrato_status` names the new status); Inativo to Ativo returned 200
424
+ * and a read-back confirmed it, but the body was not captured; Ativo to Inativo was refused with
425
+ * a 400 (the body is known from the support notes' prose, not from a capture; SGP's panel does
426
+ * not offer Inativo from Ativo). Status codes are in `CONTRACT_STATUS`, but any number is sent.
427
+ * `motivo` is the ID of a reason from the provider's own list: read it with
428
+ * `contracts.listStatusReasons`, never assume a value; it is optional, and omitted it is not
429
+ * sent (a call without it was never exercised).
430
+ *
431
+ * SGP's refusal, HTTP 400 `{ error: "Status de Contrato não alterado." }`, is `REJECTED` with
432
+ * `error.reason === "STATUS_NOT_CHANGED"` and effect `"none"`. Its body text is known from the
433
+ * support exchange only, not from a raw capture.
434
+ *
435
+ * Other failures carry `error.effect`: `"none"` only when the SDK can affirm nothing was applied
436
+ * (the input was refused locally, the call was cancelled before send, or SGP refused with a
437
+ * field/business error such as `errors` as an object, `error` or `detail`); `"unknown"` after a
438
+ * timeout, network failure, cancellation after send, an HTTP 5xx or 3xx, SGP's generic `errors`
439
+ * array, or a 2xx outside the contract (`INVALID_RESPONSE`). On `"unknown"`, read the contract
440
+ * (`contracts.list`) before sending again.
441
+ */
442
+ updateStatus: (input: ContractUpdateStatusInput, options?: CallOptions) => Promise<SgpResult<ContractUpdateStatusData>>;
129
443
  /**
130
- * Lists the sellers (vendedores): `POST /api/precadastro/vendedor/list`. Takes no parameters.
444
+ * Edits a contract: `POST /api/ura/contrato/edit/`, JSON. Never retried. Only `forma_cobranca`
445
+ * (the billing method, `BILLING_METHOD`) is accepted; changing it changes how the contract is
446
+ * billed. A success carries SGP's `resposta.alterados`, the list of fields SGP says it applied,
447
+ * returned as-is.
131
448
  *
132
- * Used for `vendedor_id` when creating contracts (v1.1). Sellers are employees: name, CPF and
133
- * e-mail are personal data; strip them with `omitSensitive` and `sellerPersonalKeys` before
134
- * logging or forwarding.
449
+ * Failures carry `error.effect` by the same rules as `contracts.updateStatus`; this route has no
450
+ * known rejection, so a 4xx is `"none"` only with an `errors` object, `error` or `detail` body.
451
+ * On `"unknown"`, read the contract before sending again.
135
452
  */
136
- listSellers: () => Promise<SgpResult<ListSellersResponse>>;
453
+ update: (input: ContractUpdateInput, options?: CallOptions) => Promise<SgpResult<ContractUpdateData>>;
454
+ /**
455
+ * Lists the reasons the provider can register with a status change: `POST
456
+ * /api/ura/contrato/status/motivos/` (trailing slash), JSON, no input. Each provider has its own
457
+ * list, so read it before passing a `motivo` to `contracts.updateStatus` and never assume a
458
+ * value. The route is not paginated, so the result is SGP's own bare array of `{ id, motivo }`:
459
+ * no page envelope, no total. Unknown fields reach `data` unchanged. Only the `id` of each reason
460
+ * must be a number (an element that is not an object fails the response too:
461
+ * `INVALID_RESPONSE`); any other field of the wrong type is left out of `data` and reported in
462
+ * `warnings` (the original stays in `response`). A read: the opt-in `maxRetries` may retry it.
463
+ */
464
+ listStatusReasons: (options?: CallOptions) => Promise<SgpResult<ContractsListStatusReasonsData>>;
137
465
  }
138
- /** Methods that hit the `/api/crm/` routes. Writes: they return an {@link SgpWriteResult}. */
139
- export interface CrmClient {
466
+ /** Operations on installation coverage (SGP "viabilidade de instalação"). */
467
+ export interface CoverageClient {
468
+ /**
469
+ * Checks the viability of an installation around a coordinate: `GET /api/ura/viabilidadeinstalacao`
470
+ * (no trailing slash), params and credentials in the query string. `gateway`, `raio` (meters) and
471
+ * `coordenada` (`"lat,lng"`) are all required, or the call is refused locally (`INVALID_INPUT`,
472
+ * nothing sent). Read the `gateway` ids with `coverage.listGateways`. The SDK does not geocode:
473
+ * bring the coordinate yourself.
474
+ *
475
+ * The result keeps SGP's own shape: an array whose element is an object keyed by the gateway's
476
+ * own name (`SGPMaps`, `Geogrid`: data-defined), holding the CTOs within the radius (`lat`,
477
+ * `lng`, `distancia` in meters, `nome`, and `id` on Geogrid) or the message `"Localização
478
+ * inviável"` when there are none. `lat`, `lng`, `distancia` and `id` are a `number` or `null`:
479
+ * Geogrid sends them as numeric text (`"0"`), SGPMaps as numbers, and an empty text is `null`,
480
+ * never `0`. Text that is not a plain number is left out of `data` with a warning (the original
481
+ * stays in `response`). No page envelope.
482
+ *
483
+ * Unknown fields reach `data` unchanged. The structure must hold (the answer an array of objects,
484
+ * each gateway's answer a list of objects or a message, `INVALID_RESPONSE` otherwise); any field
485
+ * of a CTO of the wrong type is left out of `data` and reported in `warnings` (the original stays
486
+ * in `response`). The coordinate is personal data: see `getSensitivity("coverage.check")`. A
487
+ * read: the opt-in `maxRetries` may retry it.
488
+ */
489
+ check: (input: CoverageCheckInput, options?: CallOptions) => Promise<SgpResult<CoverageCheckData>>;
490
+ /**
491
+ * Checks viability by ADDRESS, before a coordinate exists: `POST /api/ura/viabilidade/` (trailing
492
+ * slash), `multipart/form-data` without files. The filters are SGP's own: `cep`, `cidade`,
493
+ * `logradouro`, `bairro`, `numero_inicial`, `numero_final`; the vendor says to use one of them, so
494
+ * at least one is required or the call is refused locally (`INVALID_INPUT`, nothing sent). Only
495
+ * `cep` alone and `cidade` alone were exercised; how filters combine is SGP's decision. For a
496
+ * coordinate and a map gateway use `check`.
497
+ *
498
+ * The result is SGP's own object, kept as received: observed `{ "viabilidade": true }` (a postal
499
+ * code) and `{}` (a city alone). A MISSING `viabilidade` MEANS UNKNOWN, NEVER "NO COVERAGE": do
500
+ * not turn it into `false`. The "no coverage" answer was NEVER OBSERVED, so what SGP sends for an
501
+ * address without coverage is not known; whatever comes is passed through. The body must be an
502
+ * object (`INVALID_RESPONSE` otherwise); `viabilidade` of the wrong type is left out of `data` and
503
+ * reported in `warnings` (the original stays in `response`). The address is personal data: see
504
+ * `getSensitivity("coverage.checkAddress")`. A read: the opt-in `maxRetries` may retry it.
505
+ */
506
+ checkAddress: (input: CoverageCheckAddressInput, options?: CallOptions) => Promise<SgpResult<CoverageCheckAddressData>>;
507
+ /**
508
+ * Lists the map gateways the provider can check coverage against: `GET /api/ura/listgatewaymapa`
509
+ * (no trailing slash), credentials in the query string, no input. The `id` of each entry is the
510
+ * `gateway` that `coverage.check` takes, so read it here and never assume a value. The route is
511
+ * not paginated, so the result is SGP's own bare array of `{ id, descricao, gateway }`: no page
512
+ * envelope, no total. Unknown fields reach `data` unchanged. Only the `id` (a number) and the
513
+ * `descricao` (text) of each gateway must have the expected type (an element that is not an
514
+ * object fails the response too: `INVALID_RESPONSE`); any other field of the wrong type is left
515
+ * out of `data` and reported in `warnings` (the original stays in `response`). A read: the
516
+ * opt-in `maxRetries` may retry it.
517
+ */
518
+ listGateways: (options?: CallOptions) => Promise<SgpResult<CoverageListGatewaysData>>;
519
+ }
520
+ /** Operations on maintenance notices (SGP "manutenção", the planned or emergency network works). */
521
+ export interface MaintenanceClient {
140
522
  /**
141
- * Creates an individual (PF) customer: `POST /api/crm/cliente/F`.
523
+ * Lists the maintenance notices: `GET /api/ura/manutencao/list/` (trailing slash), credentials in
524
+ * the query string, no input and NO FILTER. The route is not paginated, so the result is SGP's
525
+ * own bare array: no page envelope, no total. It holds EVERY notice, INACTIVE ONES INCLUDED (the
526
+ * one capture held three past notices, all with `ativa: false`): filter by `ativa` and by the
527
+ * period (`data_inicial`, `data_final`, `AAAA-MM-DD HH:MM:SS` text) yourself, and by the affected
528
+ * network elements if you need an area (their lists were empty in the capture, so their content
529
+ * is unknown). An empty array means no notice.
142
530
  *
143
- * Requires `nome`, `cpfcnpj` and `endereco`; the address is sent nested and as loose fields.
144
- * The response `message` carries the name and CPF; strip it with `omitSensitive` and
145
- * `customerCreatedPersonalKeys` before logging or forwarding.
531
+ * Unknown fields reach `data` unchanged. Only the `id` of each notice must be a number (an
532
+ * element that is not an object fails the response too: `INVALID_RESPONSE`); any other field of
533
+ * the wrong type is left out of `data` and reported in `warnings` (the original stays in
534
+ * `response`). The notices are the provider's announcements; no customer data was seen in the capture (its
535
+ * equipment lists were empty, and `mensagem_central` is free text). A read: the
536
+ * opt-in `maxRetries` may retry it.
537
+ */
538
+ list: (options?: CallOptions) => Promise<SgpResult<MaintenanceListData>>;
539
+ }
540
+ /** Operations on customers (SGP "clientes"). */
541
+ export interface CustomersClient {
542
+ /**
543
+ * Lists one page of customers: `POST /api/ura/clientes/`. `paginacao` is SGP's own, `total`
544
+ * included; the SDK never computes it. Unknown fields reach `data` unchanged at every level.
545
+ * Only `paginacao.total`, `clientes` and the ids, name, document and type of each customer, plus
546
+ * the ids of contracts, services and plans, must have the expected type; an element of
547
+ * `clientes`, `contratos` or `servicos` that is not an object fails the response too
548
+ * (`INVALID_RESPONSE`). Any other field of the wrong type is left out of `data` and reported in
549
+ * `warnings` (`dropped` names the field that is absent; the original stays in `response`).
146
550
  *
147
- * Never retried by the SDK. With `outcome: "unknown"`, check the state in SGP before repeating.
551
+ * The `login` filter (the vendor documents it) matches the exact PPPoE login: observed live, the
552
+ * exact login listed its customer, a prefix of it and an unknown login listed nothing (`total`
553
+ * 0). Use it before `preRegistrations.create` to find out whether a login is already taken. The
554
+ * login is a secret: see `getSensitivity("customers.list")`.
148
555
  */
149
- createIndividualCustomer: (params: CreateIndividualCustomerParams) => Promise<SgpWriteResult<CreateCustomerResponse>>;
556
+ list: (input?: CustomersListInput, options?: CallOptions) => Promise<SgpResult<CustomersListData>>;
150
557
  /**
151
- * Creates a company (PJ) customer: `POST /api/crm/cliente/J`.
558
+ * Searches customers by contract, document, name, PPPoE login or phone: `POST
559
+ * /api/ura/consultacliente/`, JSON. At least one criterion is required, or the call is refused
560
+ * locally (`INVALID_INPUT`, nothing sent). A text criterion (`cpfcnpj`, `nome`, `login`,
561
+ * `telefone`) cannot be an empty string, not even next to a valid criterion: that is parameter
562
+ * validation, not protection against a broad search (a string of spaces is not empty and goes to
563
+ * SGP as given). How criteria combine and how names and phones are matched is SGP's decision.
152
564
  *
153
- * Requires `nome`, `cpfcnpj` and `endereco`; the address is sent nested and as loose fields.
154
- * The response `message` carries the name and CNPJ; strip it with `omitSensitive` and
155
- * `customerCreatedPersonalKeys` before logging or forwarding.
565
+ * It returns CANDIDATES and never picks one: `data.contratos` has one entry per matching
566
+ * contract, each carrying its customer's data flattened (`clienteId`, `razaoSocial`,
567
+ * `cpfCnpj`...). Any criterion other than `contrato` may match several contracts, of one customer
568
+ * or of different customers (the same document may belong to more than one customer), so decide
569
+ * between candidates yourself, by `clienteId` and `contratoId`. No match is a success with
570
+ * `contratos: []`. For a filtered, paginated list of customers with their contracts and services,
571
+ * use `customers.list`.
156
572
  *
157
- * Never retried by the SDK. With `outcome: "unknown"`, check the state in SGP before repeating.
573
+ * Every candidate carries the service's Central and PPPoE credentials, Wi-Fi and the customer's
574
+ * identity and address: see `getSensitivity("customers.search")` and project with `pick` before
575
+ * logging or handing it on. Unknown fields reach `data` unchanged. Only `contratos`, and each
576
+ * candidate's `contratoId` and `clienteId`, must have the expected type (a candidate that is not
577
+ * an object fails the response too: `INVALID_RESPONSE`); any other field of the wrong type is left
578
+ * out of `data` and reported in `warnings` (the original stays in `response`). A read: the opt-in
579
+ * `maxRetries` may retry it.
158
580
  */
159
- createCompanyCustomer: (params: CreateCompanyCustomerParams) => Promise<SgpWriteResult<CreateCustomerResponse>>;
581
+ search: (input: CustomersSearchInput, options?: CallOptions) => Promise<SgpResult<CustomersSearchData>>;
582
+ }
583
+ /** Annotations (SGP "anotações") of a customer. */
584
+ export interface ExperimentalAnnotationsClient {
160
585
  /**
161
- * Creates a contract on a CRM customer: `POST /api/crm/cliente/{cliente_id}/contratos/`.
586
+ * EXPERIMENTAL: may change incompatibly in a minor release, without a major version.
162
587
  *
163
- * Requires `pop_id`, `plano_id`, `portador_id`, `forma_cobranca_codigo` (`formaCobrancaCodigo`),
164
- * `vencimento_dia` and both addresses: `endereco_instalacao` and `endereco_cobranca`, sent
165
- * nested; the installation one also goes as loose fields. SGP requires `login` and `senha`
166
- * (PPPoE) for an internet service. The params carry secrets (`login`, `senha`, `central_login`,
167
- * `central_senha`): never log them. The response `cliente` is the customer's name; strip it with
168
- * `omitSensitive` and `contractCreatedPersonalKeys` before logging or forwarding.
588
+ * Lists the notes of a customer and/or a contract: `GET /api/ura/cliente/anotacao/list/`, query
589
+ * string. At least one of `cliente_id` and `contrato_id` is required (a positive safe integer);
590
+ * both together mean AND. Without a valid filter the call is refused locally (`INVALID_INPUT`,
591
+ * nothing sent), and a key other than those two is refused too, never forwarded.
169
592
  *
170
- * The loose address fields carry the installation address. A billing address different from the
171
- * installation one has not been verified live. `error.detail` is SGP's text and may echo submitted
172
- * values (e.g. `senha`): treat it as sensitive before logging.
593
+ * SGP ignores both filters and answers with the notes of other customers, so the SDK selects
594
+ * LOCALLY, over the one response it received, by each note's raw `cliente` and `clientecontrato`.
595
+ * A customer-only call keeps that customer's notes without a contract; a contract-only call keeps
596
+ * that contract's; no match is a success with `[]`, never a relaxed filter. Source order and
597
+ * duplicates are kept. A note that no definite mismatch excludes and whose requested identity is
598
+ * missing or not a number cannot be decided: the whole call is `INVALID_RESPONSE`
599
+ * (`error.issues` names `[].cliente` and/or `[].clientecontrato`), never a silent skip. A note of
600
+ * another customer is dropped before it is read, so its malformed fields do not matter.
173
601
  *
174
- * `os_instalacao` opens the installation service order without a date; to schedule one, use
175
- * `ura.openTicket`. The boleto delivery methods and the invoice (nota fiscal) are not in the
176
- * API: they stay empty.
602
+ * The selected notes are then read like any 2.0 response: `id`, `cliente`, `clientecontrato`
603
+ * (a number or `null`) and `anotacao` must have their type (`INVALID_RESPONSE` otherwise); any
604
+ * other known field of the wrong type is left out of `data` and reported in `warnings`, whose
605
+ * paths index the selected notes. Unknown fields of a selected note reach `data` unchanged, and
606
+ * each note also carries `raw`, a deep copy of that one record as SGP sent it (personal data like
607
+ * the note), so a field dropped from its typed position stays recoverable there. A selected note
608
+ * that embeds, at any depth, an identity of another customer (or of another contract when a
609
+ * contract was requested), or one that cannot be read, fails the call (`INVALID_RESPONSE`,
610
+ * `error.issues` `[].(nested).cliente` or `[].(nested).clientecontrato`). Identity keys are matched
611
+ * by pattern and letter case (`Cliente`, `cliente_id`, `clienteContrato`, `contratos`...), a number
612
+ * or a list of numbers is compared, and on a customer-only call another contract of the same
613
+ * customer is accepted only in an object that also names that customer.
177
614
  *
178
- * Never retried by the SDK. With `outcome: "unknown"`, check the state in SGP before repeating.
615
+ * COMPLETENESS: returns the matching notes present in one SGP response; source completeness is
616
+ * not guaranteed while this method is experimental. The route documents no pagination, and an
617
+ * undocumented cap cannot be ruled out. The SDK sends one request, never pages, never truncates.
618
+ *
619
+ * PRIVACY: the whole upstream body, other customers' notes included, enters this process's memory.
620
+ * The SDK never returns, caches or logs it: `response.body` is `{ kind: "withheld" }` whatever the
621
+ * status (a field dropped from `data` is recoverable from that note's `raw`, never from
622
+ * `response`), `error.sgp` keeps only strings, and no hook receives it. `request()` refuses this
623
+ * route (`ROUTE_NOT_ALLOWED`, nothing sent), so it cannot go around this method.
624
+ * A `fetch` or tracing layer you inject sees the body BEFORE the selection: it must not capture
625
+ * it. Local selection is not an authorization boundary: authorize the ids you pass, and run this
626
+ * only in a trusted server process. The note text (`anotacao`) and the staff member (`usuario`)
627
+ * are personal data, and the text may hold anything a person typed: see
628
+ * `getSensitivity("experimental.annotations.list")` and project with `pick` before logging or
629
+ * handing a note on. A read: the opt-in `maxRetries` may retry it, and each attempt downloads the
630
+ * whole response again.
179
631
  */
180
- createContract: (clienteId: number, params: CreateContractParams) => Promise<SgpWriteResult<CreateContractResponse>>;
632
+ list: (input: ExperimentalAnnotationsListInput, options?: CallOptions) => Promise<SgpResult<ExperimentalAnnotationsListData>>;
633
+ }
634
+ /** Operations that are not stable yet: they may change incompatibly in a minor release. */
635
+ export interface ExperimentalClient {
636
+ /** Customer annotations. */
637
+ annotations: ExperimentalAnnotationsClient;
638
+ }
639
+ /** Operations on invoices (SGP "títulos"). */
640
+ export interface InvoicesClient {
181
641
  /**
182
- * Sets the CRM status of a customer: `POST /api/crm/cliente/{cliente_id}/status/`.
642
+ * Lists one page of invoices: `POST /api/ura/titulos/`, JSON; every filter is optional. Returns
643
+ * ONE page with SGP's own `paginacao` as received: `offset` (index of the first invoice, from 0),
644
+ * `limit` (the page size SGP applied, which may differ from the requested one: SGP documents a
645
+ * maximum of 250), `parcial` (invoices on this page) and `total` (invoices matching the filters
646
+ * across all pages). The SDK never computes `total`: a page without a numeric `paginacao.total`
647
+ * is `INVALID_RESPONSE`. It never fetches the next page either: ask for it with `offset`.
183
648
  *
184
- * Set `crmStatus.contratoRealizadoNoSgp` after the contract, or SGP's screen keeps the customer
185
- * as a CRM customer and blocks contract status changes. The response `message` carries the
186
- * customer's name; strip it with `omitSensitive` and `customerStatusPersonalKeys` before
187
- * logging or forwarding.
649
+ * An empty page is a success with `titulos: []` (and, for a filter that matches nothing,
650
+ * `total: 0`). Unknown fields reach `data` unchanged at every level. Only `paginacao.total`,
651
+ * `titulos` and the `id` of each invoice must have the expected type (an element of `titulos` that
652
+ * is not an object fails the response too: `INVALID_RESPONSE`); any other field of the wrong type
653
+ * is left out of `data` and reported in `warnings` (the original stays in `response`).
188
654
  *
189
- * Never retried by the SDK. With `outcome: "unknown"`, check the state in SGP before repeating.
655
+ * Each invoice carries the customer's name and document, payment links and the PIX code: see
656
+ * `getSensitivity("invoices.list")` and project with `pick` before logging or handing it on. A
657
+ * read: the opt-in `maxRetries` may retry it.
190
658
  */
191
- updateCustomerStatus: (clienteId: number, params: UpdateCustomerStatusParams) => Promise<SgpWriteResult<UpdateCustomerStatusResponse>>;
659
+ list: (input?: InvoicesListInput, options?: CallOptions) => Promise<SgpResult<InvoicesListData>>;
192
660
  }
193
- /** Methods that hit the `/api/suporte/` routes. */
194
- export interface SuporteClient {
661
+ /** Operations on plans (SGP "planos"), the catalog of existing services and contracts. */
662
+ export interface PlansClient {
195
663
  /**
196
- * Attaches a document to a customer: `PUT /api/suporte/cliente/{cliente_id}/documento/add/`,
197
- * sent as multipart with the file in the `file` part.
664
+ * Lists the plan catalog: `GET /api/ura/consultaplano/`, credentials in the query string. The
665
+ * route is not paginated, so the result keeps SGP's own shape (`planos` plus SGP's totals
666
+ * `total_planos` and `total_qtd_servicos`, as received), with no page envelope. Unknown fields
667
+ * reach `data` unchanged at every level. Only `planos` and the `id` of each plan must have the
668
+ * expected type (an element of `planos` that is not an object fails the response too:
669
+ * `INVALID_RESPONSE`); any other field of the wrong type is left out of `data` and reported in
670
+ * `warnings` (the original stays in `response`).
198
671
  *
199
- * SGP answers 200 with an empty body and does not return the document ID: `data` is `null`. To
200
- * check the upload, use `listCustomerDocuments`. SGP converts images to `.jpeg`, so the stored
201
- * file name may differ from `file.filename`. `descricao` is personal data when it names the
202
- * customer.
672
+ * ID space: `planos[].id` is a `PlanId`, the identifier of the operations on existing services and
673
+ * contracts (the `plano` filter of `contracts.list`, `services.changePlan`, `services.addTv`,
674
+ * and the `servicos[].plano.id` of `customers.list`). It is NOT the id of
675
+ * `preRegistrations.listPlans` (a `PreRegistrationPlanId`), the catalog `preRegistrations.create`
676
+ * takes `plano_id` from: the same commercial plan may carry another id there. The two types are
677
+ * kept apart on purpose, in both directions.
203
678
  *
204
- * Never retried by the SDK. With `outcome: "unknown"`, check the state in SGP before repeating.
679
+ * A read: the opt-in `maxRetries` may retry it.
205
680
  */
206
- addCustomerDocument: (clienteId: number, file: SgpFile, params?: AddCustomerDocumentParams) => Promise<SgpWriteResult<AddCustomerDocumentResponse>>;
681
+ list: (options?: CallOptions) => Promise<SgpResult<PlansListData>>;
682
+ }
683
+ /** Operations on pré-cadastros (pre-registrations). */
684
+ export interface PreRegistrationsClient {
207
685
  /**
208
- * Lists the documents attached to a customer: `GET /api/suporte/cliente/{cliente_id}/documento/list/`.
686
+ * Creates a pré-cadastro: `POST /api/precadastro/F` or `/J`, picked by `input.personType`, sent as
687
+ * `multipart/form-data` without files. The address goes in SGP's own loose top-level fields
688
+ * (`logradouro`, `numero`, ...), not grouped. Never retried.
209
689
  *
210
- * Each document carries the file name or link (`arquivo`), its description and the operator:
211
- * personal data; strip it with `omitSensitive` and `customerDocumentPersonalKeys` before logging
212
- * or forwarding.
690
+ * What it does in SGP: with `precadastro_ativar: 1` the pré-cadastro becomes a definitive
691
+ * customer, and a contract is created only when the plan and billing data are sufficient
692
+ * (`plano_id`, `pop_id`, `portador_id`, `vencimento_id`, `formacobranca_id`, ...). The pré-cadastro
693
+ * row itself keeps existing afterwards. A success carries SGP's `message` and, when SGP sends
694
+ * them, the created `new_cliente_id` (a `CustomerId`), `new_contrato_id` and `precadastro_id`,
695
+ * as numbers (`null` when SGP sends an empty text). They are optional: older records list only
696
+ * `message`, and the 1.x decoder dropped unknown keys, so whether SGP sent the IDs before is
697
+ * unknown. When they are absent, read the customer back with `customers.list({ cpfcnpj })`; the
698
+ * SDK never fabricates them. `plano_id` is a `PreRegistrationPlanId`: it comes from `preRegistrations.listPlans`, never a `PlanId` of `plans.list`; `vencimento_id` from `preRegistrations.listDueDays` and `vendedor_id` from `preRegistrations.listSellers`.
699
+ *
700
+ * Failures carry `error.effect`: `"none"` only when the SDK can affirm nothing was applied (the
701
+ * input was refused locally, the call was cancelled before send, or SGP refused with a
702
+ * field/business error such as `errors` as an object, `error` or `detail`); `"unknown"` after a
703
+ * timeout, network failure, cancellation after send, an HTTP 5xx or 3xx, SGP's generic `errors`
704
+ * array, or a 2xx outside the contract (`INVALID_RESPONSE`). On `"unknown"`, check SGP before
705
+ * sending again: a second call may create a duplicate.
706
+ *
707
+ * An existing CPF is refused with HTTP 402 and `error.reason === "DOCUMENT_ALREADY_REGISTERED"`
708
+ * (`REJECTED`, effect `"none"`, observed live on `/F`).
709
+ *
710
+ * SGP stores `cpfcnpj` exactly as sent, and a digits-only document was observed to escape the
711
+ * duplicate check of `crm.customers.create`. So the SDK sends it in the canonical mask the base
712
+ * holds: a CPF (`/F`) as `999.999.999-99`, a CNPJ (`/J`, alphanumeric included, uppercased) as
713
+ * `AA.AAA.AAA/AAAA-99`, whether you give it with or without punctuation. A document in any
714
+ * other format, or of the other kind than the route, is refused locally (`INVALID_INPUT`,
715
+ * `error.issues` `["cpfcnpj: expected ..."]`, nothing sent). Format only: the SDK does not verify
716
+ * the check digits, but SGP does for a CPF: a CPF with wrong digits is refused with HTTP 400
717
+ * `{ message: "CPF inválido", error: "Requisição inválida." }`, which is `REJECTED` with
718
+ * `error.reason === "DOCUMENT_INVALID"` and effect `"none"` (observed live on `/F`, and a
719
+ * read-back showed nothing created; `error.sgp` carries the `error` text, the `message` stays in
720
+ * `response.body`). The check digits of a CNPJ were never tested.
721
+ *
722
+ * A PPPoE `login` already in use is refused with HTTP 400 `{ message: "Login <login> já existe",
723
+ * error: "Requisição inválida." }` (exactly those two text keys), which is `REJECTED` with
724
+ * `error.reason === "LOGIN_ALREADY_REGISTERED"` and effect `"none"` (observed once on `/F`, and a
725
+ * read-back showed nothing created). `error.sgp` carries the `error` text only: the `message`
726
+ * echoes the login you sent and stays in `response.body`; the SDK copies it into no error field.
727
+ * Any other 400 keeps no reason. The refusal is not a complete guard: read
728
+ * `customers.list({ login })` BEFORE creating, to learn whether the login is taken and by whom.
729
+ *
730
+ * Evidence: only `/F` was exercised. The 200 body was seen live with `message` and the three IDs;
731
+ * older records list only `message` (the 1.x decoder dropped unknown keys, so whether the IDs
732
+ * were sent before is unknown). `/J` follows the vendor's documentation.
213
733
  */
214
- listCustomerDocuments: (clienteId: number) => Promise<SgpResult<ListCustomerDocumentsResponse>>;
734
+ create: (input: PreRegistrationCreateInput, options?: CallOptions) => Promise<SgpResult<PreRegistrationCreateData>>;
735
+ /**
736
+ * Lists the plans of the pré-cadastro catalog: `POST /api/precadastro/plano/list`
737
+ * (no trailing slash), sent as `multipart/form-data` without files and with no input. The route
738
+ * is not paginated, so the result is SGP's own bare array: no page envelope, no total. Unknown
739
+ * fields reach `data` unchanged at every level. Only the `id` of each plan must be a number (an
740
+ * element that is not an object fails the response too: `INVALID_RESPONSE`); any other field of
741
+ * the wrong type is left out of `data` and reported in `warnings` (the original stays in
742
+ * `response`). `gateway.id` and `gateway.gateway_id` are a `number` or `null`: SGP sends `""` for a
743
+ * plan without a gateway and numeric text (or a number) otherwise; `""` is `null`, never `0`.
744
+ *
745
+ * ID space: `id` is a `PreRegistrationPlanId`, the one `preRegistrations.create` takes as
746
+ * `plano_id`. It is NOT a `PlanId` of `plans.list`: the same commercial plan may carry another id
747
+ * there, and an id accepted by one route can be refused by the other. The two types are kept
748
+ * apart on purpose, in both directions. A read: the opt-in `maxRetries` may retry it.
749
+ */
750
+ listPlans: (options?: CallOptions) => Promise<SgpResult<PreRegistrationsListPlansData>>;
751
+ /**
752
+ * Lists the due days of the pré-cadastro: `POST /api/precadastro/vencimento/list` (no trailing
753
+ * slash), JSON, no input. The route is not paginated, so the result is SGP's own bare array: no
754
+ * page envelope, no total. Each entry pairs an `id` (what `preRegistrations.create` takes as
755
+ * `vencimento_id`) with the `dia` of the month it stands for: read it, never assume a value.
756
+ * Unknown fields reach `data` unchanged. Only the `id` of each entry must be a number (an element
757
+ * that is not an object fails the response too: `INVALID_RESPONSE`); any other field of the wrong
758
+ * type is left out of `data` and reported in `warnings` (the original stays in `response`). A
759
+ * read: the opt-in `maxRetries` may retry it.
760
+ */
761
+ listDueDays: (options?: CallOptions) => Promise<SgpResult<PreRegistrationsListDueDaysData>>;
762
+ /**
763
+ * Lists the sellers: `POST /api/precadastro/vendedor/list` (no trailing slash), JSON, no input.
764
+ * The route is not paginated, so the result is SGP's own bare array: no page envelope, no total.
765
+ * `id` is what `preRegistrations.create` takes as `vendedor_id`. Unknown fields reach `data`
766
+ * unchanged. Only the `id` of each seller must be a number (an element that is not an object
767
+ * fails the response too: `INVALID_RESPONSE`); any other field of the wrong type is left out of
768
+ * `data` and reported in `warnings` (the original stays in `response`).
769
+ *
770
+ * Sellers are employees of the provider: name, CPF and e-mail are personal data, see
771
+ * `getSensitivity("preRegistrations.listSellers")` and project with `pick` before logging or
772
+ * handing it on. A read: the opt-in `maxRetries` may retry it.
773
+ */
774
+ listSellers: (options?: CallOptions) => Promise<SgpResult<PreRegistrationsListSellersData>>;
215
775
  }
216
- /**
217
- * SGP client. Reads return an {@link SgpResult}, writes (`crm`, `ura.openTicket`,
218
- * `suporte.addCustomerDocument`) an {@link SgpWriteResult}; no method ever throws.
219
- */
776
+ /** Operations on work orders (SGP "ordens de serviço"). */
777
+ export interface WorkOrdersClient {
778
+ /**
779
+ * Lists one page of work orders: `POST /api/ura/ordemservico/list/`, JSON; every filter is
780
+ * optional. Returns ONE page with SGP's own `paginacao` as received: `offset` (index of the first
781
+ * work order, from 0), `limit` (the page size SGP applied, which may differ from the requested
782
+ * one), `parcial` (work orders on this page) and `total` (work orders matching the filters across
783
+ * all pages). The SDK never computes `total`: a page without a numeric `paginacao.total` is
784
+ * `INVALID_RESPONSE`. It never fetches the next page either: ask for it with `offset`.
785
+ *
786
+ * An empty page is a success with `ordens_servicos: []`. Unknown fields reach `data` unchanged at
787
+ * every level. Only `paginacao.total`, `ordens_servicos` and the `id` of each work order must have
788
+ * the expected type (an element that is not an object fails the response too:
789
+ * `INVALID_RESPONSE`); any other field of the wrong type is left out of `data` and reported in
790
+ * `warnings` (the original stays in `response`). The occurrence number (`ocorrencia`) is text and
791
+ * stays text.
792
+ *
793
+ * Each work order carries the customer's name, free text and the people involved: see
794
+ * `getSensitivity("workOrders.list")` and project with `pick` before logging or handing it on. A
795
+ * read: the opt-in `maxRetries` may retry it.
796
+ */
797
+ list: (input?: WorkOrdersListInput, options?: CallOptions) => Promise<SgpResult<WorkOrdersListData>>;
798
+ /**
799
+ * Reads one work order in full: `POST /api/os/list/id/{id}` (NO trailing slash), `multipart/form-data`
800
+ * without files, credentials only. `id` is a positive integer, refused locally otherwise.
801
+ *
802
+ * The result is ONE flat object (72 fields observed) mixing the work order (`os_*`), the customer,
803
+ * contract, address, plan and service. The vendor's collection shows a one-element array; SGP
804
+ * sent the bare object, and that is what `data` is. Unknown fields reach `data` unchanged. Only
805
+ * `os_id` must be a number; any other field of the wrong type is left out of `data` and reported
806
+ * in `warnings` (the original stays in `response`). Normalized: SGP sends `servico_id`,
807
+ * `contrato_status_id` and `os_setor_id` as text, and `data` carries each as a `number` (`null`
808
+ * for an empty text, never `0`; text that is not a plain number is left out with a warning). SGP
809
+ * pads `contrato_status` with a leading space and `data` carries it trimmed.
810
+ *
811
+ * WARNING: THE OBJECT HOLDS PLAINTEXT CREDENTIALS. `servico_password` (the service's password),
812
+ * `servico_login`, `wan_user`, `wan_password`, `wifi_ssid`, `wifi_password`, `wifi_ssid_5` and
813
+ * `wifi_password_5`, plus the MAC and IP of the service and the NAS IP, are SECRET; the customer's
814
+ * name, e-mail, contacts and address (and the coordinates), the free text of the work order and
815
+ * the people involved are PERSONAL. See `getSensitivity("workOrders.get")`, project with `pick`
816
+ * and log `toSafeLog(result)`, never the result. The Wi-Fi and WAN keys were empty in the one
817
+ * capture; they are classified as secret anyway. A read: the opt-in `maxRetries` may retry it.
818
+ */
819
+ get: (input: WorkOrdersGetInput, options?: CallOptions) => Promise<SgpResult<WorkOrdersGetData>>;
820
+ /**
821
+ * Lists the comments of a work order: `GET /api/os/{id}/comentario/list/` (trailing slash),
822
+ * credentials in the query string. `id` is a positive integer, refused locally otherwise. The
823
+ * route is not paginated, so the result is SGP's own bare array: no page envelope, no total. An
824
+ * empty array means no comment.
825
+ *
826
+ * DOCUMENTED ONLY: the one live read returned `[]`, so the item fields (`comentario_id`,
827
+ * `comentario`, `usuario`, `data_cadastro`, `checklist_id`, `checklist_descricao`,
828
+ * `usuario_setores`) come from the vendor's collection and were never seen. Nothing is required
829
+ * of an item beyond being an object (an element that is not an object fails the response:
830
+ * `INVALID_RESPONSE`); any known field of the wrong type is left out of `data` and reported in
831
+ * `warnings`. The comment text and its author are personal data: see
832
+ * `getSensitivity("workOrders.listComments")`. A read: the opt-in `maxRetries` may retry it.
833
+ */
834
+ listComments: (input: WorkOrdersListCommentsInput, options?: CallOptions) => Promise<SgpResult<WorkOrdersListCommentsData>>;
835
+ /**
836
+ * Lists the occurrence reasons (the `motivo` of a work order): `GET /api/os/ocorrencia/motivo/list/`,
837
+ * credentials in the query string, no input. The route is not paginated, so the result is SGP's
838
+ * own bare array: no page envelope, no total. Each reason has two identifiers, `id` and `codigo`,
839
+ * both numbers and kept apart as SGP sends them: `occurrences.create` takes the `codigo` as
840
+ * `motivoos` (the vendor's collection says "Código"; live, `motivoos` 10 was the reason whose
841
+ * `codigo` is 10 and `id` 1). Unknown fields reach `data` unchanged. Only `id` and `codigo` of each reason must be
842
+ * numbers (an element that is not an object fails the response too: `INVALID_RESPONSE`); any
843
+ * other field of the wrong type is left out of `data` and reported in `warnings` (the original
844
+ * stays in `response`). `classificacoes` and `setores` were always empty in the captures: their
845
+ * content is untyped. A read: the opt-in `maxRetries` may retry it.
846
+ */
847
+ listReasons: (options?: CallOptions) => Promise<SgpResult<WorkOrdersListReasonsData>>;
848
+ }
849
+ /** Operations on services (SGP "serviços") of a contract. */
850
+ export interface ServicesClient {
851
+ /**
852
+ * Changes the plan of a service: `POST /api/suporte/service/update/{servico_id}/` (trailing
853
+ * slash), `multipart/form-data` without files, with `action` fixed to `change_plano`. Never
854
+ * retried. A plan change is a billing event.
855
+ *
856
+ * `plano_id` is a `PlanId` from the URA catalog (`plans.list`). `servico_tipo` is required; only `1`
857
+ * (`SERVICE_TYPE.internet`) was exercised against SGP, other values are sent as given and SGP
858
+ * decides. A success carries SGP's `msg` only, with no ID of the service or the plan: read the
859
+ * contract (`customers.list`) to confirm the new plan.
860
+ *
861
+ * Failures carry `error.effect`: `"none"` only when the SDK can affirm nothing was applied (the
862
+ * input was refused locally, including a `servico_id` that is not a positive safe integer, the
863
+ * call was cancelled before send, or SGP refused with a field/business error such as `errors` as
864
+ * an object, `error` or `detail`); `"unknown"` after a timeout, network failure, cancellation
865
+ * after send, an HTTP 5xx or 3xx, SGP's generic `errors` array, or a 2xx outside the contract
866
+ * (`INVALID_RESPONSE`). This route has no known rejection. On `"unknown"`, read the service
867
+ * before sending again.
868
+ */
869
+ changePlan: (input: ServiceChangePlanInput, options?: CallOptions) => Promise<SgpResult<ServiceChangePlanData>>;
870
+ /**
871
+ * Adds a service of the generic type to a contract: `POST /api/servico/generico` (no trailing
872
+ * slash), `multipart/form-data` without files, the route TSMX recommends for extra services of
873
+ * that type. Never retried. TSMX says a generic plan has no billing effect (it only sets the service type);
874
+ * not verified.
875
+ *
876
+ * `planobase_id` must be a plan created as "generic" in the SGP panel (a `PlanId`; whether the
877
+ * URA catalog `plans.list` shows it is not confirmed). SGP refuses any other plan type with HTTP
878
+ * 400 `{ error: "Plano informado não é do tipo genérico." }`, which is `REJECTED` with
879
+ * `error.reason === "PLAN_NOT_GENERIC"` and effect `"none"` (a read-back after the observed
880
+ * refusal showed nothing added; its raw body was not captured). That refusal is the only
881
+ * exchange observed: this provider has no generic plan, so a success was never seen. It is
882
+ * documented, not observed, and `data` is the JSON object SGP sends, kept as received with no
883
+ * field assumed (in particular, the new service's id is not guaranteed). A 2xx that is not a JSON
884
+ * object is `INVALID_RESPONSE` with effect `"unknown"`. Only `descricao` among the optional fields
885
+ * was sent (in the refused call); the others are documented by the vendor and never sent.
886
+ *
887
+ * Other failures carry `error.effect` by the same rules as `services.changePlan`. On
888
+ * `"unknown"`, read the contract's services (`customers.list`) before sending again: a second
889
+ * call may add a duplicate service.
890
+ */
891
+ addGeneric: (input: ServiceAddGenericInput, options?: CallOptions) => Promise<SgpResult<ServiceAddGenericData>>;
892
+ /**
893
+ * Adds a TV service to a contract: `POST /api/servico/tv` (no trailing slash),
894
+ * `multipart/form-data` without files. Never retried. Adding a service changes what the contract
895
+ * is billed for.
896
+ *
897
+ * `planobase_id` is a `PlanId` from the URA catalog (`plans.list`). SGP accepts only active contracts. A
898
+ * success (HTTP 201) returns the new `servico_id` (a number); `clientecontrato_id` is a `number` (SGP sends it as
899
+ * text; `null` for an empty text, and text that is not a plain number is left out of `data` with a
900
+ * warning, the original stays in `response`). Only `info_extra` was exercised among the optional fields; `tipo_equipamento`
901
+ * and `endereco_id` are documented by the vendor and never sent.
902
+ *
903
+ * SGP's refusal of a contract that is not active, HTTP 400
904
+ * `{ errors: ["clientecontrato_id: Só é possível adicionar serviços em contratos ativos."] }`, is
905
+ * `REJECTED` with `error.reason === "CONTRACT_NOT_ACTIVE"` and effect `"none"` (a read-back after
906
+ * the observed refusal showed nothing added on read-back; its raw body is reconstructed). Any other `errors` array is SGP's generic wrapper and
907
+ * stays `"unknown"`.
908
+ *
909
+ * Other failures carry `error.effect` by the same rules as `services.changePlan`. On
910
+ * `"unknown"`, read the contract's services before sending again: a second call may add a
911
+ * duplicate service.
912
+ */
913
+ addTv: (input: ServiceAddTvInput, options?: CallOptions) => Promise<SgpResult<ServiceAddTvData>>;
914
+ /**
915
+ * Removes a generic service: `DELETE /api/servico/generico/{servico_id}` (no trailing slash),
916
+ * with the contract in a `multipart/form-data` body (without files), as SGP expects. Never
917
+ * retried.
918
+ *
919
+ * Documented by the vendor, never observed: no generic service was ever created, so none could
920
+ * be removed. The vendor documents that the route does not remove the only service of a contract;
921
+ * no SGP body for that refusal was captured, so it has no `reason` and, like any other failure,
922
+ * carries `error.effect` by the same rules as `services.changePlan`. A success is the JSON object
923
+ * SGP sends, kept as received with no field assumed; a 2xx that is not a JSON object is
924
+ * `INVALID_RESPONSE` with effect `"unknown"`. On `"unknown"`, read the contract's services
925
+ * (`customers.list`) before sending again.
926
+ */
927
+ removeGeneric: (input: ServiceRemoveGenericInput, options?: CallOptions) => Promise<SgpResult<ServiceRemoveGenericData>>;
928
+ /**
929
+ * Removes a TV service: `DELETE /api/servico/tv/{servico_id}` (no trailing slash), with the
930
+ * contract in a `multipart/form-data` body (without files), as SGP expects. Never retried.
931
+ *
932
+ * A success returns SGP's `msg`, the removed `servico_id` and `clientecontrato_id` (a `number`: SGP
933
+ * sends it as text, and `null` for an empty text). This route has no known rejection; failures carry `error.effect` by the same
934
+ * rules as `services.changePlan`. On `"unknown"`, read the contract's services before sending
935
+ * again.
936
+ */
937
+ removeTv: (input: ServiceRemoveTvInput, options?: CallOptions) => Promise<SgpResult<ServiceRemoveTvData>>;
938
+ }
939
+ /** SGP 2.0 client. */
220
940
  export interface SgpClient {
221
- ura: UraClient;
222
- os: OsClient;
223
- precadastro: PrecadastroClient;
941
+ /** Operations on catalogs (POPs, NAS, billing profiles). */
942
+ catalogs: CatalogsClient;
943
+ /** Operations on contracts. */
944
+ contracts: ContractsClient;
945
+ /** Operations on installation coverage. */
946
+ coverage: CoverageClient;
947
+ /** Operations of the CRM funnel. */
224
948
  crm: CrmClient;
225
- suporte: SuporteClient;
949
+ /** Operations on customers. */
950
+ customers: CustomersClient;
951
+ /** Operations on customers' documents. */
952
+ documents: DocumentsClient;
953
+ /**
954
+ * Operations that may change incompatibly in a minor release; SemVer holds for everything else.
955
+ */
956
+ experimental: ExperimentalClient;
957
+ /** Operations on invoices. */
958
+ invoices: InvoicesClient;
959
+ /** Operations on maintenance notices. */
960
+ maintenance: MaintenanceClient;
961
+ /** Operations on occurrences. */
962
+ occurrences: OccurrencesClient;
963
+ /** Operations on plans. */
964
+ plans: PlansClient;
965
+ /** Operations on pré-cadastros. */
966
+ preRegistrations: PreRegistrationsClient;
967
+ /**
968
+ * Raw call to a route no method covers yet. A developer tool: never expose it as an agent or
969
+ * MCP tool, and never build `path` or `body` from untrusted input.
970
+ *
971
+ * It uses the client's credentials, time budget, cancellation and hooks, and classifies by
972
+ * HTTP alone (the same status mapping as every method). Nothing else is interpreted: `ok: true`
973
+ * means SGP accepted the request at HTTP level (a 2xx), never that the business operation
974
+ * succeeded: SGP answers some refusals with a 200, so read `data` yourself. `data` is the body
975
+ * as received (parsed JSON, text, or `undefined` when empty), typed `unknown`; `response` is the
976
+ * full evidence.
977
+ *
978
+ * Destination: only a relative path under `/api/` of the configured instance is accepted (see
979
+ * {@link RawRequestInput.path}; a `;` is sent literally and stays on the same origin, under
980
+ * `/api/`); anything else is `INVALID_INPUT` with `effect: "none"` and `attempts: 0`, and
981
+ * nothing is sent. The annotations route is refused as `ROUTE_NOT_ALLOWED` (same effect and
982
+ * attempts; use `experimental.annotations.list`). Redirects are never followed: a 3xx is `INVALID_RESPONSE`.
983
+ * It is never retried, whatever `maxRetries` says.
984
+ *
985
+ * Effect: `"none"` only when the call was refused or cancelled before send. After a request was
986
+ * sent every failure is `"unknown"`, a 4xx included, and the HTTP verb is never taken as proof
987
+ * that a call only reads: check SGP before sending again.
988
+ *
989
+ * Sensitivity: the result declares no sensitive keys, so treat `data` and `response` as
990
+ * sensitive. The body is not redacted and may echo credentials or personal data (only header
991
+ * values are redacted); `toSafeLog` leaves it out. Log `toSafeLog(result)`, and send on only what `pick` names; an unknown key is
992
+ * never safe. Hooks get the method but never the path.
993
+ */
994
+ request: (input: RawRequestInput, options?: CallOptions) => Promise<SgpResult<unknown>>;
995
+ /** Operations on services. */
996
+ services: ServicesClient;
997
+ /** Operations on work orders. */
998
+ workOrders: WorkOrdersClient;
226
999
  }
227
- /** Creates an SGP client bound to `config`; `token` and `app` are sent on every request. */
228
- export declare const createSgpClient: (config: SgpClientConfig) => SgpClient;
1000
+ /** Creates a client. Throws `InvalidConfigurationError` for an invalid configuration. */
1001
+ export declare const createSgpClient: (options: ClientOptions) => SgpClient;