Documentação / Webhooks v1
API REST fiscal

Receba atualizações automáticas do ciclo fiscal em tempo real.

Esta documentação descreve a versão pública atual da API fiscal da Contora, com base compartilhada de empresas, certificados, chaves, filas, webhooks e artefatos para NF-e, NFC-e, NFS-e, CT-e e MDF-e. NF-e, NFC-e e NFS-e operam em produção regular; CT-e e MDF-e em produção assistida e controlada.

Atualizado em .

Webhooks

Para não travar o ERP aguardando resposta da SEFAZ, a plataforma envia mudanças de status por webhook. O endpoint pode ser cadastrado por empresa e receberá os eventos assinados pela plataforma.

GET https://fiscal.contora.com.br/api/v1/webhooks?page=1&per_page=20&is_active=1
POST https://fiscal.contora.com.br/api/v1/webhooks
{
  "company_id": "uuid-da-empresa",
  "url": "https://seu-erp.com.br/webhooks/fiscal",
  "secret": "segredo-para-assinatura",
  "events": [
    "document.queued",
    "document.processing_started",
    "document.authorized",
    "document.rejected",
    "document.cancelled",
    "document.cancellation_rejected",
    "document.failed",
    "nfe.received"
  ]
}

Catálogo de eventos suportados

O ciclo de vida de todos os documentos fiscais emitidos pela plataforma (NF-e modelo 55, NFC-e modelo 65, NFS-e, CT-e e MDF-e) é unificado sob o prefixo document.*. Eventos de documentos recebidos de fornecedores utilizam o prefixo nfe.*, e eventos de gestão cadastral utilizam company.*.

Evento
Escopo / Descrição
document.authorized
Documento autorizado com sucesso na SEFAZ ou Prefeitura. Inclui protocolo, chave de acesso e links diretos para os artefatos (XML autorizado e DANFE em PDF).
document.rejected
Documento rejeitado pelo órgão fiscal. Inclui last_error_code, last_error_message e o status code devolvido pela SEFAZ no context.
document.cancelled
Cancelamento homologado pelo órgão fiscal. Contém cancellation_protocol, cancellation_status_code e data de cancelamento.
document.cancellation_rejected
Pedido de cancelamento rejeitado pelo órgão fiscal (ex: prazo de cancelamento extrapolado).
document.failed
Falha crítica ou erro de comunicação antes ou durante a transmissão (ex: indisponibilidade do autorizador).
document.queued
Documento aceito pela API e enfileirado para processamento assíncrono.
document.processing_started
Início da assinatura digital, validação de schema e comunicação com o autorizador.
nfe.received
NF-e de terceiro (fornecedor) capturada via Distribuição DF-e na SEFAZ Nacional. Contém chave de acesso, emitente, valor total e status de manifestação.
company.certificate_expiring
Alerta preventivo de vencimento do Certificado Digital A1 da empresa (disparado nos marcos de 30, 15, 7 e 1 dia restante).
company.certificate_expired
Aviso de que o Certificado Digital A1 da empresa expirou.
Ambientes (data.environment): Nos eventos de documento (document.*) e de notas recebidas (nfe.received), a propriedade data.environment contém sempre as strings literais em minúsculas: producao ou homologacao. Eventos administrativos como company.certificate_* não possuem o campo environment pois são vinculados diretamente ao cadastro da empresa.

Cadastro no console

Se a equipe ainda estiver em onboarding, o caminho mais simples é cadastrar o endpoint pelo próprio console da plataforma. Hoje o painel ja permite criar, ativar, testar e reenfileirar entregas com falha.

Primeiro teste Cadastre a URL, gere um segredo, envie um ping de teste e valide assinatura e conectividade antes de emitir.
Operacao continua Depois da integração pronta, o histórico recente de deliveries e falhas fica visível no painel de webhooks.

Histórico operacional

As listagens de endpoints, deliveries e pings de teste seguem o mesmo padrão paginado da API, com meta e links. Isso facilita auditoria, telas administrativas e sincronizacao incremental no ERP integrador.

GET https://fiscal.contora.com.br/api/v1/webhooks/{endpoint}/deliveries?page=1&per_page=20&status=failed&event=document.authorized
GET https://fiscal.contora.com.br/api/v1/webhooks/{endpoint}/tests?page=1&per_page=20&status=failed

Rotação de secret

Se o secret do webhook for comprometido ou precisar ser rotacionado por política de segurança, use o endpoint dedicado. O novo secret é retornado apenas uma vez na resposta.

