Callback fiscal
API
Callback fiscal
Endpoint inbound para o qual seu provedor fiscal faz POST quando um documento fiscal muda de estado. Multipaís (BR, CO, EC, CL, AR, VE). Atualiza o estado fiscal do pedido dentro do Fire e — para o Brasil — dispara os eventos de pedido downstream.
POST
Callback fiscal
Este endpoint é inbound — seu provedor fiscal faz POST nele sempre que um documento fiscal é autorizado, rejeitado, denegado, cancelado ou falha. É a API canônica multi-país de fiscal callback que aceita payloads de BR, CO, EC, CL, AR, VE. O Fire valida o payload, atualiza o estado fiscal do pedido em
Como complementa
Resultados negativos (
Para estados não autorizados, omita
Um
fiscal_documents e orders.fiscal, e — para o Brasil — despacha eventos outbound order.invoiced / order.reversed para seus Integration Flows.
Este endpoint é assíncrono. O Fire autentica, roda o guard de source-of-truth + tenancy, deduplica, pré-marca o pedido como
processing e enfileira o callback — depois retorna 202 Accepted com um webhookEventId (tipicamente em menos de 100 ms). A atualização de fiscal_documents / orders.fiscal acontece um instante depois em um worker em segundo plano (normalmente em ~2 segundos). Para ver o resultado do processamento, consulte GET /v1/webhooks/events/{webhookEventId}. Problemas corrigíveis pelo cliente (payload inválido, eventId errado, tenant errado, uma ação reusando o evento de outra) são rejeitados sincronamente com 4xx antes do 202.Como complementa order.completed e order.cancelled
order.completed e order.cancelled carregam o estado de negócio de um pedido. O callback fiscal carrega o estado fiscal (autorização SEFAZ / DIAN / SRI / SII / AFIP / SENIAT). Juntos formam este lifecycle:
Após processar o callback, o próximo order.completed ou order.cancelled para o mesmo orderId reflete o estado fiscal atualizado em:
data.store.storeFiscalConfig— contexto do emissor (CNPJ / NIT / RUC / RUT / CUIT / RIF…)data.payments.metadata.fiscal— agregados fiscais totais (BR populado; outros paísesnull)data.orderLines[].metadata.fiscal— classificação fiscal por linha (BR populado; outrosnull)
order.invoiced (ou order.reversed) separado com as referências do documento SEFAZ em data.fiscal.
Hoje, apenas
order.invoiced e order.reversed estão cabeados como eventos outbound (Brasil). O endpoint valida e armazena callbacks para os 6 países (CO, EC, CL, AR, VE, BR), e o estado fiscal atualizado aparece no próximo evento order.completed / order.cancelled independentemente do país. Os eventos outbound para CO/EC/CL/AR/VE estão a caminho.Autenticação
Este endpoint requer uma API key com scopewebhooks:fiscal, vendor-scoped ao account dono do pedido. Keys sem scope ou apenas a nível account são rejeitadas com 403 Forbidden.
Sua API key do Fire. Gere uma no dashboard em Settings → API Keys → Developer keys, com scope
webhooks:fiscal e um binding de vendor para o account cujos pedidos esta key pode atualizar.Opcional
Bearer <token>. Não exigido para este endpoint hoje, mas reservado para futuros tokens emitidos pelo provedor.Corpo da requisição
O body é um objeto JSON com estes campos top-level. O formato dodocument é discriminado por countryCode — veja Documento por país abaixo.
Código de país ISO 3166-1 alpha-2. Um de
BR, CO, EC, CL, AR, VE. Determina as regras de validação do objeto document.Estado do documento. Um de:
authorized— a autoridade fiscal aprovou o documentocancelled— um documento previamente autorizado foi canceladorejected— o documento foi rejeitado (validação, schema, assinatura)denied— a autoridade negou a solicitação (tipicamente falha permanente de regra de negócio)error— ocorreu um erro não recuperável no provedor ou autoridade
eventType é authorized ou cancelled, o campo document é obrigatório. Quando é rejected, denied ou error, o campo error é obrigatório.O id próprio do seu provedor para esta entrega. Armazenado para auditoria/forense — não é a chave de idempotência. O Fire deduplica por
(orderId, eventId), então você pode enviar um providerEventId novo a cada retentativa sem criar duplicatas. Use o ID nativo do evento do provedor se disponível; caso contrário, um UUID.Timestamp ISO 8601 UTC de quando o evento ocorreu na autoridade fiscal (não quando o provedor enviou o callback).
UUID do pedido no Fire. Coincide com
data.orderId nos eventos order.completed e order.cancelled. O Fire o usa para encontrar o documento fiscal existente.UUID de correlação e chave de idempotência (junto com
orderId). Deve ser o event.id de um envelope V4 que o Fire emitiu para este pedido — ecoe-o exato; nunca o invente.- Verificação de fonte da verdade. Um
eventIdque não referencie um evento do Fire para esse pedido é rejeitado com400antes do202. - Cada ação carrega seu próprio evento. Ecoe o
event.iddo evento que disparou esta ação — a emissãoorder.invoicedpara um callbackauthorized, o evento de cancelamento/estorno para um callbackcancelled. Reusar oeventIdde uma ação para outroeventType(ex. umcancelledque ecoa oeventIddoauthorized) é rejeitado com409— um cancelamento deve referenciar seu próprio evento, não se pendurar no da autorização. Veja Idempotência e cenários.
O documento fiscal autorizado / cancelado. Obrigatório quando
eventType é authorized ou cancelled. O formato varia por país — veja Documento por país.Contexto de erro para resultados negativos. Obrigatório quando
eventType é rejected, denied ou error.Bag free-form para extras específicos do provedor (resposta raw, IDs internos, etc.). Não validado; passa para o log de auditoria.
Documento por país
O formato exigido do campodocument depende do countryCode. Todas as variantes compartilham os campos base abaixo (comuns aos 6 países) mais os identificadores específicos do país exigidos por aquela autoridade.
Campos base comuns
Aplicam-se a qualquercountryCode. docType e docSubtype são obrigatórios; o restante é opcional — envie-os sempre que seu provedor fiscal os tiver disponíveis. O Fire os persiste em fiscal_documents / orders.fiscal e os reemite nos eventos outbound order.invoiced / order.reversed (Brasil) e no próximo order.completed / order.cancelled.
| Campo | Tipo | Obrigatório | Notas |
|---|---|---|---|
docType | "invoice" / "cancellation" | ✓ | Classe do documento — invoice para emissão, cancellation para cancelamento |
docSubtype | string | ✓ | Subtipo conforme país/provedor (ex.: nfce, nfe, factura, boleta, factura_a) |
pdfUrl | string (URL) | null | Link de download do PDF do documento (DANFE / representação gráfica) | |
xmlUrl | string (URL) | null | Link de download do XML canônico da autoridade fiscal | |
emittedAt | string (ISO 8601) | null | Timestamp UTC de quando a autoridade autorizou/emitiu o documento | |
cancelledAt | string (ISO 8601) | null | Timestamp UTC do cancelamento — relevante quando eventType é cancelled | |
totalAmount | number | null | Valor total bruto do documento | |
taxAmount | number | null | Valor total de impostos | |
currencyCode | string | null | Código de moeda ISO 4217 — exatamente 3 letras (ex.: BRL, COP, USD) |
pdfUrl e xmlUrl são armazenados exatamente como você os envia — o Fire não baixa nem re-hospeda o arquivo. Se seu provedor assina essas URLs com expiração, considere que o link armazenado pode caducar; baixe e persista o artefato do seu lado se precisar de acesso durável.- Brasil (BR)
- Colombia (CO)
- Equador (EC)
- Chile (CL)
- Argentina (AR)
- Venezuela (VE)
Documentos fiscais brasileiros (NF-e / NFC-e). Use este código de país ao enviar callbacks do seu provedor fiscal ou de qualquer outro provedor BR.Além dos campos base comuns (
O exemplo abaixo inclui os campos base opcionais (
docType, docSubtype, pdfUrl, xmlUrl, emittedAt, etc.), o BR exige estes identificadores específicos:| Campo | Tipo | Obrigatório | Notas |
|---|---|---|---|
chaveAcesso | string | ✓ | Exatamente 44 dígitos — chave de acesso SEFAZ |
protocolo | string | ✓ | Protocolo de autorização SEFAZ |
numero | int / string | ✓ | Número do documento |
serie | int / string | null | Série do documento (codificada na chave) | |
modelo | 55 / 65 | null | 55 = NF-e, 65 = NFC-e | |
cnpjEmitente | string | null | CNPJ do emissor |
pdfUrl, xmlUrl, emittedAt, totalAmount, taxAmount, currencyCode) — todos podem ser omitidos, mas envie-os se seu provedor os tiver:Resultados negativos (rejected, denied, error)
Para estados não autorizados, omita document e forneça error. O countryCode ainda se aplica (valida o roteamento); o documento não é exigido porque não há artefato autorizado.
Rejeitado
Resposta
Em caso de sucesso o endpoint retorna202 Accepted — o evento foi autenticado, validado, deduplicado e enfileirado. Um 202 não significa que o documento fiscal já foi atualizado; isso acontece de forma assíncrona em um worker em segundo plano. Use o endpoint de status para confirmar o resultado final.
O body traz dois ids distintos para não haver ambiguidade: eventId é o id que você enviou (devolvido como echo), webhookEventId é o id do Fire para o registro enfileirado.
Sempre
true quando a requisição foi aceita e enfileirada.true quando este (orderId, eventId) já foi ingerido com o mesmo eventType — o registro existente é retornado e nada é re-enfileirado. false para um evento novo.Echo do
eventId que você enviou (o event.id da emissão do Fire). Use-o para correlacionar este acuse com a sua requisição.O id do Fire para o registro enfileirado em
webhook_events. Passe para GET /v1/webhooks/events/{webhookEventId} para consultar o resultado do processamento. Em uma duplicata é o mesmo id retornado na primeira vez.Status atual do registro na fila —
queued → processing → processed (e retry / failed / dead / ignored).Timestamp ISO 8601 UTC de quando o Fire recebeu pela primeira vez este evento. Estável entre retentativas — útil como âncora de rastreamento.
Resumo legível do que aconteceu.
Verificar o resultado
Como o processamento é assíncrono, o202 só confirma que o evento foi enfileirado. Para ver se o documento fiscal foi atualizado, consulte o endpoint de status com o webhookEventId retornado pelo 202:
Ciclo de vida na fila:
queued → processing → processed (pronto) · failed / dead (esgotou as retentativas) · retry (aguardando a próxima tentativa) · ignored.Tentativas de processamento até agora.
Em sucesso, o resultado do worker — ex.
{ "kind": "updated", "documentId": "…", "receiptId": "…" }.{ "message": "…" } quando a última tentativa falhou; null caso contrário.404 é retornado para ids desconhecidos — ou ids de outro tenant — sem vazar existência. Autentique com a mesma key webhooks:fiscal que usou no callback.
Idempotência e cenários
O Fire deduplica callbacks por(orderId, eventId) — não por providerEventId (que você pode regenerar livremente). Um evento é único com o seu pedido: o mesmo (orderId, eventId) reenviado com o mesmo eventType é um replay benigno; o mesmo (orderId, eventId) com um eventType diferente é uma tentativa de pendurar uma ação no evento de outra, e o Fire rejeita.
Esta é a matriz completa de comportamento — cada combinação que você pode enviar:
| Cenário | Resultado |
|---|---|
(orderId, eventId) novo | 202 · duplicate: false — enfileirado |
Mesmo (orderId, eventId, eventType) reenviado (qualquer providerEventId) | 202 · duplicate: true — registro existente retornado, não re-enfileirado |
Mesmo (orderId, eventId) mas eventType diferente (ex. cancelled com o eventId do authorized) | 409 — rejeitado. Use o evento que pertence a esta ação |
eventId não emitido pelo Fire para esse orderId | 400 — eventId incorreto/inventado |
| Pedido/evento fora da conta + vendor da sua API key | 403 |
| Payload malformado (Zod), campos obrigatórios faltando | 400 |
| API key faltando / inválida | 401 |
| Auth store momentaneamente inacessível | 503 — transitório, retente |
409 vs 202. Um 409 é o único caso em que um callback bem formado e autenticado é recusado na camada de idempotência — porque aceitá-lo divergiria o estado. Um replay do mesmo tipo nunca é um erro: retorna 202 para que suas retentativas fiquem limpas. Um 503 é nosso (infra transitória), então é seguro e esperado retentar.Concorrência
As transições de estado emfiscal_documents usam locking otimista. Se dois callbacks para o mesmo documento chegarem simultaneamente, um tem sucesso e o outro resolve para idempotent ou regression conforme a ordem. O merge de orders.fiscal JSONB é atômico.
O que acontece após o 202
O202 apenas enfileira o evento. Um worker em segundo plano então o pega — em ~2 segundos via o wake-up instantâneo, ou no próximo ciclo de polling como fallback — e:
- A linha
fiscal_documentsé upsertada com o novo status e referências do documento (chaveAcesso,protocolo,cufe,cae, etc., conforme o país). - A coluna
orders.fiscalJSONB é mergeada com os mesmos dados — visível no próximo eventoorder.completed/order.cancelledpara o mesmoorderId, independente do país. - Um trigger outbound é despachado — para o Brasil,
triggerType = 'order.invoiced'(paraeventType=authorized) ou'order.reversed'(paraeventType=cancelled). Os Integration Flows ativos para esse trigger rodam e fazem POST para o seu endpoint.
- Hoje, apenas
order.invoicedeorder.reversedestão cabeados. Disparam quando um callback authorized/cancelled para uma loja BR é processado. - Para CO/EC/CL/AR/VE, os eventos outbound equivalentes ainda não estão cabeados — os callbacks são validados e armazenados, e o estado fiscal se reflete no próximo
order.completed/order.cancelledpara o mesmo pedido.
Relacionado
order.completed
Veja onde o estado fiscal aterrissa dentro do snapshot V4 do pedido.
order.invoiced
Evento outbound BR-only disparado por este callback.
Injetar pedido
O endpoint de injeção que cria o pedido que este callback atualiza.
Autenticação
Como funcionam API keys, scopes e vendor binding.

