Skip to Content
API de integração — v1
Fluxos de uso

Fluxos de uso

Guias ponta a ponta dos cenários mais comuns da API. Os exemplos usam curl e a base https://api.conttrole.io; troque pela sua URL de integração se tiver um domínio próprio. Toda chamada autenticada leva o header Authorization: Bearer ck_live_sua_chave (ver Autenticação).

O detalhe de cada campo (tipos, enums, obrigatoriedade) está na Referência da API. Aqui o foco é a ordem das chamadas.

1. Emitir uma nota fiscal

A emissão tem dois momentos: criar o documento (rascunho, síncrono) e emitir (processamento assíncrono junto ao fisco). Você acompanha pelo status.

Passo 0 — pré-requisitos

  • Cliente cadastrado: o clientId é de um cliente que já existe na sua empresa. O cadastro de clientes é feito no painel (ainda não há endpoint de clientes na API). Anote o id do cliente.
  • Empresa configurada: certificado digital e configurações fiscais válidas no painel — sem isso a emissão é rejeitada.

Passo 1 — criar o documento

curl -X POST https://api.conttrole.io/v1/fiscal-documents \ -H "Authorization: Bearer ck_live_sua_chave" \ -H "Content-Type: application/json" \ -d '{ "type": "NFE", "clientId": "cli_xxx", "operationNature": "Venda de mercadoria", "items": [ { "code": "P1", "description": "Produto 1", "cfop": "5102", "ncm": "61091000", "unit": "UN", "quantity": 2, "unitValue": 50.0 } ], "payments": [ { "method": "PIX", "value": 100.0 } ] }'

Resposta 201 — o documento nasce em DRAFT (ainda sem número definitivo):

{ "id": "doc_abc", "type": "NFE", "status": "DRAFT", "number": 0, "runId": null }

Passo 2 — emitir

curl -X POST https://api.conttrole.io/v1/fiscal-documents/doc_abc/emit \ -H "Authorization: Bearer ck_live_sua_chave"

Resposta 202 com runId — o documento entra em PROCESSING e o trabalho roda em segundo plano:

{ "documentId": "doc_abc", "status": "PROCESSING", "runId": "run_..." }

Atalho: envie "emit": true no corpo do passo 1 para criar e emitir numa só chamada. A resposta 201 já volta com status: "PROCESSING" e o runId.

Passo 3 — acompanhar o status

Há duas formas de saber o desfecho da emissão. Prefira webhooks: cadastre um endpoint uma vez e a API te avisa com um POST assinado (document.authorized / document.rejected) assim que a nota muda de estado — sem ficar consultando. Veja Receber eventos via webhook.

Quando webhooks não forem viáveis, use polling como alternativa: consulte o documento até sair de PROCESSING.

curl https://api.conttrole.io/v1/fiscal-documents/doc_abc \ -H "Authorization: Bearer ck_live_sua_chave"
statusSignificado
DRAFTRascunho, ainda não emitido
PROCESSINGEm emissão (aguarde)
AUTHORIZEDAutorizada pelo fisco — tem accessKey
REJECTEDRejeitada — veja rejectionReason; corrija e emita de novo
CANCELLEDCancelada

Passo 4 — baixar XML e DANFE

Depois de AUTHORIZED:

# XML autorizado (application/xml) curl https://api.conttrole.io/v1/fiscal-documents/doc_abc/xml \ -H "Authorization: Bearer ck_live_sua_chave" -o nota.xml # DANFE/DANFSe em PDF (application/pdf) curl https://api.conttrole.io/v1/fiscal-documents/doc_abc/danfe \ -H "Authorization: Bearer ck_live_sua_chave" -o nota.pdf

2. Definir os impostos da nota

Há três formas de preencher os impostos dos itens, nesta prioridade:

  1. Explícito no item — você manda os campos tributários direto:

    { "code": "P1", "description": "Produto 1", "cfop": "5102", "unit": "UN", "quantity": 1, "unitValue": 100, "icmsSituation": "00", "icmsRate": 18, "pisSituation": "01", "pisRate": 1.65 }
  2. Regra tributária — referencie uma regra por taxRuleId, no documento (vale pra todos os itens) ou no item (sobrepõe a do documento):

    { "type": "NFE", "clientId": "cli_xxx", "taxRuleId": "rule_abc", "items": [ { "code": "P1", "description": "...", "cfop": "5102", "unit": "UN", "quantity": 1, "unitValue": 100 } ] }

    A regra é casada por UF do destinatário + tipo de cliente. Crie/liste regras em /v1/tax-rules (ver fluxo 3).

  3. Configuração da empresa — sem imposto no item e sem taxRuleId, vale a configuração tributária padrão da empresa. NCM ausente também herda o da empresa.

O taxRuleId precisa ser de uma regra da sua empresa — caso contrário a criação responde 422 invalid_tax_rule.

3. Criar e usar regras tributárias

Regras tributárias evitam repetir impostos em cada nota. Requer escopo tax-rules:write para criar e tax-rules:read para listar.

Criar uma regra (NF-e)

curl -X POST https://api.conttrole.io/v1/tax-rules \ -H "Authorization: Bearer ck_live_sua_chave" \ -H "Content-Type: application/json" \ -d '{ "name": "Venda dentro de SP", "model": "NFE", "nfeTaxRules": [ { "states": ["SP"], "clientTypes": ["CONTRIBUINTE"], "icmsCst": "00", "icmsPIcms": 18, "pisCst": "01", "pisPPis": 1.65, "cofinsCst": "01", "cofinsPCofins": 7.6 } ] }'