POST https://fiscal.contora.com.br/api/v1/webhooks/{endpoint}/rotate-secret
POST https://fiscal.contora.com.br/api/v1/webhooks/{endpoint}/rotate-secret
{
  "ok": true,
  "message": "Secret rotacionado com sucesso. Atualize seu endpoint em até 24 horas.",
  "data": {
    "id": "uuid-do-endpoint",
    "secret": "novo-secret-gerado-automaticamente",
    "secret_rotated_at": "2026-07-11T10:30:00-03:00",
    "migration_deadline": "2026-07-12T10:30:00-03:00",
    "signature_migration": {
      "primary_header": "X-Fiscal-Signature",
      "next_header": "X-Fiscal-Signature-Next"
    }
  }
}
Migração gradual Por 24 horas, X-Fiscal-Signature usa o secret anterior e X-Fiscal-Signature-Next usa o novo. Depois do prazo, o novo passa a ser a assinatura principal.
Notificação A rotação fica registrada na auditoria e o evento webhook.secret_rotated é enfileirado para o próprio endpoint.
Migração sem interrupção: atualize o consumidor para validar primeiro X-Fiscal-Signature-Next com o novo secret. Ao fim das 24 horas, X-Fiscal-Signature passará automaticamente a usar esse novo secret.

Estratégia de retry

A plataforma utiliza backoff exponencial com jitter para retries de webhooks falhos. Isso evita sobrecarga no endpoint do integrador em caso de falhas temporárias.

GET https://fiscal.contora.com.br/api/v1/webhooks/{endpoint}/retry-info
GET https://fiscal.contora.com.br/api/v1/webhooks/{endpoint}/retry-info
{
  "ok": true,
  "data": {
    "endpoint_id": "uuid-do-endpoint",
    "retry_strategy": {
      "pattern": [30, 60, 120, 240, 480, 960, 1920, 3600],
      "description": "Backoff exponencial com jitter: ~30s, ~60s, ~120s, ~240s, ~480s, ~960s, ~1920s, ~3600s",
      "total_max_wait_seconds": 7410
    },
    "max_attempts": 8,
    "rules": {
      "server_errors": "Repete em caso de status 5xx",
      "rate_limits": "Repete em caso de status 429",
      "timeouts": "Repete em caso de status 408",
      "client_errors": "Não repete em caso de status 4xx (exceto 429 e 408)"
    }
  }
}
Tentativa 1
~30 segundos após falha
Tentativa 2
~60 segundos após falha
Tentativa 3
~2 minutos após falha
Tentativa 4
~4 minutos após falha
Tentativa 5
~8 minutos após falha
Tentativa 6
~16 minutos após falha
Tentativa 7
~32 minutos após falha
Tentativa 8
~60 minutos após falha (máximo)

Headers e assinatura

Os webhooks da v1 usam os cabeçalhos abaixo.

X-Fiscal-Event
Nome do evento entregue.
X-Fiscal-Delivery-Id
Identificador numérico da entrega do pipeline fiscal.
X-Fiscal-Idempotency-Key
Chave para deduplicação no ERP consumidor.
X-Fiscal-Attempt
Número da tentativa atual.
X-Fiscal-Timestamp
Timestamp ISO 8601 usado na assinatura.
X-Fiscal-Signature
HMAC SHA-256 em timestamp.body usando o segredo do endpoint.
assinatura = hex(hmac_sha256(timestamp + "." + body, secret))

Exemplo 1: NF-e Autorizada (document.authorized)

POST /webhooks/fiscal HTTP/1.1
Content-Type: application/json
User-Agent: Fiscal-Contora-Webhook/1.0
X-Fiscal-Event: document.authorized
X-Fiscal-Delivery-Id: 4812
X-Fiscal-Idempotency-Key: delivery-4812
X-Fiscal-Attempt: 1
X-Fiscal-Timestamp: 2026-10-21T08:55:25-03:00
X-Fiscal-Signature: c8f3...

