GET https://app.fire.rest/api/v1/external/orders/EXT-100234/cancellation-eligibility?locale=pt
x-api-key: <sua_api_key>
{
"success": true,
"data": {
"canCancel": true,
"outcome": "ALLOW",
"outcomeLabel": "Permitir cancelar",
"code": null,
"reason": null,
"reasonDetail": null,
"source": "default",
"threshold": null,
"resolvedFrom": {
"orderStatus": "COMPLETED",
"paymentStatus": "SUCCEEDED",
"countryCode": "BR",
"fiscalStatus": "authorized",
"isFinalConsumer": "true",
"minutesSinceCreation": "12.4",
"minutesSinceAuthorization": "11.9"
}
}
}
{
"success": true,
"data": {
"canCancel": false,
"outcome": "DENY",
"outcomeLabel": "Não permitir",
"code": "ORDER_NOT_CANCELLABLE",
"reason": "O pedido já não está num estado cancelável",
"reasonDetail": null,
"source": "baseline",
"threshold": null,
"resolvedFrom": {
"orderStatus": "CANCELLED",
"paymentStatus": "SUCCEEDED",
"countryCode": "BR",
"fiscalStatus": "cancelled",
"minutesSinceCreation": "94.2"
}
}
}
{
"success": true,
"data": {
"canCancel": false,
"outcome": "DENY",
"outcomeLabel": "Não permitir",
"code": "CANCELLATION_POLICY_DENIED",
"reason": "Prazo de anulação da SEFAZ vencido",
"reasonDetail": "A NFC-e autorizada só pode ser anulada em até 30 minutos. Depois disso é preciso abrir um chamado fiscal.",
"source": "account",
"threshold": {
"field": "minutesSinceAuthorization",
"threshold": 30,
"actual": 47.3
},
"resolvedFrom": {
"orderStatus": "COMPLETED",
"paymentStatus": "SUCCEEDED",
"countryCode": "BR",
"fiscalStatus": "authorized",
"isFinalConsumer": "false",
"govIdType": "CPF",
"minutesSinceCreation": "52.1",
"minutesSinceAuthorization": "47.3"
}
}
}
{
"success": false,
"error": "FORBIDDEN",
"message": "Vendor-scoped API key required (accountId binding missing)"
}
{
"success": false,
"error": "NOT_FOUND",
"message": "InjectedOrder not found: EXT-100234"
}
{
"success": false,
"error": "CONFLICT",
"code": "AMBIGUOUS_ORDER_REFERENCE",
"message": "External order id EXT-100234 matches 2 orders across vendors; cannot disambiguate"
}
APIs de parceiro
Elegibilidade de cancelamento
Pergunta se um pedido pode ser cancelado — sem cancelá-lo. O preflight do botão de cancelar.
GET
/
api
/
v1
/
external
/
orders
/
{orderId}
/
cancellation-eligibility
GET https://app.fire.rest/api/v1/external/orders/EXT-100234/cancellation-eligibility?locale=pt
x-api-key: <sua_api_key>
{
"success": true,
"data": {
"canCancel": true,
"outcome": "ALLOW",
"outcomeLabel": "Permitir cancelar",
"code": null,
"reason": null,
"reasonDetail": null,
"source": "default",
"threshold": null,
"resolvedFrom": {
"orderStatus": "COMPLETED",
"paymentStatus": "SUCCEEDED",
"countryCode": "BR",
"fiscalStatus": "authorized",
"isFinalConsumer": "true",
"minutesSinceCreation": "12.4",
"minutesSinceAuthorization": "11.9"
}
}
}
{
"success": true,
"data": {
"canCancel": false,
"outcome": "DENY",
"outcomeLabel": "Não permitir",
"code": "ORDER_NOT_CANCELLABLE",
"reason": "O pedido já não está num estado cancelável",
"reasonDetail": null,
"source": "baseline",
"threshold": null,
"resolvedFrom": {
"orderStatus": "CANCELLED",
"paymentStatus": "SUCCEEDED",
"countryCode": "BR",
"fiscalStatus": "cancelled",
"minutesSinceCreation": "94.2"
}
}
}
{
"success": true,
"data": {
"canCancel": false,
"outcome": "DENY",
"outcomeLabel": "Não permitir",
"code": "CANCELLATION_POLICY_DENIED",
"reason": "Prazo de anulação da SEFAZ vencido",
"reasonDetail": "A NFC-e autorizada só pode ser anulada em até 30 minutos. Depois disso é preciso abrir um chamado fiscal.",
"source": "account",
"threshold": {
"field": "minutesSinceAuthorization",
"threshold": 30,
"actual": 47.3
},
"resolvedFrom": {
"orderStatus": "COMPLETED",
"paymentStatus": "SUCCEEDED",
"countryCode": "BR",
"fiscalStatus": "authorized",
"isFinalConsumer": "false",
"govIdType": "CPF",
"minutesSinceCreation": "52.1",
"minutesSinceAuthorization": "47.3"
}
}
}
{
"success": false,
"error": "FORBIDDEN",
"message": "Vendor-scoped API key required (accountId binding missing)"
}
{
"success": false,
"error": "NOT_FOUND",
"message": "InjectedOrder not found: EXT-100234"
}
{
"success": false,
"error": "CONFLICT",
"code": "AMBIGUOUS_ORDER_REFERENCE",
"message": "External order id EXT-100234 matches 2 orders across vendors; cannot disambiguate"
}
Responde se um pedido pode ser cancelado, sem cancelar nada. O ponto de venda consulta este endpoint para mostrar ou ocultar o botão de cancelar, e para explicar ao operador de caixa por que não é possível quando não é.
Executa o mesmo serviço de políticas que o cancelamento real, então o preflight e o resultado não podem divergir sobre as regras. O par natural deste endpoint é Cancelar pedido: este pergunta, aquele executa.
Um
Nem sempre foi assim. A nota de crédito e o dia de operação eram verificados soltos dentro do cancelamento real, este endpoint os pulava, e um campo
orderId aceita qualquer uma das quatro formas de nomear um pedido de fora: o id externo que o seu canal gerou ao injetá-lo, o order_id que viajou no payload de injeção, o order_code do Fire e o UUID interno do Fire. O Fire tenta todas dentro do vendor da sua key. Se o id corresponder a mais de um pedido nesse escopo, recusa com 409 em vez de adivinhar: responder sobre o pedido errado seria pior do que não responder.Um
200 não significa “sim”. O veredito viaja no corpo: este endpoint devolve 200 mesmo quando o pedido não pode ser cancelado, porque “não” é a resposta à pergunta, não um erro. Um status diferente de 200 é um erro de verdade — autenticação, pedido inexistente —, nunca uma recusa de política.Autenticação
string
obrigatório
Sua API key do Fire com o scope
orders:read. A key deve estar limitada a um vendor — keys sem vínculo com uma conta são rejeitadas com 403. O tenant é derivado da key, nunca da requisição.Parâmetros de rota
string
obrigatório
Identificador do pedido. Aceita o id externo, o
order_id do payload, o order_code do Fire ou o UUID interno do Fire.Parâmetros de consulta
string
padrão:"es"
es, en ou pt. Idioma de reason, reasonDetail e outcomeLabel. Afeta apenas as regras próprias do Fire, que trazem seu rótulo nos três idiomas; o texto de uma regra configurada pela conta é dela e volta exatamente como foi escrito, sem tradução.GET https://app.fire.rest/api/v1/external/orders/EXT-100234/cancellation-eligibility?locale=pt
x-api-key: <sua_api_key>
Resposta
O veredito chega no envelope padrão:{ "success": true, "data": { ... } }.
boolean
A resposta. É o mesmo veredito que o cancelamento real vai dar.
string
Resultado bruto da política:
ALLOW ou DENY. Hoje é redundante com canCancel de propósito: viaja desde o início para que, se um terceiro resultado aparecer um dia, adicioná-lo não quebre os consumidores existentes.string
Nome de exibição do resultado, no idioma pedido. É a rede de segurança quando
reason vem null: sem ele, uma recusa por uma regra sem nome chegaria ao operador sem uma única palavra para mostrar.string | null
O motivo, estável.
null quando o pedido pode ser cancelado. Este é o contrato — decida em código com code, nunca interpretando reason. Os códigos possíveis estão listados mais abaixo.string | null
O nome da regra que decidiu, para humanos. Cabe em uma linha na tela do POS. É texto editável e traduzível — não é contrato.
string | null
A nota longa dessa mesma regra, ou
null. Vem separada de reason para que o consumidor decida quanto espaço lhe dá: o POS pinta uma linha, uma tela de detalhe pode pintar as duas. Também é texto editável, não contrato. As regras próprias do Fire não levam nota, então uma recusa por uma regra do Fire traz sempre reasonDetail: null — é o esperado, não um bug. A nota só aparece em regras configuradas pela conta.string
De onde veio a decisão:
baseline (uma regra do Fire), account (uma regra configurada pela conta) ou default (nenhuma regra correspondeu — o pedido pode ser cancelado).object | null
Presente apenas quando a regra vencedora comparava contra um limite numérico.
Com isso você pode dizer ao operador “passou do limite em 17 minutos” sem aprender códigos novos.
Mostrar threshold
Mostrar threshold
object
O contexto avaliado, como um mapa de campo para valor. É o recibo forense: permite reconstruir por que aquilo foi decidido mesmo que a configuração mude depois.
Um true daqui é o mesmo true do POST /cancel
Nem sempre foi assim. A nota de crédito e o dia de operação eram verificados soltos dentro do cancelamento real, este endpoint os pulava, e um campo pending anunciava essas duas verificações omitidas. Esse campo não existe mais: as duas são regras da política, e os dois endpoints as executam.
Resta uma diferença, e é uma corrida legítima, não uma falha de desenho: entre perguntar e cancelar, o dia de operação pode fechar ou alguém pode disparar outro cancelamento. Perguntar não reserva nada.
Este endpoint responde por um pedido de propósito: resolvê-lo custa duas consultas, e sobre uma lista seria uma por linha.
Códigos de recusa
O cancelamento real devolve o mesmocode quando nega pelo mesmo motivo.
| Código | Origem | O que aconteceu |
|---|---|---|
CANCELLATION_IN_PROGRESS | regra do Fire | Já há um cancelamento em andamento. |
FISCAL_ALREADY_CANCELLED | regra do Fire | O documento fiscal já está anulado. |
ORDER_NOT_CANCELLABLE | regra do Fire | O pedido está FORCE_CLOSED ou CANCELLED. |
FISCAL_REPRESENTATION_NOT_VOIDED | regra do Fire | Há nota fiscal e ainda não há nota de crédito. Peça primeiro o cancelamento fiscal. |
BUSINESS_DAY_CLOSED | regra do Fire | O pedido é de um dia de operação já fechado, ou de um dia anterior ao ativo. |
CANCELLATION_POLICY_DENIED | regra da conta | Uma regra configurada pela conta negou. O motivo legível viaja em reason. |
{
"success": true,
"data": {
"canCancel": true,
"outcome": "ALLOW",
"outcomeLabel": "Permitir cancelar",
"code": null,
"reason": null,
"reasonDetail": null,
"source": "default",
"threshold": null,
"resolvedFrom": {
"orderStatus": "COMPLETED",
"paymentStatus": "SUCCEEDED",
"countryCode": "BR",
"fiscalStatus": "authorized",
"isFinalConsumer": "true",
"minutesSinceCreation": "12.4",
"minutesSinceAuthorization": "11.9"
}
}
}
{
"success": true,
"data": {
"canCancel": false,
"outcome": "DENY",
"outcomeLabel": "Não permitir",
"code": "ORDER_NOT_CANCELLABLE",
"reason": "O pedido já não está num estado cancelável",
"reasonDetail": null,
"source": "baseline",
"threshold": null,
"resolvedFrom": {
"orderStatus": "CANCELLED",
"paymentStatus": "SUCCEEDED",
"countryCode": "BR",
"fiscalStatus": "cancelled",
"minutesSinceCreation": "94.2"
}
}
}
{
"success": true,
"data": {
"canCancel": false,
"outcome": "DENY",
"outcomeLabel": "Não permitir",
"code": "CANCELLATION_POLICY_DENIED",
"reason": "Prazo de anulação da SEFAZ vencido",
"reasonDetail": "A NFC-e autorizada só pode ser anulada em até 30 minutos. Depois disso é preciso abrir um chamado fiscal.",
"source": "account",
"threshold": {
"field": "minutesSinceAuthorization",
"threshold": 30,
"actual": 47.3
},
"resolvedFrom": {
"orderStatus": "COMPLETED",
"paymentStatus": "SUCCEEDED",
"countryCode": "BR",
"fiscalStatus": "authorized",
"isFinalConsumer": "false",
"govIdType": "CPF",
"minutesSinceCreation": "52.1",
"minutesSinceAuthorization": "47.3"
}
}
}
{
"success": false,
"error": "FORBIDDEN",
"message": "Vendor-scoped API key required (accountId binding missing)"
}
{
"success": false,
"error": "NOT_FOUND",
"message": "InjectedOrder not found: EXT-100234"
}
{
"success": false,
"error": "CONFLICT",
"code": "AMBIGUOUS_ORDER_REFERENCE",
"message": "External order id EXT-100234 matches 2 orders across vendors; cannot disambiguate"
}
O que construir com cada campo
- Decida em código com
code.reasonereasonDetailsão texto editável e traduzível — nunca os interprete. - Mostre
reasonem uma linha;reasonDetailé o parágrafo, para telas com mais espaço. Sereasonviernullnuma recusa, useoutcomeLabelcomo reserva. - Use
thresholdpara montar mensagens de “passou em N” de forma genérica, sem conhecer nenhuma regra em particular. - Guarde
resolvedFromnos seus logs: é o recibo que explica o veredito mesmo depois que as regras da conta mudarem.
Relacionado
Cancelar pedido
A outra metade do par: este endpoint pergunta, aquele executa.
Obter pedido
Leia o pedido ao qual o veredito se refere.

