Skip to main content
O que o provedor devolve não fica na resposta síncrona. Ele é anexado ao pedido e trafega em todos os seus eventos, então cada campo da resposta tem um consumidor final que não é o FIRE. Esta página existe para fechar esse círculo: se você está implementando o endpoint, aqui vê o que acontece com o que você devolve.

O percurso

O ponto de venda numera antes de o pedido existir: cobra, pede os números, imprime, e só depois injeta a venda. Ao injetar, o FIRE busca a numeração desse orderCode e a cola no pedido. Dali em diante ela trafega em data.fiscalRepresentation de order.opened, order.completed, order.invoiced, order.cancelled e order.reversed.
Os valores do evento não estão na mesma escala dos da requisição de numeração.E não é um detalhe marginal: o evento é de onde sai a venda que você emite. A numeração lhe dá os identificadores; os valores, as linhas e o comprador que você declara ao órgão são tirados daqui. Por isso este é o lugar onde a escala pode morder.Tudo o que é monetário em data.payments trafega como inteiro em string, multiplicado por 10.000 — é a escala com que o FIRE armazena, para fazer aritmética com inteiros e não arrastar erro de ponto flutuante ao somar impostos.Um exemplo com a Colômbia — cada país trafega na sua moeda, mas a escala é a mesma:Divida por 10.000 todo valor que tirar do evento antes de declará-lo ao órgão. Para o hash do CUFE use os da requisição de numeração, que são os mesmos valores e já vêm sem escalar.Não é uma inconsistência do dado —é o mesmo valor em duas convenções— mas descobrir tarde custa caro: se você não dividir, declara 500.000.000 COP por uma venda de 50.000 COP —dez mil vezes o montante—, o documento fica bem formado e o órgão o aceita.

Campo a campo

Equador, que é o bloco document de /fiscal/ec/prekeys: Um exemplo completo, com dados reais:
O bloco acima sempre tem as mesmas chaves, com null naquelas que não se aplicam — é contra isso que você programa. O que muda por país vive dentro de countryData, e ali trafegam apenas as chaves do país que numerou: um comprovante equatoriano não leva cufe, nem um colombiano claveAcceso.

Os quatro casos, completos

Estes são todos os estados que o bloco pode ter, e qual resposta sua os produz. O bloco acima sempre traz as mesmas 12 chaves: o que muda são os valores e o conteúdo de countryData.
Você devolveu 2xx com document.
O integrador imprime e concilia. countryData traz o vocabulário do SRI e nada de outros países.
Você devolveu não-2xx com retryable: false.
É uma venda cobrada sem comprovante fiscal. O integrador compensa do seu lado e devolve o comprovante pelo callback. Retentar não resolve: é preciso corrigir o dado.
Você devolveu não-2xx com retryable: true.
Mesmo bloco que o anterior; muda o numberingStatus e o scope. Não há comprovante, mas pode vir a haver: o canal retenta com o mesmo orderCode.
Houve timeout ou a conexão caiu. Você nunca produz este estado: dizê-lo implicaria ter respondido.
É o estado mais delicado, e o que mais fácil se interpreta mal. Ele não significa “não há comprovante”: significa não sabemos. Você pode ter numerado, consumido um sequencial e emitido o documento, e a resposta ter se perdido na volta.Um integrador que o leia como “não há comprovante” e compense emitindo outro declara a mesma venda duas vezes perante o órgão. Com FAILED_RETRYABLE essa compensação é correta; com PENDING é um erro caro.Por isso a sua deduplicação tem que ser por orderCode: a retentativa chega com o mesmo orderCode e você devolve o mesmo documento com reused: true, em vez de numerar outro. Não espere um header de idempotência — não mandamos nenhum para você.

E o caso sem numeração

Quando a venda não passou por nenhum provedor — o comércio não fatura, ou o país não tem gateway fiscal — o bloco inteiro trafega em null:
A chave nunca é omitida. O integrador ramifica por valor:
documentType hoje é sempre SALE_INVOICE nos eventos do pedido. CREDIT_NOTE existe no contrato — é produzido por operation: "CANCEL" — mas a numeração do cancelamento ainda não é anexada ao pedido. Quando for habilitada, é o mesmo bloco com documentType: "CREDIT_NOTE".

Três campos que convém entender bem

provider e metadata — dois blocos, dois destinos

Eles se parecem e não são a mesma coisa, então trafegam separados: Nenhum dos dois leva providerCode: esse é o nosso identificador de adaptador e já trafega à parte, acima do bloco.
provider.reference é a única razão pela qual este bloco tem forma. Quando algo dá errado, é o que o integrador cita para você encontrar a operação nos seus registros. Enterrado em uma bolsa opaca — onde, por contrato, ninguém deve programar — ele não cumpria essa função.
O que você colocar em metadata chega ao integrador sem ser tocado, em providerMetadata. Não o interpretamos, não o validamos, não o renomeamos. Isso tem duas faces:
É o único campo da resposta que não controlamos. Se você colocar ali algo sensível — uma credencial, um identificador interno da sua infraestrutura, um dado de outro cliente — está publicando isso para o integrador do ponto de venda.
E do outro lado: ninguém deve programar contra as suas chaves. Ele é declarado opaco justamente para que você possa mudá-lo sem quebrar ninguém. Se um dado é importante o bastante para que o integrador ramifique por ele, ele não vai em metadata — vai no contrato.
Não repita ali dentro o que já tem o seu lugar. Mandar failure dentro de metadata, ou o name do bloco ao lado, guarda o mesmo fato duas vezes — e duas cópias se dessincronizam. E não mude a bolsa entre uma emissão e a sua retentativa idempotente: quem ler o evento vai ver que “mudou” algo que não mudou.

graphic — é a única coisa que não pode ser derivada

Todo o resto da resposta pode ser reconstruído ou composto. graphic não: o QR da NFC-e brasileira é uma URL assinada com um hash que só o emitente pode construir. Se ele não chegar, o comprovante é impresso sem QR. Ele trafega tal como veio, sem transformação: o FIRE o repassa ao ponto de venda, que o renderiza com a sua própria biblioteca. Não geramos imagens deste lado — o tamanho e a resolução dependem da impressora, e isso só quem imprime sabe.

failure — habilita a compensação na outra ponta

Quando a numeração falha, o erro não fica em um log: ele trafega no evento. A venda foi cobrada do mesmo jeito e o integrador precisa saber que ela ficou sem comprovante fiscal. Com isso ele pode compensar do seu lado e devolver o comprovante pelo callback. Sem isso, uma venda cobrada sem comprovante é indistinguível de uma conta que não fatura. Por isso failure.code tem que ser estável e failure.message acionável: quem os lê não é só a nossa equipe de suporte, é o sistema do cliente final.

O que NÃO trafega para os eventos

E o veredito do órgão, à parte

fiscalRepresentation são os números que foram impressos, e eles nunca mudam. O fato de existirem não significa que o órgão autorizou o comprovante. O veredito chega depois pelo seu callback e trafega em outro lugar do evento:
São dois ciclos de vida distintos e o contrato os mantém separados de propósito: um é imutável e o outro é atualizado.