{
  "id": 9931,
  "event": "document.authorized",
  "created_at": "2026-10-21T08:55:25-03:00",
  "data": {
    "document_id": "80851398-6707-42a2-9fb5-89fee809b9f2",
    "document_type": "nfe",
    "status": "authorized",
    "processing_status": "completed",
    "environment": "producao",
    "series": 1,
    "number": 5622,
    "access_key": "35261016834821000163550010000056221267987067",
    "protocol": "135264472169093",
    "cancellation_status": null,
    "cancellation_protocol": null,
    "cancellation_status_code": null,
    "cancellation_status_message": null,
    "cancelled_at": null,
    "correction_status": null,
    "correction_sequence": 0,
    "correction_protocol": null,
    "correction_status_code": null,
    "correction_status_message": null,
    "corrected_at": null,
    "last_error_code": null,
    "last_error_message": null,
    "artifacts": {
      "xml_unsigned": "https://fiscal.contora.com.br/api/v1/nfe/drafts/80851398-6707-42a2-9fb5-89fee809b9f2/artifacts/xml_unsigned",
      "xml_signed": "https://fiscal.contora.com.br/api/v1/nfe/drafts/80851398-6707-42a2-9fb5-89fee809b9f2/artifacts/xml_signed",
      "xml_authorized": "https://fiscal.contora.com.br/api/v1/nfe/drafts/80851398-6707-42a2-9fb5-89fee809b9f2/artifacts/xml_authorized",
      "pdf": "https://fiscal.contora.com.br/api/v1/nfe/drafts/80851398-6707-42a2-9fb5-89fee809b9f2/artifacts/pdf_danfe"
    }
  },
  "context": {
    "action": "authorize",
    "sefaz_status_code": "100",
    "protocol": "135264472169093"
  }
}

Exemplo 2: NF-e Rejeitada pela SEFAZ (document.rejected)

POST /webhooks/fiscal HTTP/1.1
Content-Type: application/json
User-Agent: Fiscal-Contora-Webhook/1.0
X-Fiscal-Event: document.rejected
X-Fiscal-Delivery-Id: 4813
X-Fiscal-Idempotency-Key: delivery-4813
X-Fiscal-Attempt: 1
X-Fiscal-Timestamp: 2026-10-21T08:55:31-03:00
X-Fiscal-Signature: e4a1...

{
  "id": 9932,
  "event": "document.rejected",
  "created_at": "2026-10-21T08:55:31-03:00",
  "data": {
    "document_id": "3fa296c9-072e-414e-913b-f30016172054",
    "document_type": "nfe",
    "status": "error",
    "processing_status": "completed",
    "environment": "producao",
    "series": 1,
    "number": 466,
    "access_key": "35261056390185000142550010000004661056506881",
    "protocol": null,
    "cancellation_status": null,
    "cancellation_protocol": null,
    "cancellation_status_code": null,
    "cancellation_status_message": null,
    "cancelled_at": null,
    "correction_status": null,
    "correction_sequence": 0,
    "correction_protocol": null,
    "correction_status_code": null,
    "correction_status_message": null,
    "corrected_at": null,
    "last_error_code": "732",
    "last_error_message": "Rejeição: CFOP de operação interestadual e idDest <> 2",
    "artifacts": {
      "xml_unsigned": "https://fiscal.contora.com.br/api/v1/nfe/drafts/3fa296c9-072e-414e-913b-f30016172054/artifacts/xml_unsigned",
      "xml_signed": "https://fiscal.contora.com.br/api/v1/nfe/drafts/3fa296c9-072e-414e-913b-f30016172054/artifacts/xml_signed",
      "pdf": "https://fiscal.contora.com.br/api/v1/nfe/drafts/3fa296c9-072e-414e-913b-f30016172054/artifacts/pdf_danfe"
    }
  },
  "context": {
    "action": "authorize",
    "sefaz_status_code": "732",
    "sefaz_status_message": "Rejeição: CFOP de operação interestadual e idDest <> 2"
  }
}

Exemplo 3: NF-e Recebida de Fornecedor via DF-e (nfe.received)

POST /webhooks/fiscal HTTP/1.1
Content-Type: application/json
User-Agent: Fiscal-Contora-Webhook/1.0
X-Fiscal-Event: nfe.received
X-Fiscal-Delivery-Id: 4814
X-Fiscal-Idempotency-Key: delivery-4814
X-Fiscal-Attempt: 1
X-Fiscal-Timestamp: 2026-10-21T08:56:00-03:00
X-Fiscal-Signature: 7b29...

