Cancel order (partners)
curl --request POST \
--url https://app.fire.rest/api/v1/adapters/xmart/stores/orders/{orderId}/cancel \
--header 'Authorization: <authorization>' \
--header 'Content-Type: application/json' \
--data '
{
"reason": "<string>",
"cancellationType": "<string>",
"cancellationNote": "<string>",
"cancellationGroup": "<string>"
}
'import requests
url = "https://app.fire.rest/api/v1/adapters/xmart/stores/orders/{orderId}/cancel"
payload = {
"reason": "<string>",
"cancellationType": "<string>",
"cancellationNote": "<string>",
"cancellationGroup": "<string>"
}
headers = {
"Authorization": "<authorization>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {Authorization: '<authorization>', 'Content-Type': 'application/json'},
body: JSON.stringify({
reason: '<string>',
cancellationType: '<string>',
cancellationNote: '<string>',
cancellationGroup: '<string>'
})
};
fetch('https://app.fire.rest/api/v1/adapters/xmart/stores/orders/{orderId}/cancel', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://app.fire.rest/api/v1/adapters/xmart/stores/orders/{orderId}/cancel",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'reason' => '<string>',
'cancellationType' => '<string>',
'cancellationNote' => '<string>',
'cancellationGroup' => '<string>'
]),
CURLOPT_HTTPHEADER => [
"Authorization: <authorization>",
"Content-Type: application/json"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://app.fire.rest/api/v1/adapters/xmart/stores/orders/{orderId}/cancel"
payload := strings.NewReader("{\n \"reason\": \"<string>\",\n \"cancellationType\": \"<string>\",\n \"cancellationNote\": \"<string>\",\n \"cancellationGroup\": \"<string>\"\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Authorization", "<authorization>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://app.fire.rest/api/v1/adapters/xmart/stores/orders/{orderId}/cancel")
.header("Authorization", "<authorization>")
.header("Content-Type", "application/json")
.body("{\n \"reason\": \"<string>\",\n \"cancellationType\": \"<string>\",\n \"cancellationNote\": \"<string>\",\n \"cancellationGroup\": \"<string>\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://app.fire.rest/api/v1/adapters/xmart/stores/orders/{orderId}/cancel")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Authorization"] = '<authorization>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"reason\": \"<string>\",\n \"cancellationType\": \"<string>\",\n \"cancellationNote\": \"<string>\",\n \"cancellationGroup\": \"<string>\"\n}"
response = http.request(request)
puts response.read_body{
"message": "<string>",
"data.reasonDetail": "<string>",
"data.resolvedFrom": {}
}Partner APIs
Cancel order (partners)
Cancels an injected order by its external id. Runs the cancellation policy.
POST
/
api
/
v1
/
adapters
/
xmart
/
stores
/
orders
/
{orderId}
/
cancel
Cancel order (partners)
curl --request POST \
--url https://app.fire.rest/api/v1/adapters/xmart/stores/orders/{orderId}/cancel \
--header 'Authorization: <authorization>' \
--header 'Content-Type: application/json' \
--data '
{
"reason": "<string>",
"cancellationType": "<string>",
"cancellationNote": "<string>",
"cancellationGroup": "<string>"
}
'import requests
url = "https://app.fire.rest/api/v1/adapters/xmart/stores/orders/{orderId}/cancel"
payload = {
"reason": "<string>",
"cancellationType": "<string>",
"cancellationNote": "<string>",
"cancellationGroup": "<string>"
}
headers = {
"Authorization": "<authorization>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {Authorization: '<authorization>', 'Content-Type': 'application/json'},
body: JSON.stringify({
reason: '<string>',
cancellationType: '<string>',
cancellationNote: '<string>',
cancellationGroup: '<string>'
})
};
fetch('https://app.fire.rest/api/v1/adapters/xmart/stores/orders/{orderId}/cancel', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://app.fire.rest/api/v1/adapters/xmart/stores/orders/{orderId}/cancel",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'reason' => '<string>',
'cancellationType' => '<string>',
'cancellationNote' => '<string>',
'cancellationGroup' => '<string>'
]),
CURLOPT_HTTPHEADER => [
"Authorization: <authorization>",
"Content-Type: application/json"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://app.fire.rest/api/v1/adapters/xmart/stores/orders/{orderId}/cancel"
payload := strings.NewReader("{\n \"reason\": \"<string>\",\n \"cancellationType\": \"<string>\",\n \"cancellationNote\": \"<string>\",\n \"cancellationGroup\": \"<string>\"\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Authorization", "<authorization>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://app.fire.rest/api/v1/adapters/xmart/stores/orders/{orderId}/cancel")
.header("Authorization", "<authorization>")
.header("Content-Type", "application/json")
.body("{\n \"reason\": \"<string>\",\n \"cancellationType\": \"<string>\",\n \"cancellationNote\": \"<string>\",\n \"cancellationGroup\": \"<string>\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://app.fire.rest/api/v1/adapters/xmart/stores/orders/{orderId}/cancel")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Authorization"] = '<authorization>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"reason\": \"<string>\",\n \"cancellationType\": \"<string>\",\n \"cancellationNote\": \"<string>\",\n \"cancellationGroup\": \"<string>\"\n}"
response = http.request(request)
puts response.read_body{
"message": "<string>",
"data.reasonDetail": "<string>",
"data.resolvedFrom": {}
}Cancels an order you injected, looking it up by the external id you gave it. Unlike the
backoffice endpoint, you do not need to store our internal UUID.
Fire works out which of the two cases applies on its own, from that account, country and
vendor’s configuration. You do not have to find out: if the credit note applies to you,
the
This endpoint runs the cancellation policy: Fire’s rules plus whatever the account
configured. Before trying, you can ask Cancellation
eligibility, which returns the same verdict and
the same
code with a 200 and no side effects.The order of the steps depends on the fiscal gateway
This is the part integrations get wrong most often, and the only place where the order matters.- With gateway numbering
- Without gateway numbering
Fire numbers the receipt, so the fiscal void comes first:It is the same pattern as issuing — the fiscal fact first, the order second — which makes
it easy to remember: you void the way you issue.If you invert the steps, this endpoint answers
1
Void the receipt
POST /api/v2/external/fiscal/numbering with operation: "CANCEL". It returns the
credit note. See Fiscal numbering v2.2
Cancel the order
Only now, this endpoint.
409 with
FISCAL_REPRESENTATION_NOT_VOIDED. It is not transient: retrying will not fix it.There is no prior void to request: cancel directly, with this endpoint and nothing
else.
409 tells you.
string
required
Bearer <api-key> with the orders:write scope, vendor-scoped.string
default:"es"
Language of the rejection reason: It only affects Fire’s own rules, which carry labels in all three languages. The text of a
rule configured by the account comes back exactly as the account wrote it, in whatever
language that is. Without this parameter, Spanish.
es, en or pt. It is the same parameter already used by
Cancellation eligibility and
Fiscal numbering.It goes in the URL:POST https://app.fire.rest/api/v1/adapters/xmart/stores/orders/ORD-123/cancel?locale=pt
string
required
The order’s external id — the same
orderId you sent when injecting it. Not our
internal UUID: you do not need to store it.string
required
The reason. Between 5 and 500 characters. With a catalog, the text of the chosen reason.
string
The reason id within the catalog. For aggregator channels it must come from the SAG
catalog.
string
Free-form note, up to 500 characters. Stored separately from the reason.
string
The group. You do not need to send it: the backend derives it.
What a rejection carries
Beyond thecode, a 409 body carries the reason ready to display:
string
The headline: the name of the rule that denied. This is what fits in a short notice.
string
The long why. Only present when the rule has one. It travels apart from
message so you can
show just the headline when there is no room for more.The number behind the rejection, when the rule compares one: the limit and the actual value.
Lets you say “17 minutes past” without parsing the text.
object
What it decided with. A receipt for diagnosing, not for showing to a person.
Rejection codes
All of them come back as409. Branch on code, never on the message: the text is for a
person to read and may change or be translated without notice.
code | What happened | What to do |
|---|---|---|
CANCELLATION_IN_PROGRESS | A cancellation is already in flight. | Wait; do not retry in a loop. |
FISCAL_ALREADY_CANCELLED | The fiscal document is already voided. | Nothing: the desired effect already happened. |
ORDER_NOT_CANCELLABLE | The order is already closed or cancelled. | Nothing: it is a terminal state. |
FISCAL_REPRESENTATION_NOT_VOIDED | There is an invoice and no credit note yet. | Request the fiscal void first, wait for the response, and only then cancel. |
BUSINESS_DAY_CLOSED | The order belongs to a closed business day, or to one before the active day. | Not cancellable over the API: an accounting adjustment applies. |
CANCELLATION_POLICY_DENIED | A rule configured by the account denied it. | Read message: the customer wrote it. |
A
200 means the order was cancelled. It does not mean the fiscal document is
already voided: with a gateway you did that in the previous step, and with native issuing it
settles later, through the provider’s callback.
