Skip to main content
Você está lendo o contrato atual (v1.1) de order.opened. v1.1 adiciona data.fiscalRepresentation: a numeração fiscal que o ponto de venda obteve antes de injetar o pedido. Viaja sempre: em null quando não se tentou numerar, e preenchido quando sim — numberingStatus diz como terminou. Trazer conteúdo não significa que o comprovante esteja autorizado. Apenas aditivo — nada do que você já lia mudou.O bloco carrega o documento fiscal vigente do pedido: os campos que significam o mesmo em qualquer país no topo, os identificadores do órgão dentro de countryData no vocabulário do seu país, e os documentos anteriores em history. Quando um cancelamento numera, a nota de crédito passa ao topo e a de venda desce para o histórico — com compensates apontando para ela.
order.opened dispara quando um pedido é injetado já aberto: ele existe no Fire, a cozinha pode começar, mas nenhum pagamento foi confirmado. Carrega o mesmo snapshot V4 que order.completed, então tudo o que você faz com um pedido completado também pode fazer aqui. Este é o evento que torna o pagamento diferido possível. Sem ele, um pedido não pago seria invisível para suas integrações até o dinheiro chegar.

Condição de disparo

O Fire emite order.opened uma vez, na injeção, quando:
  • order.status === "OPEN"
Essa é a única condição. Diferente de order.completed, não há guarda de pagamentopaymentStatus normalmente vem como "PENDING" e isso é o esperado.
order.opened não dispara para pedidos injetados como COMPLETED ou CANCELLED. Esses pedidos nunca “abrem”: pulam o ciclo de pagamento diferido por completo e produzem apenas order.completed. Emiti-lo para eles arriscaria despachar o mesmo pedido duas vezes para a cozinha.

A vida do pedido depois deste evento

order.opened é o primeiro de até três eventos do mesmo pedido. Conhecer a sequência importa, porque esse pedido vai chegar ao seu endpoint mais de uma vez:
Um pedido cancelado antes do pagamento produz order.cancelled em vez de order.completed.
Se o seu fluxo emite um documento fiscal em order.opened, o mesmo pedido vai passar de novo pelo seu nó fiscal em order.completed. Essa segunda passagem é esperada e inofensiva: o Fire detecta o documento existente e devolve um resultado idempotente de “já faturado” em vez de emitir outro. Veja Política de pagamento diferido abaixo.

O que vem em trigger.data

trigger.data é o snapshot V4 — exatamente a mesma estrutura que order.completed carrega, com duas diferenças que você deve esperar: Essa última linha é a que surpreende os integradores. Leia com atenção.

O meio declarado não é o meio cobrado

Em order.opened ninguém pagou, então payments.paymentMethods[] carrega o meio que o PDV anunciou ao criar o pedido — frequentemente o marketplace (IFOOD, RAPPI) ou um placeholder. transactionStatus vem como "PENDING" e transactionId geralmente vazio. Quando a cobrança entra, o Fire sobrescreve esse array com os tenders reais e emite order.completed. Mesmo pedido, mesmo campo, significado diferente:
order.opened — declarado
order.completed — realmente cobrado
Nunca trate payments.paymentMethods[] de order.opened como evidência de recebimento. É uma intenção, não um fato. Se você precisa saber o que foi realmente arrecadado, aguarde order.completed ou chame Get order, que expõe settlement.

Política de pagamento diferido

data.policy.deferredPayment é a razão de existir deste evento. Ele diz se o pedido pode ser trabalhado antes do pagamento: cozinhado, faturado, despachado. A política é resolvida uma única vez, na injeção, a partir da combinação canal × serviço × meio de pagamento declarado. Depois é carimbada de forma imutável no pedido, e todos os eventos seguintes a repetem sem recalcular. Dois eventos do mesmo pedido sempre carregam uma policy idêntica.
Por que imutável? Porque a decisão precisa ficar auditável. Se a configuração da loja mudar uma hora depois, um pedido já em voo deve continuar se comportando como foi instruído — e você precisa poder provar por quê. Mesmo padrão de store.storeFiscalConfig.
policy está presente em todos os eventos de pedido (order.opened, order.completed, order.invoiced, order.cancelled), não só neste. Um pedido com eligible: false também carrega o bloco — ele apenas diz que a resposta foi não.

