curl --request POST \
--url https://api.openfiskal.com/v1/operations/{operationId}/complete \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--header 'Idempotency-Key: <idempotency-key>' \
--header 'If-Match: <if-match>' \
--header 'X-OpenFiskal-Merchant: <x-openfiskal-merchant>' \
--data '
{
"payments": [
{
"payment_id": "pay_1001_card",
"method": "card",
"amount": "47.50",
"currency": "EUR",
"status": "captured",
"processor": "sumup",
"card_brand": "visa",
"processor_reference": "ch_123",
"processed_at": "2026-02-26T12:05:00.000Z",
"gift_card_id": "gc_abc123"
}
],
"completed_at": "2026-02-26T12:05:00.000Z"
}
'import requests
url = "https://api.openfiskal.com/v1/operations/{operationId}/complete"
payload = {
"payments": [
{
"payment_id": "pay_1001_card",
"method": "card",
"amount": "47.50",
"currency": "EUR",
"status": "captured",
"processor": "sumup",
"card_brand": "visa",
"processor_reference": "ch_123",
"processed_at": "2026-02-26T12:05:00.000Z",
"gift_card_id": "gc_abc123"
}
],
"completed_at": "2026-02-26T12:05:00.000Z"
}
headers = {
"X-OpenFiskal-Merchant": "<x-openfiskal-merchant>",
"If-Match": "<if-match>",
"Idempotency-Key": "<idempotency-key>",
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {
'X-OpenFiskal-Merchant': '<x-openfiskal-merchant>',
'If-Match': '<if-match>',
'Idempotency-Key': '<idempotency-key>',
Authorization: 'Bearer <token>',
'Content-Type': 'application/json'
},
body: JSON.stringify({
payments: [
{
payment_id: 'pay_1001_card',
method: 'card',
amount: '47.50',
currency: 'EUR',
status: 'captured',
processor: 'sumup',
card_brand: 'visa',
processor_reference: 'ch_123',
processed_at: '2026-02-26T12:05:00.000Z',
gift_card_id: 'gc_abc123'
}
],
completed_at: '2026-02-26T12:05:00.000Z'
})
};
fetch('https://api.openfiskal.com/v1/operations/{operationId}/complete', 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://api.openfiskal.com/v1/operations/{operationId}/complete",
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([
'payments' => [
[
'payment_id' => 'pay_1001_card',
'method' => 'card',
'amount' => '47.50',
'currency' => 'EUR',
'status' => 'captured',
'processor' => 'sumup',
'card_brand' => 'visa',
'processor_reference' => 'ch_123',
'processed_at' => '2026-02-26T12:05:00.000Z',
'gift_card_id' => 'gc_abc123'
]
],
'completed_at' => '2026-02-26T12:05:00.000Z'
]),
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>",
"Content-Type: application/json",
"Idempotency-Key: <idempotency-key>",
"If-Match: <if-match>",
"X-OpenFiskal-Merchant: <x-openfiskal-merchant>"
],
]);
$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://api.openfiskal.com/v1/operations/{operationId}/complete"
payload := strings.NewReader("{\n \"payments\": [\n {\n \"payment_id\": \"pay_1001_card\",\n \"method\": \"card\",\n \"amount\": \"47.50\",\n \"currency\": \"EUR\",\n \"status\": \"captured\",\n \"processor\": \"sumup\",\n \"card_brand\": \"visa\",\n \"processor_reference\": \"ch_123\",\n \"processed_at\": \"2026-02-26T12:05:00.000Z\",\n \"gift_card_id\": \"gc_abc123\"\n }\n ],\n \"completed_at\": \"2026-02-26T12:05:00.000Z\"\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("X-OpenFiskal-Merchant", "<x-openfiskal-merchant>")
req.Header.Add("If-Match", "<if-match>")
req.Header.Add("Idempotency-Key", "<idempotency-key>")
req.Header.Add("Authorization", "Bearer <token>")
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://api.openfiskal.com/v1/operations/{operationId}/complete")
.header("X-OpenFiskal-Merchant", "<x-openfiskal-merchant>")
.header("If-Match", "<if-match>")
.header("Idempotency-Key", "<idempotency-key>")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"payments\": [\n {\n \"payment_id\": \"pay_1001_card\",\n \"method\": \"card\",\n \"amount\": \"47.50\",\n \"currency\": \"EUR\",\n \"status\": \"captured\",\n \"processor\": \"sumup\",\n \"card_brand\": \"visa\",\n \"processor_reference\": \"ch_123\",\n \"processed_at\": \"2026-02-26T12:05:00.000Z\",\n \"gift_card_id\": \"gc_abc123\"\n }\n ],\n \"completed_at\": \"2026-02-26T12:05:00.000Z\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.openfiskal.com/v1/operations/{operationId}/complete")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["X-OpenFiskal-Merchant"] = '<x-openfiskal-merchant>'
request["If-Match"] = '<if-match>'
request["Idempotency-Key"] = '<idempotency-key>'
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"payments\": [\n {\n \"payment_id\": \"pay_1001_card\",\n \"method\": \"card\",\n \"amount\": \"47.50\",\n \"currency\": \"EUR\",\n \"status\": \"captured\",\n \"processor\": \"sumup\",\n \"card_brand\": \"visa\",\n \"processor_reference\": \"ch_123\",\n \"processed_at\": \"2026-02-26T12:05:00.000Z\",\n \"gift_card_id\": \"gc_abc123\"\n }\n ],\n \"completed_at\": \"2026-02-26T12:05:00.000Z\"\n}"
response = http.request(request)
puts response.read_body{
"id": "<string>",
"merchant_id": "<string>",
"source": "POS",
"status": "open",
"currency": "EUR",
"resource_version": 123,
"created_at": "2023-11-07T05:31:56Z",
"updated_at": "2023-11-07T05:31:56Z",
"pretax_amount": "<string>",
"tax_amount": "<string>",
"tip_amount": "<string>",
"total_amount": "<string>",
"line_items": [
{
"id": "<string>",
"type": "item",
"title": "<string>",
"quantity": 123,
"unit_price": "<string>",
"total_amount": "<string>",
"sku_identifier": "TSHIRT-BLUE-M",
"taxes": [
{
"id": "<string>",
"name": "<string>",
"rate": "<string>",
"tax_amount": "<string>"
}
],
"gift_card_id": "<string>"
}
],
"payments": [
{
"id": "<string>",
"payment_id": "<string>",
"method": "<string>",
"amount": "<string>",
"currency": "<string>",
"status": "captured",
"processor": "<string>",
"card_brand": "<string>",
"processor_reference": "<string>",
"processed_at": "2023-11-07T05:31:56Z",
"gift_card_id": "<string>"
}
],
"type": "sale",
"cart_level_discounts": [
{
"id": "<string>",
"amount": "<string>",
"description": "<string>"
}
],
"location_id": "<string>",
"register_id": "<string>",
"session_id": "<string>",
"external_id": "<string>",
"fiscal_information": {
"regime": "KassenSichV",
"document_number": "<string>",
"document_type": "<string>",
"tss_serial_number": "<string>",
"pos_client_serial_number": "<string>",
"signature_algorithm": "<string>",
"time_format": "<string>",
"start_event": {
"signed_at": "2023-11-07T05:31:56Z"
},
"end_event": {
"signed_at": "2023-11-07T05:31:56Z",
"transaction_counter": 123,
"signature": "<string>",
"public_key": "<string>",
"process_type": "<string>",
"process_data": "<string>"
},
"verification": {
"qr_data": "<string>"
}
},
"completed_at": "2023-11-07T05:31:56Z",
"voided_at": "2023-11-07T05:31:56Z",
"void_reason": "<string>",
"note": "<string>"
}{
"code": "invalid_request",
"message": "The request body is malformed.",
"retryable": false
}{
"code": "unauthorized",
"message": "Authentication failed.",
"retryable": false
}{
"code": "forbidden",
"message": "The authenticated caller cannot access this resource.",
"retryable": false
}{
"code": "not_found",
"message": "The requested resource does not exist.",
"retryable": false
}{
"code": "operation_invalid_state",
"message": "Only OPEN operations can be completed.",
"retryable": false
}{
"code": "precondition_failed",
"message": "Resource version mismatch.",
"retryable": true,
"details": {
"expected_resource_version": 1,
"current_resource_version": 2
}
}{
"code": "regime_validation_failed",
"message": "The payload violates regime-specific validation rules.",
"retryable": false
}{
"code": "precondition_required",
"message": "This operation requires an If-Match header.",
"retryable": false
}Complete operation
Finalizes a goods-movement operation (sale / return / exchange) and attaches the typed payment contract used for fiscalization and reconciliation. Session-lifecycle operations (session_open, session_cash_adjustment, session_cash_count, session_close) auto-complete on POST /operations and must not be sent here — they will return 409 operation_invalid_state because they are never in OPEN status.
curl --request POST \
--url https://api.openfiskal.com/v1/operations/{operationId}/complete \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--header 'Idempotency-Key: <idempotency-key>' \
--header 'If-Match: <if-match>' \
--header 'X-OpenFiskal-Merchant: <x-openfiskal-merchant>' \
--data '
{
"payments": [
{
"payment_id": "pay_1001_card",
"method": "card",
"amount": "47.50",
"currency": "EUR",
"status": "captured",
"processor": "sumup",
"card_brand": "visa",
"processor_reference": "ch_123",
"processed_at": "2026-02-26T12:05:00.000Z",
"gift_card_id": "gc_abc123"
}
],
"completed_at": "2026-02-26T12:05:00.000Z"
}
'import requests
url = "https://api.openfiskal.com/v1/operations/{operationId}/complete"
payload = {
"payments": [
{
"payment_id": "pay_1001_card",
"method": "card",
"amount": "47.50",
"currency": "EUR",
"status": "captured",
"processor": "sumup",
"card_brand": "visa",
"processor_reference": "ch_123",
"processed_at": "2026-02-26T12:05:00.000Z",
"gift_card_id": "gc_abc123"
}
],
"completed_at": "2026-02-26T12:05:00.000Z"
}
headers = {
"X-OpenFiskal-Merchant": "<x-openfiskal-merchant>",
"If-Match": "<if-match>",
"Idempotency-Key": "<idempotency-key>",
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {
'X-OpenFiskal-Merchant': '<x-openfiskal-merchant>',
'If-Match': '<if-match>',
'Idempotency-Key': '<idempotency-key>',
Authorization: 'Bearer <token>',
'Content-Type': 'application/json'
},
body: JSON.stringify({
payments: [
{
payment_id: 'pay_1001_card',
method: 'card',
amount: '47.50',
currency: 'EUR',
status: 'captured',
processor: 'sumup',
card_brand: 'visa',
processor_reference: 'ch_123',
processed_at: '2026-02-26T12:05:00.000Z',
gift_card_id: 'gc_abc123'
}
],
completed_at: '2026-02-26T12:05:00.000Z'
})
};
fetch('https://api.openfiskal.com/v1/operations/{operationId}/complete', 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://api.openfiskal.com/v1/operations/{operationId}/complete",
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([
'payments' => [
[
'payment_id' => 'pay_1001_card',
'method' => 'card',
'amount' => '47.50',
'currency' => 'EUR',
'status' => 'captured',
'processor' => 'sumup',
'card_brand' => 'visa',
'processor_reference' => 'ch_123',
'processed_at' => '2026-02-26T12:05:00.000Z',
'gift_card_id' => 'gc_abc123'
]
],
'completed_at' => '2026-02-26T12:05:00.000Z'
]),
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>",
"Content-Type: application/json",
"Idempotency-Key: <idempotency-key>",
"If-Match: <if-match>",
"X-OpenFiskal-Merchant: <x-openfiskal-merchant>"
],
]);
$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://api.openfiskal.com/v1/operations/{operationId}/complete"
payload := strings.NewReader("{\n \"payments\": [\n {\n \"payment_id\": \"pay_1001_card\",\n \"method\": \"card\",\n \"amount\": \"47.50\",\n \"currency\": \"EUR\",\n \"status\": \"captured\",\n \"processor\": \"sumup\",\n \"card_brand\": \"visa\",\n \"processor_reference\": \"ch_123\",\n \"processed_at\": \"2026-02-26T12:05:00.000Z\",\n \"gift_card_id\": \"gc_abc123\"\n }\n ],\n \"completed_at\": \"2026-02-26T12:05:00.000Z\"\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("X-OpenFiskal-Merchant", "<x-openfiskal-merchant>")
req.Header.Add("If-Match", "<if-match>")
req.Header.Add("Idempotency-Key", "<idempotency-key>")
req.Header.Add("Authorization", "Bearer <token>")
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://api.openfiskal.com/v1/operations/{operationId}/complete")
.header("X-OpenFiskal-Merchant", "<x-openfiskal-merchant>")
.header("If-Match", "<if-match>")
.header("Idempotency-Key", "<idempotency-key>")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"payments\": [\n {\n \"payment_id\": \"pay_1001_card\",\n \"method\": \"card\",\n \"amount\": \"47.50\",\n \"currency\": \"EUR\",\n \"status\": \"captured\",\n \"processor\": \"sumup\",\n \"card_brand\": \"visa\",\n \"processor_reference\": \"ch_123\",\n \"processed_at\": \"2026-02-26T12:05:00.000Z\",\n \"gift_card_id\": \"gc_abc123\"\n }\n ],\n \"completed_at\": \"2026-02-26T12:05:00.000Z\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.openfiskal.com/v1/operations/{operationId}/complete")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["X-OpenFiskal-Merchant"] = '<x-openfiskal-merchant>'
request["If-Match"] = '<if-match>'
request["Idempotency-Key"] = '<idempotency-key>'
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"payments\": [\n {\n \"payment_id\": \"pay_1001_card\",\n \"method\": \"card\",\n \"amount\": \"47.50\",\n \"currency\": \"EUR\",\n \"status\": \"captured\",\n \"processor\": \"sumup\",\n \"card_brand\": \"visa\",\n \"processor_reference\": \"ch_123\",\n \"processed_at\": \"2026-02-26T12:05:00.000Z\",\n \"gift_card_id\": \"gc_abc123\"\n }\n ],\n \"completed_at\": \"2026-02-26T12:05:00.000Z\"\n}"
response = http.request(request)
puts response.read_body{
"id": "<string>",
"merchant_id": "<string>",
"source": "POS",
"status": "open",
"currency": "EUR",
"resource_version": 123,
"created_at": "2023-11-07T05:31:56Z",
"updated_at": "2023-11-07T05:31:56Z",
"pretax_amount": "<string>",
"tax_amount": "<string>",
"tip_amount": "<string>",
"total_amount": "<string>",
"line_items": [
{
"id": "<string>",
"type": "item",
"title": "<string>",
"quantity": 123,
"unit_price": "<string>",
"total_amount": "<string>",
"sku_identifier": "TSHIRT-BLUE-M",
"taxes": [
{
"id": "<string>",
"name": "<string>",
"rate": "<string>",
"tax_amount": "<string>"
}
],
"gift_card_id": "<string>"
}
],
"payments": [
{
"id": "<string>",
"payment_id": "<string>",
"method": "<string>",
"amount": "<string>",
"currency": "<string>",
"status": "captured",
"processor": "<string>",
"card_brand": "<string>",
"processor_reference": "<string>",
"processed_at": "2023-11-07T05:31:56Z",
"gift_card_id": "<string>"
}
],
"type": "sale",
"cart_level_discounts": [
{
"id": "<string>",
"amount": "<string>",
"description": "<string>"
}
],
"location_id": "<string>",
"register_id": "<string>",
"session_id": "<string>",
"external_id": "<string>",
"fiscal_information": {
"regime": "KassenSichV",
"document_number": "<string>",
"document_type": "<string>",
"tss_serial_number": "<string>",
"pos_client_serial_number": "<string>",
"signature_algorithm": "<string>",
"time_format": "<string>",
"start_event": {
"signed_at": "2023-11-07T05:31:56Z"
},
"end_event": {
"signed_at": "2023-11-07T05:31:56Z",
"transaction_counter": 123,
"signature": "<string>",
"public_key": "<string>",
"process_type": "<string>",
"process_data": "<string>"
},
"verification": {
"qr_data": "<string>"
}
},
"completed_at": "2023-11-07T05:31:56Z",
"voided_at": "2023-11-07T05:31:56Z",
"void_reason": "<string>",
"note": "<string>"
}{
"code": "invalid_request",
"message": "The request body is malformed.",
"retryable": false
}{
"code": "unauthorized",
"message": "Authentication failed.",
"retryable": false
}{
"code": "forbidden",
"message": "The authenticated caller cannot access this resource.",
"retryable": false
}{
"code": "not_found",
"message": "The requested resource does not exist.",
"retryable": false
}{
"code": "operation_invalid_state",
"message": "Only OPEN operations can be completed.",
"retryable": false
}{
"code": "precondition_failed",
"message": "Resource version mismatch.",
"retryable": true,
"details": {
"expected_resource_version": 1,
"current_resource_version": 2
}
}{
"code": "regime_validation_failed",
"message": "The payload violates regime-specific validation rules.",
"retryable": false
}{
"code": "precondition_required",
"message": "This operation requires an If-Match header.",
"retryable": false
}Authorizations
Bearer authentication header of the form Bearer <token>, where <token> is your auth token.
Headers
Merchant identifier returned by the merchants resource.
Latest operation ETag returned by OpenFiskal. Replace it after every successful mutation.
Unique key per endpoint, merchant, and tenant. Retained for at least 24 hours.
Path Parameters
Body
Response
Operation completed
- SaleOperation
- ReturnOperation
- ExchangeOperation
POS, ONLINE open, completed, voided ISO 4217 currency code.
"EUR"
Current server-issued version for the operation, starting at 1. Returned as ETag header.
Show child attributes
Show child attributes
Show child attributes
Show child attributes
sale "sale"
Cart-level (order-level) discounts applied across the SALE. Empty array when none. Surfaced separately from line items so consumers do not need to back-derive from totals.
Show child attributes
Show child attributes
Only set for source: POS.
Only set for source: POS.
The RegisterSession this Operation is bound to. Set on every POS Operation; null for ONLINE goods-movement (no register, hence no session). On session-event variants this is the session being opened, adjusted, or closed; on goods-movement variants it is the session the operation was rung up during.
Merchant or POS identifier for the upstream order.
The Fiskaly signature attached to this Operation, when one exists. Null until the operation has been signed.
- FiscalInformationKassenSichV
- FiscalInformationRKSV
- FiscalInformationRT
Show child attributes
Show child attributes
Merchant free-text note for the goods-movement event.
Was this page helpful?