Resposta 201 com o id da regra — use esse id como taxRuleId na criação da nota (fluxo 2).

Listar regras

curl "https://api.conttrole.io/v1/tax-rules?model=NFE&isActive=true" \ -H "Authorization: Bearer ck_live_sua_chave"

PATCH /v1/tax-rules/{id} atualiza a regra — enviar nfeTaxRules/ nfseTaxRules substitui integralmente as sub-regras daquele modelo. DELETE /v1/tax-rules/{id} faz soft delete.

4. Cancelar uma nota autorizada

Síncrono — a API chama o fisco e devolve o resultado. A justificativa tem de ter 15 a 255 caracteres (regra SEFAZ) e o cancelamento respeita o prazo legal.

curl -X POST https://api.conttrole.io/v1/fiscal-documents/doc_abc/cancel \ -H "Authorization: Bearer ck_live_sua_chave" \ -H "Content-Type: application/json" \ -d '{ "justification": "Cancelamento a pedido do cliente." }'

5. Corrigir uma nota (Carta de Correção)

Para NF-e/NFC-e autorizadas: evento 110110, síncrono. Texto de 15 a 1000 caracteres, prazo de 30 dias, máximo de 20 correções. Não corrige valores fiscais nem dados de emitente/destinatário, e não se aplica a NFS-e.

curl -X POST https://api.conttrole.io/v1/fiscal-documents/doc_abc/correction-letter \ -H "Authorization: Bearer ck_live_sua_chave" \ -H "Content-Type: application/json" \ -d '{ "correction": "Correção do endereço de entrega do produto." }'

6. Inutilizar uma faixa de numeração

Quando um intervalo de números de NF-e/NFC-e foi pulado e precisa ser declarado como inutilizado:

curl -X POST https://api.conttrole.io/v1/fiscal-inutilizations \ -H "Authorization: Bearer ck_live_sua_chave" \ -H "Content-Type: application/json" \ -d '{ "series": 1, "startNumber": 10, "endNumber": 20, "justification": "Numeração pulada por falha de sistema." }'

7. Receber eventos via webhook (sem polling)

Em vez de consultar o status repetidamente, cadastre um endpoint e receba um POST assinado quando a nota muda de estado. Requer escopo webhooks:write para criar e webhooks:read para listar/consultar entregas.

Passo 1 — criar o endpoint

curl -X POST https://api.conttrole.io/v1/webhooks \ -H "Authorization: Bearer ck_live_sua_chave" \ -H "Content-Type: application/json" \ -d '{ "url": "https://seu-app.com/webhooks/conttrole", "description": "Eventos fiscais de produção", "events": ["DOCUMENT_AUTHORIZED", "DOCUMENT_REJECTED"] }'
  • url deve ser HTTPS (em produção) e pública — IPs privados/internos são bloqueados (proteção anti-SSRF).
  • events filtra o que você recebe; vazio = todos. Eventos disponíveis: DOCUMENT_AUTHORIZED, DOCUMENT_REJECTED, DOCUMENT_CANCELLED, DOCUMENT_INUTILIZED.

Resposta 201 — o secret (whsec_…) vem uma única vez; guarde-o para validar as assinaturas:

{ "id": "ep_abc", "url": "https://seu-app.com/webhooks/conttrole", "events": ["DOCUMENT_AUTHORIZED", "DOCUMENT_REJECTED"], "isActive": true, "secret": "whsec_xxxxxxxx" }

Perdeu o secret? Gere outro com POST /v1/webhooks/{id}/rotate-secret (o antigo deixa de valer).

Passo 2 — validar a assinatura no seu endpoint

Cada entrega traz o header X-Conttrole-Signature: t=<timestamp>,v1=<hmac>, onde hmac é o HMAC-SHA256 de "<timestamp>.<corpo-cru>" usando o seu secret. Recalcule e compare (comparação em tempo constante):

import crypto from "node:crypto"; function isValid(rawBody, signatureHeader, secret) { const parts = Object.fromEntries( signatureHeader.split(",").map((kv) => kv.split("=")), ); const expected = crypto .createHmac("sha256", secret) .update(`${parts.t}.${rawBody}`) .digest("hex"); return crypto.timingSafeEqual( Buffer.from(expected), Buffer.from(parts.v1), ); }

Responda 2xx rapidamente. Em falha (timeout ou status ≠ 2xx) a entrega é reagendada automaticamente com backoff (até 20 tentativas / 24h).

Passo 3 — testar e inspecionar entregas

# Dispara um evento de teste para o endpoint curl -X POST https://api.conttrole.io/v1/webhooks/ep_abc/test \ -H "Authorization: Bearer ck_live_sua_chave" # Histórico de entregas (status, tentativas) curl https://api.conttrole.io/v1/webhooks/ep_abc/deliveries \ -H "Authorization: Bearer ck_live_sua_chave" # Reenviar manualmente uma entrega que falhou curl -X POST https://api.conttrole.io/v1/webhooks/ep_abc/deliveries/del_xyz/redeliver \ -H "Authorization: Bearer ck_live_sua_chave"

Para editar (PATCH /v1/webhooks/{id}), remover (DELETE) e os demais detalhes de segurança e payload dos eventos, veja Webhooks.

Last updated on