API do SisTelMax — v1
Como ela é diferente
Estas escolhas não são estilo: cada uma corresponde a um problema real que integradores enfrentam em APIs de provedor, e que custa horas de depuração justamente porque não dá erro — o campo vira nulo e a culpa parece ser do provedor.
- Uma credencial. Uma chave
sistel_live_…no cabeçalho. Semclient_id+client_secret+ usuário + senha, sem token que vence em 30 dias, sem refresh, sem host diferente por cliente. - O envelope é sempre
data. Nunca muda de nome conforme o recurso, e não existem pares singular/plural com significados diferentes. - Um nome por campo. O código Pix é
pix_codeem toda a API — não muda de grafia entre um endpoint e outro. - Dinheiro em centavos, inteiro (
amount_cents). Ponto flutuante em dinheiro erra um centavo na conciliação e ninguém descobre onde. - Datas em ISO-8601. Sempre.
- Limite por chave, não por IP — atrás de um SaaS, limite por IP pune o inquilino errado.
- Todo erro traz
request_id, no corpo e no cabeçalhoX-Request-Id. É o número que o suporte pede.
Endereço
/functions/v1/api-v1Um endereço próprio (api.sistelmax.com) entra depois e passa a responder no mesmo caminho — a rota /v1/… não muda, e nada do que você escrever agora quebra.
Autenticação
A chave é criada no sistema, em Sistema → Chaves de API, e o segredo aparece uma vez. Guarde-o; se perder, revogue e crie outra. Cada chave carrega escopos, e uma chamada fora do escopo recebe 403 — nunca 404 disfarçado.
curl /functions/v1/api-v1/v1/ping \
-H "Authorization: Bearer sistel_live_SUA_CHAVE"Respostas
Sucesso:
{ "data": { ... } } // ou { "data": [ ... ] }Erro:
{ "error": {
"code": "insufficient_scope",
"message": "A chave não tem o escopo necessário.",
"docs": "https://sistema.sistelmax.com/api",
"request_id": "0c9f…"
} }| HTTP | code | Quando |
|---|---|---|
| 400 | missing_parameter | Faltou um parâmetro obrigatório |
| 401 | unauthorized | Chave ausente, inválida, revogada ou expirada |
| 403 | insufficient_scope | A chave existe, mas não tem o escopo |
| 404 | not_found | Rota ou recurso inexistente |
| 405 | method_not_allowed | Método errado para a rota |
| 429 | rate_limited | Passou do limite da chave |
| 500 | internal_error | Falha nossa — mande o request_id |
No ar hoje
/v1/pingConfere a chave e devolve os escopos dela. Não exige escopo nenhum.
{ "data": { "ok": true, "version": "1.0",
"account": "Integração X",
"scopes": ["customers:read","invoices:read"] } }/v1/customers?document= | ?phone=customers:readIdentifica o cliente por CPF/CNPJ ou por telefone — as duas portas de um PBX quando o telefone toca. Aceita o documento com ou sem pontuação, e o telefone com ou sem DDD e nono dígito.
{ "data": [ {
"id": "83f3b7be-…", "code": "DEMO001",
"name": "ANA PAULA DEMONSTRACAO",
"document": "11111111111", "document_masked": false,
"status": "ativo", "blocked": false,
"due_day": 10,
"address": { "street": "Rua da Amostra", "number": "100", "district": "Centro" }
} ] }blocked responde direto à pergunta que se faz na ligação — “posso atender ou está cortado?” — sem você precisar conhecer os nomes internos de situação. Quem deve mas ainda não foi cortado aparece comblocked: false, porque ele ainda navega.
O documento só sai inteiro quando foi ele o parâmetro da busca.Procurando por phone, ele vem mascarado (529*****25) e document_masked vemtrue: dá para conferir com quem está na linha, e não dá para montar uma base de CPF varrendo telefones. Sempre só dígitos — você não precisa limpar pontuação.
/v1/customers/{id}/invoices?status=open|paid|allinvoices:readFaturas do cliente, com tudo o que se usa para pagar.
{ "data": [ {
"id": "c6f91d1f-…",
"reference": "2026-12-01", "due_date": "2026-12-15",
"amount_cents": 6000, "status": "aberto",
"overdue": false,
"installment": 1, "installments": 12,
"pix_code": "00020101021226940014BR.GOV.BCB.PIX…",
"barcode": "36490.00027 00044.074706 00000.381640 1 0000…",
"pdf_url": "https://…"
} ] }status usa o mesmo vocabulário da tela do sistema (aberto, vencido, pago,identificado, expirado, cancelado). Traduzir para inglês criaria dois nomes para a mesma coisa.
/v1/customers/{id}/serviceservice:readComo está o acesso do cliente. Só isso.
{ "data": {
"service_status": "bloqueado",
"plan": { "name": "Fibra 600 MB" } // ou null
} }service_status | Significa |
|---|---|
| ativo | Acesso normal |
| bloqueado | Acesso cortado |
| reduzido | Navegando em velocidade reduzida |
| aguardando_instalacao | Contratou, ainda não foi instalado |
| cancelado | Contrato encerrado |
Nada financeiro sai aqui — nem quantas faturas estão vencidas, nem o valor que o cliente paga. Isso é invoices:read, de propósito: uma chave que só precisa saber se o acesso está no ar não deve receber junto a situação financeira da pessoa.
plan.name é o nome público do plano, e vem nullquando a operadora não publicou um — o que hoje é comum. O rótulo interno de cobrança nunca sai.
blocked e service_status podem discordar, e não é defeito: blocked (em /customers) é a situação do cadastro; service_status é a do acesso. Um cliente pode estar ativo no cadastro e bloqueado na rede, ou o contrário, durante uma sincronização. Para decidir se atende, useservice_status.
/v1/customers/{id}/ticketstickets:readAs ordens de serviço do cliente.
{ "data": [ {
"number": 1042,
"subject": "Sem sinal", "category": "manutencao",
"work_type": "manutencao", "stage": "em_atendimento",
"opened_by_api": true,
"created_at": "2026-08-31T14:02:11Z"
} ] }stage tem três valores: recebida,em_atendimento (já tem técnico) e concluida.
O que não sai, e é de propósito: o nome e o id do técnico (dado pessoal de funcionário), a descrição livre digitada pelo atendente, o setor e quem abriu internamente. O subject é o nome do tipo de chamado, nunca o texto do chamado.
/v1/customers/{id}/ticketstickets:write{ "category": "manutencao",
"description": "cliente relata queda de sinal desde ontem à noite" }Categorias possíveis: manutencao, religamento,cancelamento, outros — mas só as que a operadora liberar para a API funcionam. Sem liberação, a resposta é422 dizendo isso.
description precisa de pelo menos 15 caracteres: é o que o técnico vai ler antes de sair. Máximo de 300.
| HTTP | Quando |
|---|---|
| 201 | Aberta. Vem number, que é o protocolo do assinante. |
| 409 | Já existe uma O.S. aberta desse tipo para o cliente — e o number dela vem no erro. Não repita: é estado, não falha. |
| 422 | Categoria não liberada para a API nesta operadora, ou cadastro cancelado. |
| 429 | Muitas O.S. para o mesmo cliente na última hora, ou o teto diário da chave. |
Cada abertura avisa um técnico de verdade. Por isso há teto diário por chave e freio por cliente — e por isso a operadora escolhe, uma a uma, quais categorias a API pode abrir.
Escopos
A chave só abre o que você marcar. Os marcados com · ainda não têm endpoint publicado — estão reservados para não mudar de nome depois.
| Escopo | O que abre |
|---|---|
customers:read | Identificar cliente por CPF/CNPJ ou telefone |
invoices:read | Faturas, com Pix, linha digitável e PDF |
service:read | Situação do acesso (sem nada financeiro) |
plans:read · | Catálogo de planos |
tickets:read tickets:write | Consultar e abrir ordens de serviço |
promises:read · promises:write · | Agendar pagamento (segura o corte) |
coverage:read · | Cobertura por endereço |
leads:write · | Registrar interessado |
contacts:* conversations:* messages:* · | SisTelChat |
agents:read inboxes:read reports:read · | Equipe e relatórios |
webhooks:manage · | Webhooks de saída |
Limite de uso
Cada chave tem seu próprio limite por minuto, definido na criação (padrão: 120). Ao exceder, a resposta é 429 comcode: "rate_limited". O limite é por chave — duas integrações suas não disputam a mesma cota.
