# Conttrole — API de Integração (conteúdo completo para IA) > API REST para emitir e consultar documentos fiscais eletrônicos (NF-e, NFC-e, > NFS-e). Use este arquivo como contexto para implementar a integração. Base URL: https://api.conttrole.io Contrato OpenAPI (fonte da verdade dos endpoints): https://api.conttrole.io/openapi.json ## Autenticação - Esquema: HTTP Bearer. Header: `Authorization: Bearer ck_live_`. - A chave é por empresa. Toda requisição opera sobre a empresa dona da chave — nunca envie um identificador de empresa no corpo/query. - Formato da chave: `ck___` (ambiente = live|test). - A chave em texto puro é exibida UMA vez na criação (guardamos só o hash). - Escopos (vazio = acesso total na empresa): - documents:read — ler documentos fiscais, baixar XML/DANFE, consultar inutilizações - documents:write — criar/emitir/cancelar documentos, carta de correção, inutilizar - companies:read — ler dados da empresa - webhooks:read — listar endpoints e entregas de webhook - webhooks:write — criar/alterar/remover endpoints de webhook - tax-rules:read — listar/detalhar regras tributárias - tax-rules:write — criar/alterar/remover regras tributárias ## Formato de erro (todas as respostas de erro) { "statusCode": , "error": "", "message": "", "code": "" } Códigos comuns: - 400 validation_error — parâmetros inválidos (campo "issues" detalha) - 401 missing_api_key — header Authorization ausente - 401 invalid_api_key — chave inválida/revogada/expirada - 403 insufficient_scope — escopo insuficiente - 404 not_found — recurso não encontrado - 429 — rate limit excedido (use backoff exponencial) - 500 — erro interno ## Paginação Listagens aceitam page (>=1) e pageSize (1..100) e retornam: { "data": [ ... ], "meta": { "page", "pageSize", "total", "totalPages" } } ## Endpoints (resumo — detalhe completo no OpenAPI) - GET /health — liveness (sem auth) - GET /health/ready — readiness (checa o banco) - GET /v1/fiscal-documents — lista documentos (documents:read; query: page, pageSize, status, type) - POST /v1/fiscal-documents — cria documento DRAFT (documents:write; body: type, clientId, items[], payments[], taxRuleId?, emit?) - GET /v1/fiscal-documents/{id} — detalha um documento (documents:read) - POST /v1/fiscal-documents/{id}/emit — dispara a emissão, async/202 (documents:write) - POST /v1/fiscal-documents/{id}/cancel — cancela, síncrono (documents:write; body: justification 15..255) - POST /v1/fiscal-documents/{id}/correction-letter — carta de correção (documents:write; body: correction 15..1000) - POST /v1/fiscal-documents/{id}/delivery-receipt — comprovante de entrega da NF-e, evento 110130 (documents:write; body: deliveredAt ISO c/ fuso, receiverName 2..60, receiverDocument 2..20, latitude/longitude?, proof {contentType image/jpeg|image/png|application/pdf, base64 <= 3 MB}). Comprovante ativo IMPEDE cancelar a NF-e. - DELETE /v1/fiscal-documents/{id}/delivery-receipt — cancela o comprovante ativo, evento 110131 (documents:write) - GET /v1/fiscal-documents/{id}/xml — baixa XML (documents:read; application/xml) - GET /v1/fiscal-documents/{id}/danfe — baixa DANFE/DANFSe (documents:read; application/pdf) - POST /v1/fiscal-documents/{id}/webhook — dispara o webhook da nota (webhooks:write; 202 {dispatched}). Para nota que NUNCA gerou entrega (endpoint cadastrado depois da emissão) — o reenvio por delivery exige uma entrega preexistente. Evento = estado ATUAL da nota. Gera evt_ NOVO (o parceiro não deduplica contra a entrega original). 60/min por empresa. - POST /v1/fiscal-inutilizations — inutiliza faixa de numeração (documents:write) - GET /v1/fiscal-inutilizations[/{id}] — lista/detalha inutilizações (documents:read) - GET /v1/tax-rules — lista regras tributárias (tax-rules:read; query: model, isActive) - POST /v1/tax-rules — cria regra (tax-rules:write) - GET /v1/tax-rules/{id} — detalha regra (tax-rules:read) - PATCH /v1/tax-rules/{id} — atualiza (tax-rules:write; sub-regras enviadas SUBSTITUEM) - DELETE /v1/tax-rules/{id} — soft delete (tax-rules:write) - GET/POST /v1/webhooks, GET/PATCH/DELETE /v1/webhooks/{id}, ...deliveries — webhooks (webhooks:read/write). GET .../deliveries devolve, por entrega: payload (corpo EXATO enviado, o mesmo assinado), responseStatus/responseBody (o que o servidor do integrador respondeu), errorMessage e eventId. Esses três são o resumo da ÚLTIMA tentativa; attemptLog traz uma entrada por tentativa (attempt, signedAt, signature, responseStatus, responseBody, errorMessage, durationMs). O corpo não se repete por tentativa (é o mesmo payload); a ASSINATURA sim, porque o HMAC cobre "signedAt.payload". Entregas antigas vêm com attemptLog vazio. - POST /v1/webhooks/backfill — reenvia webhooks de um PERÍODO (webhooks:write). Body: from/to (ISO, data de emissão), types?, onlyMissing? (default true: pula quem já teve entrega, então repetir NÃO duplica), environment?, dryRun?. Use dryRun:true PRIMEIRO (200 {matched, truncated}) — cada nota vira um POST no servidor do integrador. Real devolve 202 {runId}. Teto 5.000 notas/execução (truncated:true acima) e 5 chamadas/min por empresa. PREFIRA isto a laço sobre POST /v1/fiscal-documents/{id}/webhook. ## Fluxos de uso (ordem das chamadas) - Emitir nota: garanta um cliente (cadastrado no painel; ainda não há API de clientes) -> POST /v1/fiscal-documents (ou com "emit": true) -> POST .../emit -> faça polling em GET /v1/fiscal-documents/{id} até status AUTHORIZED/REJECTED (ou use webhooks) -> baixe XML e DANFE. Status: DRAFT, PROCESSING, AUTHORIZED, REJECTED, CANCELLED. - Falha de COMUNICAÇÃO com a SEFAZ (fora do ar/timeout) NÃO é rejeição: o documento volta a DRAFT e é reemitido automaticamente. Nesse intervalo nenhum webhook é enviado — document.rejected só sai em rejeição do fisco ou quando as tentativas automáticas se esgotam. Ausência de evento não significa falha; consulte o status. - Impostos do item (prioridade): campos explícitos no item > taxRuleId (no documento ou no item) > configuração da empresa. NCM ausente herda o da empresa. - Pagamentos: payments[].method é enum (MONEY, PIX, CREDIT_CARD, DEBIT_CARD, BANK_SLIP, NO_PAYMENT, OTHERS, ...); quando OTHERS, "description" é obrigatória. Campos opcionais de cartão (cardFlag, cardCNPJ, cardAuthorization) e pix (pixKey, pixTxId). - Regras tributárias: crie em POST /v1/tax-rules e referencie o id como taxRuleId. A regra casa por UF do destinatário + tipo de cliente. taxRuleId de outra empresa -> 422. - Cancelar: POST .../cancel (justification 15..255). Corrigir: POST .../correction-letter (correction 15..1000; só NF-e/NFC-e autorizadas, prazo 30 dias, máx 20). ## Exemplo (curl) curl https://api.conttrole.io/v1/fiscal-documents \ -H "Authorization: Bearer ck_live_sua_chave" ## Recomendações para implementação com IA - Gere o client a partir de https://api.conttrole.io/openapi.json. - Trate o campo "code" do erro para lógica de retry/feedback. - Implemente backoff exponencial em 429 e em erros 5xx. - Nunca exponha a chave no front-end; mantenha-a no servidor.