{
  "id": "e229be60-d621-4f1b-bd63-bfa6403597d3",
  "event": "nfe.received",
  "created_at": "2026-10-21T08:56:00-03:00",
  "company_id": "4e72ce53-a553-4877-bb89-72f1076f8e77",
  "data": {
    "received_id": "993a4087-3ce9-4dc6-b51c-ca04bfdf2146",
    "environment": "producao",
    "access_key": "31261000000000000191550010000001231000001234",
    "emitter_document": "12345678000195",
    "emitter_name": "FORNECEDOR INDUSTRIAL LTDA",
    "total_amount": 14500.50,
    "issued_at": "2026-10-21T07:30:00-03:00",
    "has_full_xml": false,
    "manifest_type": null
  }
}
Contrato de entrega: responda com qualquer HTTP 2xx em até 10 segundos. Considere eventos duplicados ou fora de ordem, deduplique por X-Fiscal-Idempotency-Key e não permita regressão do estado conhecido. A plataforma não publica uma allowlist fixa de IPs; a autenticidade vem da assinatura HMAC. Como proteção anti-replay, recomendamos rejeitar timestamps com diferença superior a 5 minutos, depois de validar a assinatura.

Exemplo de Validação em PHP:

<?php
$secret = 'seu_webhook_secret';
$timestamp = $_SERVER['HTTP_X_FISCAL_TIMESTAMP'] ?? '';
$signature = $_SERVER['HTTP_X_FISCAL_SIGNATURE'] ?? '';
$body = file_get_contents('php://input');

$payload = $timestamp . '.' . $body;
$expectedSignature = hash_hmac('sha256', $payload, $secret);

if (hash_equals($expectedSignature, $signature)) {
    // Assinatura válida, processe o evento com segurança!
    http_response_code(200);
} else {
    // Assinatura inválida!
    http_response_code(401);
}

Exemplo de Validação em Node.js (Express):

const crypto = require('crypto');
const express = require('express');
const app = express();

app.post('/webhooks/fiscal', express.raw({type: 'application/json'}), (req, res) => {
  const secret = 'seu_webhook_secret';
  const timestamp = req.headers['x-fiscal-timestamp'];
  const signature = req.headers['x-fiscal-signature'];
  const body = req.body;

  const expectedSignature = crypto
    .createHmac('sha256', secret)
    .update(timestamp + '.')
    .update(body)
    .digest('hex');

  const validLength = typeof signature === 'string' && signature.length === expectedSignature.length;
  const valid = validLength && crypto.timingSafeEqual(
    Buffer.from(expectedSignature, 'hex'),
    Buffer.from(signature, 'hex')
  );

  if (!valid) return res.sendStatus(401);
  res.sendStatus(200);
});

Resiliência, Workers Isolados & Circuit Breaker

O pipeline de entrega de webhooks da Fiscal Contora foi projetado para operar em alta escala sem criar gargalos operacionais ou dependências cruzadas com o faturamento.

⚡ Workers e Filas 100% Isolados A entrega de webhooks roda na fila exclusiva fiscal-webhooks, com workers dedicados e separados da fila de emissão fiscal-documents. Lentidões ou indisponibilidades no seu servidor receptor nunca afetam nem atrasam a autorização de notas fiscais na SEFAZ.
🛡️ Circuit Breaker (15 Falhas Consecutivas) Caso o endpoint receptor falhe por 15 tentativas consecutivas, o envio para esse endpoint é suspenso temporariamente por proteção de recursos. Um e-mail de alerta é enviado com o log dos últimos erros e instruções de restabelecimento.
🔄 Retentativas Inteligentes com Backoff Erros temporários (timeouts, HTTP 408, 429 e 5xx) são reenfileirados automaticamente por até 8 tentativas com intervalo exponencial e jitter para evitar picos de tráfego.
🟢 Reativação Simples e Rápida Após corrigir o servidor de integração, basta reativar o webhook com 1 clique no Console da conta ou enviando PATCH /webhooks/{id} com {"is_active": true}.

Endpoints disponíveis

GET /webhooks
Listar endpoints de webhook
POST /webhooks
Criar novo endpoint
GET /webhooks/{id}
Detalhes do endpoint
PATCH /webhooks/{id}
Atualizar endpoint
POST /webhooks/{id}/rotate-secret
Rotacionar secret
GET /webhooks/{id}/retry-info
Informações de retry
POST /webhooks/{id}/test
Enviar webhook de teste
GET /webhooks/{id}/tests
Listar testes enviados
GET /webhooks/{id}/deliveries
Listar entregas
POST /webhooks/{id}/deliveries/{delivery}/redeliver
Reenfileirar entrega falha

Uso recomendado

  • Responder rapidamente com HTTP 200 para evitar retries desnecessários.
  • Validar assinatura do payload com o segredo configurado.
  • Usar idempotência no ERP consumidor.
  • Rotacionar secret periodicamente ou quando houver suspeita de comprometimento.
  • Monitorar entregas falhas e reenfileirar quando necessário.
  • Considerar a estratégia de retry ao projetar o endpoint (timeout de 60s recomendado).