Saltar para o conteúdo principal
POST
/
api
/
v1
/
webhooks
/
fiscal
/
callback
Callback fiscal
curl --request POST \
  --url https://app.fire.rest/api/v1/webhooks/fiscal/callback \
  --header 'Content-Type: application/json' \
  --header 'x-api-key: <x-api-key>' \
  --data '
{
  "countryCode": "<string>",
  "eventType": "<string>",
  "providerEventId": "<string>",
  "occurredAt": "<string>",
  "orderId": "<string>",
  "eventId": "<string>",
  "document": {},
  "error": {
    "code": "<string>",
    "message": "<string>"
  },
  "providerSpecific": {}
}
'
{
  "received": true,
  "duplicate": false,
  "eventId": "1686fca1-0a26-4a89-b2f2-fe93b15a4434",
  "webhookEventId": "6d950243-6a0c-415c-b547-bddf9af8ad61",
  "status": "queued",
  "firstReceivedAt": "2026-06-11T15:00:34.729Z",
  "message": "Event accepted and queued for processing."
}
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 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íses null)
  • data.orderLines[].metadata.fiscal — classificação fiscal por linha (BR populado; outros null)
Para o Brasil especificamente, também é emitido um evento 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 scope webhooks:fiscal, vendor-scoped ao account dono do pedido. Keys sem scope ou apenas a nível account são rejeitadas com 403 Forbidden.
x-api-key
string
obrigatório
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.
Authorization
string
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 do document é discriminado por countryCode — veja Documento por país abaixo.
countryCode
string
obrigatório
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.
eventType
string
obrigatório
Estado do documento. Um de:
  • authorized — a autoridade fiscal aprovou o documento
  • cancelled — um documento previamente autorizado foi cancelado
  • rejected — 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
Quando eventType é authorized ou cancelled, o campo document é obrigatório. Quando é rejected, denied ou error, o campo error é obrigatório.
providerEventId
string
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.
occurredAt
string
obrigatório
Timestamp ISO 8601 UTC de quando o evento ocorreu na autoridade fiscal (não quando o provedor enviou o callback).
orderId
string
obrigatório
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.
eventId
string
obrigatório
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 eventId que não referencie um evento do Fire para esse pedido é rejeitado com 400 antes do 202.
  • Cada ação carrega seu próprio evento. Ecoe o event.id do evento que disparou esta ação — a emissão order.invoiced para um callback authorized, o evento de cancelamento/estorno para um callback cancelled. Reusar o eventId de uma ação para outro eventType (ex. um cancelled que ecoa o eventId do authorized) é rejeitado com 409 — um cancelamento deve referenciar seu próprio evento, não se pendurar no da autorização. Veja Idempotência e cenários.
document
object
O documento fiscal autorizado / cancelado. Obrigatório quando eventType é authorized ou cancelled. O formato varia por país — veja Documento por país.
error
object
Contexto de erro para resultados negativos. Obrigatório quando eventType é rejected, denied ou error.
providerSpecific
object
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 campo document 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 qualquer countryCode. 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.
CampoTipoObrigatórioNotas
docType"invoice" / "cancellation"Classe do documento — invoice para emissão, cancellation para cancelamento
docSubtypestringSubtipo conforme país/provedor (ex.: nfce, nfe, factura, boleta, factura_a)
pdfUrlstring (URL) | nullLink de download do PDF do documento (DANFE / representação gráfica)
xmlUrlstring (URL) | nullLink de download do XML canônico da autoridade fiscal
emittedAtstring (ISO 8601) | nullTimestamp UTC de quando a autoridade autorizou/emitiu o documento
cancelledAtstring (ISO 8601) | nullTimestamp UTC do cancelamento — relevante quando eventType é cancelled
totalAmountnumber | nullValor total bruto do documento
taxAmountnumber | nullValor total de impostos
currencyCodestring | nullCó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.
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 (docType, docSubtype, pdfUrl, xmlUrl, emittedAt, etc.), o BR exige estes identificadores específicos:
CampoTipoObrigatórioNotas
chaveAcessostringExatamente 44 dígitos — chave de acesso SEFAZ
protocolostringProtocolo de autorização SEFAZ
numeroint / stringNúmero do documento
serieint / string | nullSérie do documento (codificada na chave)
modelo55 / 65 | null55 = NF-e, 65 = NFC-e
cnpjEmitentestring | nullCNPJ do emissor
O exemplo abaixo inclui os campos base opcionais (pdfUrl, xmlUrl, emittedAt, totalAmount, taxAmount, currencyCode) — todos podem ser omitidos, mas envie-os se seu provedor os tiver:
{
  "countryCode": "BR",
  "eventType": "authorized",
  "providerEventId": "evt-br-1",
  "occurredAt": "2026-04-26T14:32:11.000Z",
  "orderId": "550e8400-e29b-41d4-a716-446655440000",
  "eventId": "7c9e6679-7425-40de-944b-e07fc1f90ae7",
  "document": {
    "docType": "invoice",
    "docSubtype": "nfce",
    "chaveAcesso": "35260229062609000177650500000000011000000010",
    "protocolo": "141210001176277",
    "numero": 1,
    "serie": 50,
    "modelo": 65,
    "cnpjEmitente": "29062609000177",
    "emittedAt": "2026-04-26T14:32:10.000Z",
    "totalAmount": 142.90,
    "taxAmount": 18.57,
    "currencyCode": "BRL",
    "pdfUrl": "https://api.fiscal-provider.example/nfce/69fa97fe427d1240856e1282/pdf",
    "xmlUrl": "https://api.fiscal-provider.example/nfce/69fa97fe427d1240856e1282/xml"
  }
}

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
{
  "countryCode": "CO",
  "eventType": "rejected",
  "providerEventId": "evt-co-2",
  "occurredAt": "2026-04-26T14:32:11.000Z",
  "orderId": "550e8400-e29b-41d4-a716-446655440000",
  "eventId": "7c9e6679-7425-40de-944b-e07fc1f90ae7",
  "document": null,
  "error": {
    "code": "DIAN_42",
    "message": "CUFE inválido"
  }
}