Último estado conhecido

data.lastKnown é uma foto orientativa do que o Fire sabia sobre o estado de cozinha e fiscal do pedido no momento da emissão do evento.
lastKnown é uma dica, nunca uma fonte de verdade. Pode estar desatualizado, e em order.opened costuma vir null simplesmente porque nada aconteceu ainda. Não condicione uma ação irreversível a este campo — se você está prestes a emitir um documento fiscal, devoluções não são algo que você queira descobrir que precisava. Verifique o estado real, ou confie na idempotência do Fire.O próprio Fire segue essa regra: seu nó fiscal relê o estado do documento na fonte antes de emitir, e ignora lastKnown completamente.
Valores possíveis de fiscal.status: pending, processing, authorized, contingency, cancelling, cancelled, rejected, denied, error. O Fire ainda mantém dois estados internos para pedidos sem documento — esses são reportados aqui como null, para não vazar contabilidade interna dentro do seu contrato.

Todo o resto

Os blocos restantes — store, client, channel, orderLines, fulfillment, kds, device, operator, marketing, metadata, payments.totals — são idênticos a order.completed. Em vez de duplicá-los, veja a referência de campos de order.completed.

Erros comuns

Não é. Ninguém pagou. Contar order.opened em relatórios de faturamento infla os números e duplica quando order.completed chegar para o mesmo orderId.
Pedidos pré-pagos (quiosque, checkout web) são injetados já COMPLETED e nunca o emitem. Se sua integração depende de order.opened chegar primeiro, ela vai pular esses pedidos em silêncio. Assine os dois.
Veja acima. Em order.opened é o que o PDV declarou, não o que foi cobrado.
O mesmo orderId chega em order.opened e de novo em order.completed. É por design. Faça seu handler idempotente por (orderId, ação), não por orderId.

Próximo

data.fiscalRepresentation

A numeração fiscal que o ponto de venda obteve antes de injetar o pedido: cobra, pede os identificadores, imprime o comprovante e só então injeta. Por isso viaja no pedido e não em um evento fiscal separado — quando o pedido nasce, isso já aconteceu.
A presença deste bloco NÃO significa que o comprovante esteja autorizado. São os números impressos no caixa; o veredito do órgão está em lastKnown.fiscal.status. Um ticket que diga “autorizado” só porque o bloco está presente declara algo que pode não ter acontecido.
A chave viaja sempre. Chega em null quando não se tentou numerar — agregadores, países sem representação fiscal, ou comércios com a numeração desativada — e traz o bloco quando houve tentativa. Trazer o bloco significa que se tentou numerar, não que foi numerado: numberingStatus diz como a tentativa terminou, e failure por quê quando não terminou bem. Ramifique pelo valor, não pela presença da chave:
O veredicto do órgão não o altera. O que o cliente levou impresso não muda porque o órgão depois autorize ou rejeite — para isso existe lastKnown.fiscal, que é o que de fato se move. O que o substitui é um documento novo. O bloco carrega o documento fiscal vigente do pedido. Enquanto houve apenas um, era sempre a nota de venda; quando um cancelamento produz uma nota de crédito, é ela que fica no topo — documentType diz qual é — e a nota de venda desce para history, inteira e com seus próprios identificadores do órgão. Não se perde: se move. compensates aponta para ela pelo número, então a relação fica explícita.

Quando a numeração falha

Uma venda pode ser cobrada e ficar sem comprovante fiscal. Esse caso também viaja, e precisa ser tratado: os identificadores vêm null e o motivo em failure.
Ramifique por failure.scope:
  • TECHNICAL — imprima “em trâmite” e siga. Pode se resolver sozinho.
  • FUNCTIONAL — há um dado errado e repetir não resolve. Precisa correção. O que muda é lastKnown.fiscal.
lastKnown.fiscal.sourceEvent agora informa a procedência real. Antes era deduzida do status, e um processing semeado na injeção era reportado como fiscal.callback sem que nenhum callback tivesse ocorrido. Esse caso agora diz order.injected. Se você ramifica por este campo, contemple o valor novo.