Resposta

Em caso de sucesso o endpoint retorna 202 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.
received
boolean
Sempre true quando a requisição foi aceita e enfileirada.
duplicate
boolean
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.
eventId
string
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.
webhookEventId
string
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
string
Status atual do registro na fila — queuedprocessingprocessed (e retry / failed / dead / ignored).
firstReceivedAt
string
Timestamp ISO 8601 UTC de quando o Fire recebeu pela primeira vez este evento. Estável entre retentativas — útil como âncora de rastreamento.
message
string
Resumo legível do que aconteceu.
{
  "received": true,
  "duplicate": false,
  "eventId": "1686fca1-0a26-4a89-b2f2-fe93b15a4434",
  "webhookEventId": "6d950243-6a0c-415c-b547-bddf9af8ad61",
  "status": "queued",
  "firstReceivedAt": "2026-06-11T15:00:34.729Z",
  "message": "Event accepted and queued for processing."
}

Verificar o resultado

Como o processamento é assíncrono, o 202 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:
GET https://app.fire.rest/api/v1/webhooks/events/{webhookEventId}
x-api-key: <sua key webhooks:fiscal>
status
string
Ciclo de vida na fila: queuedprocessingprocessed (pronto) · failed / dead (esgotou as retentativas) · retry (aguardando a próxima tentativa) · ignored.
attempts
number
Tentativas de processamento até agora.
result
object | null
Em sucesso, o resultado do worker — ex. { "kind": "updated", "documentId": "…", "receiptId": "…" }.
error
object | null
{ "message": "…" } quando a última tentativa falhou; null caso contrário.
{
  "id": "9e6c8af8-af80-4967-9422-c096ab43c0e7",
  "source": "fiscal_generic",
  "eventType": "authorized",
  "status": "processed",
  "attempts": 1,
  "processedAt": "2026-04-26T14:32:13.000Z",
  "result": { "kind": "updated", "documentId": "1a2b3c4d-…", "receiptId": "9b2a3c4d-…" },
  "error": null
}
Um 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árioResultado
(orderId, eventId) novo202 · 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 orderId400eventId incorreto/inventado
Pedido/evento fora da conta + vendor da sua API key403
Payload malformado (Zod), campos obrigatórios faltando400
API key faltando / inválida401
Auth store momentaneamente inacessível503 — transitório, retente
Um cancelamento precisa do seu próprio evento. Você não pode cancelar um documento reenviando o eventId da autorização com eventType: "cancelled" — isso retorna 409. O Fire é a fonte da verdade: um cancelamento deve referenciar o evento de cancelamento/estorno que o Fire emitiu (um eventId distinto). Retornar um 202 duplicado aqui diria erroneamente que o cancelamento foi aceito enquanto o Fire nunca cancelou — por isso o Fire o rejeita explicitamente.
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 em fiscal_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

O 202 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:
  1. A linha fiscal_documents é upsertada com o novo status e referências do documento (chaveAcesso, protocolo, cufe, cae, etc., conforme o país).
  2. A coluna orders.fiscal JSONB é mergeada com os mesmos dados — visível no próximo evento order.completed / order.cancelled para o mesmo orderId, independente do país.
  3. Um trigger outbound é despachado — para o Brasil, triggerType = 'order.invoiced' (para eventType=authorized) ou 'order.reversed' (para eventType=cancelled). Os Integration Flows ativos para esse trigger rodam e fazem POST para o seu endpoint.
  • Hoje, apenas order.invoiced e order.reversed estã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.cancelled para 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.