ProfirestAPI v2
Finální smlouva · v ostrém provozu
ObsahContents
  1. ZákladyBasics
  2. Nastavení a chybySetup and errors
  3. Opakování se stejným klíčemRetries with the same key
  4. StránkováníPaging
  5. Proud událostíThe event feed
  6. ScénářeScenarios
  7. Objednávka z e-shopuAn order from an e-shop
  8. PokladnaA cash register
  9. Kuchyňský displejA kitchen display
  10. Docházkový terminálAn attendance terminal
  11. RozvozDeliveries
  12. Stav, chyby a logy zařízeníState, errors and logs of a device
  13. Zákazníci, body a voucheryCustomers, points and vouchers
  14. Rezervace stolů a služebReservations of tables and services
  15. Útrata na pokoj (hotelová restaurace a bar)Charging bills to a room (hotel restaurant and bar)
  16. Turniket wellness a čtečka na snídaniA wellness gate and a breakfast reader
  17. Aplikace pro pokojské a údržbuAn application for housekeepers and maintenance
  18. Účetnictví a přehledyAccounting and reports

API v2

Návody

Guides

Celé scénáře krok za krokem – od připojení po poslední požadavek – v curl a v oficiálních knihovnách pro JavaScript, TypeScript, PHP, Javu, Kotlin, C#, Python, Swift, Dart a Go. Každý krok je stejná ukázka jako u operace v referenci, s příkladem odpovědi.

Whole scenarios step by step – from connecting to the last request – in curl and the official libraries for JavaScript, TypeScript, PHP, Java, Kotlin, C#, Python, Swift, Dart and Go. Every step is the same example as at the operation in the reference, with an example answer.

EET 2.0 eviduje ProfirestTržby objednávek placených na místě (hotově nebo kartou kurýrovi či při odběru) i účtenky pokladen zaeviduje do EET 2.0 server Profirestu – při předání, certifikátem provozovny. Online platby se neevidují. Vaše aplikace finanční správě nic neposílá a certifikát nepotřebuje.

EET 2.0 is done by ProfirestThe Profirest server records orders paid on the spot (cash or card to the courier or at pickup) and register receipts in EET 2.0 – at the hand-over, with the restaurant's certificate. Online payments are not recorded. Your application sends nothing to the tax administration and needs no certificate.

Co ukázky předpokládajíSpárovaného klienta oficiální knihovny v proměnné api – tokeny, obnovu, Idempotency-Key a opakování obstará knihovna (nastavení je v části Nastavení a chyby a na stránce každé knihovny v nabídce Knihovny). curl ukazuje čisté HTTP s proměnnými $ACCESS_TOKEN a $STAFF_TOKEN. Všechny ukázky se před vydáním překládají proti skutečným knihovnám.

What the examples assumeA paired client of the official library in the variable api – the library takes care of tokens, refreshing, Idempotency-Key and retries (setup is in Setup and errors and on each library's page in the Libraries menu). curl shows plain HTTP with the variables $ACCESS_TOKEN and $STAFF_TOKEN. Every example is compiled against the real libraries before release.

Každý krok si vyzkoušejteTlačítko ▶ Vyzkoušet u kroku otevře playground s operací a příkladem kroku – v režimu Ukázka hned odpoví příkladem ze smlouvy (nic se neodesílá), naostro pošle skutečný požadavek s vaším tokenem. Ukázky v JavaScriptu spustíte tlačítkem ▶ Spustit přímo v prohlížeči s klientem profirest-api.js.

Try every stepThe ▶ Try it button at a step opens the playground with the step's operation and example – in Example mode it answers at once with the contract's example (nothing is sent), live it sends a real request with your token. Run the JavaScript examples with ▶ Run right in the browser with the profirest-api.js client.

Ukázky vExamples in
Volba platí i v referenci.The choice applies to the reference too.

Základy

Basics

Nastavení a chyby

Setup and errors

Kroky scénářů níže volají oficiální knihovnu vybraného jazyka (curl ukazuje čisté HTTP). Knihovna přidá token a obnoví ho, pošle a přečte JSON a chybu promění ve výjimku s code z katalogu chyb. Rozhodujte se podle code, ne podle HTTP stavu. Instalace a celá reference klienta: nabídka Knihovny nahoře.

The scenario steps below call the official library of the chosen language (curl shows plain HTTP). The library adds and refreshes the token, sends and reads JSON and turns an error into an exception with the code from the error catalog. Branch on code, not on the HTTP status. Installation and the full client reference: the Libraries menu at the top.

# adresa API: https://api.mujprofirest.cz
export ACCESS_TOKEN='pfa_…'   # z /oauth/token
curl "https://api.mujprofirest.cz/v2/" -H "Authorization: Bearer $ACCESS_TOKEN"

# chyba přijde jako application/problem+json – rozhodujte se podle "code"
# {"type":"https://api.mujprofirest.cz/v2/docs/errors#not_found","status":404,"code":"not_found",…}
# API address: https://api.mujprofirest.cz
export ACCESS_TOKEN='pfa_…'   # from /oauth/token
curl "https://api.mujprofirest.cz/v2/" -H "Authorization: Bearer $ACCESS_TOKEN"

# an error comes as application/problem+json – branch on "code"
# {"type":"https://api.mujprofirest.cz/v2/docs/errors#not_found","status":404,"code":"not_found",…}
<script src="https://api.mujprofirest.cz/v2/profirest-api.min.js"></script>
<script>
  const api = new ProfirestApi({ clientId: 'profirest-pos' });   // tokeny přežijí restart; chraňte je jako heslo (localStorage)
  if (!api.isPaired()) {                                         // jen poprvé: kód potvrdí vedoucí v administraci
    const pairing = await api.pair({ scope: 'restaurants:read catalog:read orders:write', deviceName: 'Pokladna 1' });
    showCode(pairing.userCode);
    await pairing.connected;
  }
  try {
    const restaurants = await api.all('/restaurants');
  } catch (e) {
    if (e.code === 'not_paired') showPairing();                 // kód z katalogu chyb
  }
</script>
<script src="https://api.mujprofirest.cz/v2/profirest-api.min.js"></script>
<script>
  const api = new ProfirestApi({ clientId: 'profirest-pos' });   // tokens survive a restart; protect them like a password (localStorage)
  if (!api.isPaired()) {                                         // only the first time: a manager confirms the code in the administration
    const pairing = await api.pair({ scope: 'restaurants:read catalog:read orders:write', deviceName: 'Pokladna 1' });
    showCode(pairing.userCode);
    await pairing.connected;
  }
  try {
    const restaurants = await api.all('/restaurants');
  } catch (e) {
    if (e.code === 'not_paired') showPairing();                 // the code from the error catalog
  }
</script>
import ProfirestApi = require('./profirest-api');            // + profirest-api.d.ts

const api = new ProfirestApi({ clientId: 'profirest-pos' });
if (!api.isPaired()) {                                           // jen poprvé: kód potvrdí vedoucí v administraci
  const pairing = await api.pair({ scope: 'restaurants:read catalog:read orders:write', deviceName: 'Pokladna 1' });
  showCode(pairing.userCode);
  await pairing.connected;
}
try {
  const restaurants = await api.all('/restaurants');            // Restaurant[]
} catch (e) {
  if (e instanceof ProfirestApi.ApiError && e.code === 'not_paired') showPairing();   // kód z katalogu chyb
}
import ProfirestApi = require('./profirest-api');            // + profirest-api.d.ts

const api = new ProfirestApi({ clientId: 'profirest-pos' });
if (!api.isPaired()) {                                           // only the first time: a manager confirms the code in the administration
  const pairing = await api.pair({ scope: 'restaurants:read catalog:read orders:write', deviceName: 'Pokladna 1' });
  showCode(pairing.userCode);
  await pairing.connected;
}
try {
  const restaurants = await api.all('/restaurants');            // Restaurant[]
} catch (e) {
  if (e instanceof ProfirestApi.ApiError && e.code === 'not_paired') showPairing();   // the code from the error catalog
}
<?php
// composer require profirest/api-client
use Profirest\Api\{ApiError, Client};
use Profirest\Api\Storage\FileStorage;

$api = new Client(clientId: 'profirest-pos',
                  storage: new FileStorage('/var/lib/app/profirest.json'));   // tokeny přežijí restart; chraňte je jako heslo
if (!$api->isPaired()) {                                                     // jen poprvé: kód potvrdí vedoucí v administraci
    $pairing = $api->pair(scope: 'restaurants:read catalog:read orders:write', deviceName: 'Kiosek 1');
    echo $pairing->userCode;
    $pairing->wait();
}
try {
    $restaurants = $api->all('/restaurants');
} catch (ApiError $e) {
    if ($e->errorCode === 'not_paired') { showPairing(); }                    // kód z katalogu chyb
}
<?php
// composer require profirest/api-client
use Profirest\Api\{ApiError, Client};
use Profirest\Api\Storage\FileStorage;

$api = new Client(clientId: 'profirest-pos',
                  storage: new FileStorage('/var/lib/app/profirest.json'));   // tokens survive a restart; protect them like a password
if (!$api->isPaired()) {                                                     // only the first time: a manager confirms the code in the administration
    $pairing = $api->pair(scope: 'restaurants:read catalog:read orders:write', deviceName: 'Kiosek 1');
    echo $pairing->userCode;
    $pairing->wait();
}
try {
    $restaurants = $api->all('/restaurants');
} catch (ApiError $e) {
    if ($e->errorCode === 'not_paired') { showPairing(); }                    // the code from the error catalog
}
// implementation(files("libs/profirest-api-1.0.0.jar")) – volání blokuje, ne na hlavním vlákně
ProfirestApi api = ProfirestApi.builder()
        .clientId("profirest-pos")
        .storage(new FileStorage("profirest.json"))                // tokeny přežijí restart; chraňte je jako heslo
        .build();
if (!api.isPaired()) {                                              // jen poprvé: kód potvrdí vedoucí v administraci
    Pairing pairing = api.pair(PairOptions.builder().scope("restaurants:read catalog:read orders:write").deviceName("Pokladna 1").build());
    showCode(pairing.getUserCode());
    pairing.awaitConnected();
}
try {
    List<Restaurant> restaurants = api.all("/restaurants", null, Restaurant::fromJson);
} catch (ApiException e) {
    if ("not_paired".equals(e.getCode())) showPairing();            // kód z katalogu chyb
}
// implementation(files("libs/profirest-api-1.0.0.jar")) – volání blokuje, ne na hlavním vlákně
ProfirestApi api = ProfirestApi.builder()
        .clientId("profirest-pos")
        .storage(new FileStorage("profirest.json"))                // tokens survive a restart; protect them like a password
        .build();
if (!api.isPaired()) {                                              // only the first time: a manager confirms the code in the administration
    Pairing pairing = api.pair(PairOptions.builder().scope("restaurants:read catalog:read orders:write").deviceName("Pokladna 1").build());
    showCode(pairing.getUserCode());
    pairing.awaitConnected();
}
try {
    List<Restaurant> restaurants = api.all("/restaurants", null, Restaurant::fromJson);
} catch (ApiException e) {
    if ("not_paired".equals(e.getCode())) showPairing();            // the code from the error catalog
}
// implementation(files("libs/profirest-api-1.0.0.jar"))
val api = ProfirestApi.builder()
    .clientId("profirest-pos")
    .storage(SharedPreferencesStorage(context))                     // tokeny přežijí restart; chraňte je jako heslo
    .build()

suspend fun start() = withContext(Dispatchers.IO) {
    if (!api.isPaired) {                                            // jen poprvé: kód potvrdí vedoucí v administraci
        val pairing = api.pair(PairOptions.builder().scope("restaurants:read catalog:read orders:write").deviceName("Pokladna 1").build())
        showCode(pairing.userCode)
        pairing.awaitConnected()
    }
    try {
        val restaurants = api.all("/restaurants", null, Restaurant::fromJson)
    } catch (e: ApiException) {
        if (e.code == "not_paired") showPairing()                   // kód z katalogu chyb
    }
}
// implementation(files("libs/profirest-api-1.0.0.jar"))
val api = ProfirestApi.builder()
    .clientId("profirest-pos")
    .storage(SharedPreferencesStorage(context))                     // tokens survive a restart; protect them like a password
    .build()

suspend fun start() = withContext(Dispatchers.IO) {
    if (!api.isPaired) {                                            // only the first time: a manager confirms the code in the administration
        val pairing = api.pair(PairOptions.builder().scope("restaurants:read catalog:read orders:write").deviceName("Pokladna 1").build())
        showCode(pairing.userCode)
        pairing.awaitConnected()
    }
    try {
        val restaurants = api.all("/restaurants", null, Restaurant::fromJson)
    } catch (e: ApiException) {
        if (e.code == "not_paired") showPairing()                   // the code from the error catalog
    }
}
// dotnet add package Profirest.Api
using Profirest.Api;
using Profirest.Api.Models;
using Profirest.Api.Storage;

var api = new ProfirestApi(new ProfirestApiOptions
{
    ClientId = "profirest-pos",
    Storage = new FileTokenStorage("profirest.json"),               // tokeny přežijí restart; chraňte je jako heslo
});
if (!api.IsPaired)                                                   // jen poprvé: kód potvrdí vedoucí v administraci
{
    var pairing = await api.PairAsync(new PairOptions { Scope = "restaurants:read catalog:read orders:write", DeviceName = "Pokladna 1" });
    ShowCode(pairing.UserCode);
    await pairing.Connected;
}
try
{
    List<Restaurant> restaurants = await api.AllAsync<Restaurant>("/restaurants");
}
catch (ProfirestApiException e) when (e.Code == ErrorCodes.NotPaired) // kód z katalogu chyb
{
    ShowPairing();
}
// dotnet add package Profirest.Api
using Profirest.Api;
using Profirest.Api.Models;
using Profirest.Api.Storage;

var api = new ProfirestApi(new ProfirestApiOptions
{
    ClientId = "profirest-pos",
    Storage = new FileTokenStorage("profirest.json"),               // tokens survive a restart; protect them like a password
});
if (!api.IsPaired)                                                   // only the first time: a manager confirms the code in the administration
{
    var pairing = await api.PairAsync(new PairOptions { Scope = "restaurants:read catalog:read orders:write", DeviceName = "Pokladna 1" });
    ShowCode(pairing.UserCode);
    await pairing.Connected;
}
try
{
    List<Restaurant> restaurants = await api.AllAsync<Restaurant>("/restaurants");
}
catch (ProfirestApiException e) when (e.Code == ErrorCodes.NotPaired) // the code from the error catalog
{
    ShowPairing();
}
# pip install profirest-api
from profirest_api import ApiError, FileStorage, ProfirestApi

api = ProfirestApi(client_id='profirest-pos',
                   storage=FileStorage('/var/lib/app/profirest.json'))   # tokeny přežijí restart; chraňte je jako heslo
if not api.is_paired():                                                # jen poprvé: kód potvrdí vedoucí v administraci
    pairing = api.pair(scope='restaurants:read catalog:read orders:write', device_name='Kiosek 1')
    print(pairing.user_code)
    pairing.wait()
try:
    restaurants = api.all('/restaurants')
except ApiError as e:
    if e.code == 'not_paired':                                         # kód z katalogu chyb
        show_pairing()
# pip install profirest-api
from profirest_api import ApiError, FileStorage, ProfirestApi

api = ProfirestApi(client_id='profirest-pos',
                   storage=FileStorage('/var/lib/app/profirest.json'))   # tokens survive a restart; protect them like a password
if not api.is_paired():                                                # only the first time: a manager confirms the code in the administration
    pairing = api.pair(scope='restaurants:read catalog:read orders:write', device_name='Kiosek 1')
    print(pairing.user_code)
    pairing.wait()
try:
    restaurants = api.all('/restaurants')
except ApiError as e:
    if e.code == 'not_paired':                                         # the code from the error catalog
        show_pairing()
// Package.swift: .package(path: "profirest-api-swift-1.0.0"), knihovna ProfirestAPI
import ProfirestAPI

let api = ProfirestApi(options: .init(clientID: "profirest-pos",
                                      storage: KeychainTokenStorage()))   // tokeny přežijí restart; chraňte je jako heslo (Klíčenka)
if !api.isPaired {                                                      // jen poprvé: kód potvrdí vedoucí v administraci
    let pairing = try await api.pair(scope: "restaurants:read catalog:read orders:write", deviceName: "Pokladna 1")
    showCode(pairing.userCode)
    _ = try await pairing.connected()
}
do {
    let restaurants: [Restaurant] = try await api.all("/restaurants")
} catch let error as ProfirestAPIError where error.code == ErrorCode.notPaired {   // kód z katalogu chyb
    showPairing()
}
// Package.swift: .package(path: "profirest-api-swift-1.0.0"), knihovna ProfirestAPI
import ProfirestAPI

let api = ProfirestApi(options: .init(clientID: "profirest-pos",
                                      storage: KeychainTokenStorage()))   // tokens survive a restart; protect them like a password (Klíčenka)
if !api.isPaired {                                                      // only the first time: a manager confirms the code in the administration
    let pairing = try await api.pair(scope: "restaurants:read catalog:read orders:write", deviceName: "Pokladna 1")
    showCode(pairing.userCode)
    _ = try await pairing.connected()
}
do {
    let restaurants: [Restaurant] = try await api.all("/restaurants")
} catch let error as ProfirestAPIError where error.code == ErrorCode.notPaired {   // the code from the error catalog
    showPairing()
}
// pubspec.yaml: profirest_api: {path: ../profirest-api-dart-1.0.0}
import 'package:profirest_api/profirest_api.dart';
import 'package:profirest_api/io.dart';                 // FileStorage (ne na webu)
import 'package:profirest_api/models.dart' as pr;      // modely (volitelné)

final api = ProfirestApi(clientId: 'profirest-pos', storage: FileStorage('profirest.json'));   // tokeny přežijí restart; chraňte je jako heslo

Future<void> start() async {
  if (!await api.isPaired()) {                                         // jen poprvé: kód potvrdí vedoucí v administraci
    final pairing = await api.pair(scope: 'restaurants:read catalog:read orders:write', deviceName: 'Pokladna 1');
    showCode(pairing.userCode);
    await pairing.connected;
  }
  try {
    final restaurants = await api.all('/restaurants');
  } on ApiError catch (e) {
    if (e.code == 'not_paired') showPairing();                          // kód z katalogu chyb
  }
}
// pubspec.yaml: profirest_api: {path: ../profirest-api-dart-1.0.0}
import 'package:profirest_api/profirest_api.dart';
import 'package:profirest_api/io.dart';                 // FileStorage (ne na webu)
import 'package:profirest_api/models.dart' as pr;      // modely (volitelné)

final api = ProfirestApi(clientId: 'profirest-pos', storage: FileStorage('profirest.json'));   // tokens survive a restart; protect them like a password

Future<void> start() async {
  if (!await api.isPaired()) {                                         // only the first time: a manager confirms the code in the administration
    final pairing = await api.pair(scope: 'restaurants:read catalog:read orders:write', deviceName: 'Pokladna 1');
    showCode(pairing.userCode);
    await pairing.connected;
  }
  try {
    final restaurants = await api.all('/restaurants');
  } on ApiError catch (e) {
    if (e.code == 'not_paired') showPairing();                          // the code from the error catalog
  }
}
// import profirest "github.com/profirest/profirest-api-go" (+ ".../model")
api := profirest.New(profirest.Options{
	ClientID: "profirest-pos",
	Storage:  profirest.NewFileStorage("profirest.json"), // tokeny přežijí restart; chraňte je jako heslo
})
if !api.IsPaired() { // jen poprvé: kód potvrdí vedoucí v administraci
	pairing, err := api.Pair(ctx, profirest.PairOptions{Scope: "restaurants:read catalog:read orders:write", DeviceName: "Pokladna 1"})
	if err != nil {
		return err
	}
	showCode(pairing.UserCode)
	if _, err := pairing.Wait(ctx); err != nil {
		return err
	}
}
restaurants, err := profirest.All[model.Restaurant](ctx, api, "/restaurants", nil)
var apiErr *profirest.APIError
if errors.As(err, &apiErr) && apiErr.Code == profirest.CodeNotPaired { // kód z katalogu chyb
	showPairing()
}
// import profirest "github.com/profirest/profirest-api-go" (+ ".../model")
api := profirest.New(profirest.Options{
	ClientID: "profirest-pos",
	Storage:  profirest.NewFileStorage("profirest.json"), // tokens survive a restart; protect them like a password
})
if !api.IsPaired() { // only the first time: a manager confirms the code in the administration
	pairing, err := api.Pair(ctx, profirest.PairOptions{Scope: "restaurants:read catalog:read orders:write", DeviceName: "Pokladna 1"})
	if err != nil {
		return err
	}
	showCode(pairing.UserCode)
	if _, err := pairing.Wait(ctx); err != nil {
		return err
	}
}
restaurants, err := profirest.All[model.Restaurant](ctx, api, "/restaurants", nil)
var apiErr *profirest.APIError
if errors.As(err, &apiErr) && apiErr.Code == profirest.CodeNotPaired { // the code from the error catalog
	showPairing()
}

Základy

Basics

Opakování se stejným klíčem

Retries with the same key

Každý POST nese Idempotency-Key; při opakování stejného požadavku jde stejný klíč a server druhý záznam nezaloží. Knihovny to dělají samy: opakují výpadek sítě, 429, 409 idempotency_in_progress a stavy 500–504 a čekají podle Retry-After. Když požadavek opakujete vy (třeba po restartu aplikace), předejte vlastní klíč uložený u záznamu. Klíč, který vytvoří knihovna, žije jen v paměti procesu – po pádu aplikace ho nemáte. Vlastní klíč proto vytvořte (nebo odvoďte z ID záznamu) a uložte k záznamu dřív, než požadavek odešlete; server výsledek pod klíčem drží 24 hodin a stejný klíč s jiným tělem odmítne (422 idempotency_key_mismatch). Objednávka má navíc dvě pojistky nezávislé na klíči: kalkulaci jde použít jen jednou (409 quote_already_used) a vaše external_id je trvalé (409 external_id_conflict) – obě chyby nesou v existing_id ID už založené objednávky.

Every POST carries an Idempotency-Key; a repeat of the same request sends the same key and the server never creates a second record. The libraries do it themselves: they retry a network failure, 429, 409 idempotency_in_progress and the statuses 500–504 and wait as Retry-After says. When you repeat a request yourself (say after an application restart), pass your own key stored with the record. The key a library makes lives only in the memory of the process – after a crash you do not have it. So create your own key (or derive it from the ID of the record) and store it with the record before you send the request; the server keeps the result under the key for 24 hours and rejects the same key with another body (422 idempotency_key_mismatch). An order has two more guards that do not depend on the key: a quote can be used only once (409 quote_already_used) and your external_id is permanent (409 external_id_conflict) – both errors carry the ID of the existing order in existing_id.

# stejný klíč při každém opakování – server druhou nabídku nezaloží
KEY=$(uuidgen)
curl "https://api.mujprofirest.cz/v2/restaurants/123/quotes" \
  -H "Authorization: Bearer $ACCESS_TOKEN" -H "Idempotency-Key: $KEY" -H "Content-Type: application/json" \
  -d '{"fulfillment": {"type": "pickup"}, "items": [{"product_id": "4567", "quantity": 2}]}'
# 429 nebo 503: počkejte Retry-After sekund a pošlete totéž se stejným $KEY
# the same key on every retry – the server creates no second quote
KEY=$(uuidgen)
curl "https://api.mujprofirest.cz/v2/restaurants/123/quotes" \
  -H "Authorization: Bearer $ACCESS_TOKEN" -H "Idempotency-Key: $KEY" -H "Content-Type: application/json" \
  -d '{"fulfillment": {"type": "pickup"}, "items": [{"product_id": "4567", "quantity": 2}]}'
# 429 or 503: wait Retry-After seconds and send the same with the same $KEY
// knihovna opakuje sama: výpadek sítě, timeout, 429, 409 idempotency_in_progress a 5xx – se stejným Idempotency-Key
const quote = await api.post('/restaurants/123/quotes', basket);
// vlastní klíč z ID záznamu, který jste uložili před odesláním – opakování i po restartu aplikace nic nezdvojí
const order = await api.post('/restaurants/123/orders', body, { idempotencyKey: 'order-' + localId });
// the library retries itself: a network failure, a timeout, 429, 409 idempotency_in_progress and 5xx – with the same Idempotency-Key
const quote = await api.post('/restaurants/123/quotes', basket);
// your own key from the ID of the record you stored before sending – a retry even after an application restart duplicates nothing
const order = await api.post('/restaurants/123/orders', body, { idempotencyKey: 'order-' + localId });
// knihovna opakuje sama: výpadek sítě, timeout, 429, 409 idempotency_in_progress a 5xx – se stejným Idempotency-Key
const quote = await api.post('/restaurants/123/quotes', basket);          // Quote
// vlastní klíč z ID záznamu, který jste uložili před odesláním – opakování i po restartu aplikace nic nezdvojí
const order = await api.post('/restaurants/123/orders', body, { idempotencyKey: 'order-' + localId });
// the library retries itself: a network failure, a timeout, 429, 409 idempotency_in_progress and 5xx – with the same Idempotency-Key
const quote = await api.post('/restaurants/123/quotes', basket);          // Quote
// your own key from the ID of the record you stored before sending – a retry even after an application restart duplicates nothing
const order = await api.post('/restaurants/123/orders', body, { idempotencyKey: 'order-' + localId });
// knihovna opakuje sama: výpadek sítě, timeout, 429, 409 idempotency_in_progress a 5xx – se stejným Idempotency-Key
$quote = $api->post('/restaurants/123/quotes', $basket);
// vlastní klíč z ID záznamu, který jste uložili před odesláním – opakování i po restartu aplikace nic nezdvojí
$order = $api->post('/restaurants/123/orders', $body, ['idempotencyKey' => 'order-' . $localId]);
// the library retries itself: a network failure, a timeout, 429, 409 idempotency_in_progress and 5xx – with the same Idempotency-Key
$quote = $api->post('/restaurants/123/quotes', $basket);
// your own key from the ID of the record you stored before sending – a retry even after an application restart duplicates nothing
$order = $api->post('/restaurants/123/orders', $body, ['idempotencyKey' => 'order-' . $localId]);
// knihovna opakuje sama: výpadek sítě, timeout, 429, 409 idempotency_in_progress a 5xx – se stejným Idempotency-Key
Quote quote = api.post("/restaurants/123/quotes", basket, Quote::fromJson);
// vlastní klíč z ID záznamu, který jste uložili před odesláním – opakování i po restartu aplikace nic nezdvojí
Order order = api.post("/restaurants/123/orders", body,
        RequestOptions.builder().idempotencyKey("order-" + localId).build(), Order::fromJson);
// the library retries itself: a network failure, a timeout, 429, 409 idempotency_in_progress and 5xx – with the same Idempotency-Key
Quote quote = api.post("/restaurants/123/quotes", basket, Quote::fromJson);
// your own key from the ID of the record you stored before sending – a retry even after an application restart duplicates nothing
Order order = api.post("/restaurants/123/orders", body,
        RequestOptions.builder().idempotencyKey("order-" + localId).build(), Order::fromJson);
// knihovna opakuje sama: výpadek sítě, timeout, 429, 409 idempotency_in_progress a 5xx – se stejným Idempotency-Key
val quote = api.post("/restaurants/123/quotes", basket, Quote::fromJson)
// vlastní klíč z ID záznamu, který jste uložili před odesláním – opakování i po restartu aplikace nic nezdvojí
val order = api.post("/restaurants/123/orders", body,
    RequestOptions.builder().idempotencyKey("order-$localId").build(), Order::fromJson)
// the library retries itself: a network failure, a timeout, 429, 409 idempotency_in_progress and 5xx – with the same Idempotency-Key
val quote = api.post("/restaurants/123/quotes", basket, Quote::fromJson)
// your own key from the ID of the record you stored before sending – a retry even after an application restart duplicates nothing
val order = api.post("/restaurants/123/orders", body,
    RequestOptions.builder().idempotencyKey("order-$localId").build(), Order::fromJson)
// knihovna opakuje sama: výpadek sítě, timeout, 429, 409 idempotency_in_progress a 5xx – se stejným Idempotency-Key
var quote = await api.PostAsync<Quote>("/restaurants/123/quotes", basket);
// vlastní klíč z ID záznamu, který jste uložili před odesláním – opakování i po restartu aplikace nic nezdvojí
var order = await api.PostAsync<Order>("/restaurants/123/orders", body,
    new RequestOptions { IdempotencyKey = "order-" + localId });
// the library retries itself: a network failure, a timeout, 429, 409 idempotency_in_progress and 5xx – with the same Idempotency-Key
var quote = await api.PostAsync<Quote>("/restaurants/123/quotes", basket);
// your own key from the ID of the record you stored before sending – a retry even after an application restart duplicates nothing
var order = await api.PostAsync<Order>("/restaurants/123/orders", body,
    new RequestOptions { IdempotencyKey = "order-" + localId });
# knihovna opakuje sama: výpadek sítě, timeout, 429, 409 idempotency_in_progress a 5xx – se stejným Idempotency-Key
quote = api.post('/restaurants/123/quotes', basket)
# vlastní klíč z ID záznamu, který jste uložili před odesláním – opakování i po restartu aplikace nic nezdvojí
order = api.post('/restaurants/123/orders', body, idempotency_key=f'order-{local_id}')
# the library retries itself: a network failure, a timeout, 429, 409 idempotency_in_progress and 5xx – with the same Idempotency-Key
quote = api.post('/restaurants/123/quotes', basket)
# your own key from the ID of the record you stored before sending – a retry even after an application restart duplicates nothing
order = api.post('/restaurants/123/orders', body, idempotency_key=f'order-{local_id}')
// knihovna opakuje sama: výpadek sítě, timeout, 429, 409 idempotency_in_progress a 5xx – se stejným Idempotency-Key
let quote: Quote = try await api.post("/restaurants/123/quotes", body: basket)
// vlastní klíč z ID záznamu, který jste uložili před odesláním – opakování i po restartu aplikace nic nezdvojí
let order: Order = try await api.post("/restaurants/123/orders", body: body,
                                      options: .init(idempotencyKey: .key("order-\(localID)")))
// the library retries itself: a network failure, a timeout, 429, 409 idempotency_in_progress and 5xx – with the same Idempotency-Key
let quote: Quote = try await api.post("/restaurants/123/quotes", body: basket)
// your own key from the ID of the record you stored before sending – a retry even after an application restart duplicates nothing
let order: Order = try await api.post("/restaurants/123/orders", body: body,
                                      options: .init(idempotencyKey: .key("order-\(localID)")))
// knihovna opakuje sama: výpadek sítě, timeout, 429, 409 idempotency_in_progress a 5xx – se stejným Idempotency-Key
final quote = pr.Quote.fromJson(await api.post('/restaurants/123/quotes', basket));
// vlastní klíč z ID záznamu, který jste uložili před odesláním – opakování i po restartu aplikace nic nezdvojí
final order = pr.Order.fromJson(await api.post('/restaurants/123/orders', body, idempotencyKey: 'order-$localId'));
// the library retries itself: a network failure, a timeout, 429, 409 idempotency_in_progress and 5xx – with the same Idempotency-Key
final quote = pr.Quote.fromJson(await api.post('/restaurants/123/quotes', basket));
// your own key from the ID of the record you stored before sending – a retry even after an application restart duplicates nothing
final order = pr.Order.fromJson(await api.post('/restaurants/123/orders', body, idempotencyKey: 'order-$localId'));
// knihovna opakuje sama: výpadek sítě, timeout, 429, 409 idempotency_in_progress a 5xx – se stejným Idempotency-Key
res, err := api.Post(ctx, "/restaurants/123/quotes", basket, nil)
// vlastní klíč z ID záznamu, který jste uložili před odesláním – opakování i po restartu aplikace nic nezdvojí
res, err = api.Post(ctx, "/restaurants/123/orders", body, &profirest.RequestOptions{IdempotencyKey: "order-" + localID})
// the library retries itself: a network failure, a timeout, 429, 409 idempotency_in_progress and 5xx – with the same Idempotency-Key
res, err := api.Post(ctx, "/restaurants/123/quotes", basket, nil)
// your own key from the ID of the record you stored before sending – a retry even after an application restart duplicates nothing
res, err = api.Post(ctx, "/restaurants/123/orders", body, &profirest.RequestOptions{IdempotencyKey: "order-" + localID})

Základy

Basics

Stránkování

Paging

Seznamy vrací {"data": [...], "next_cursor": "..."}. Knihovny projdou stránky samy – všechny položky najednou, nebo stránku po stránce; konec je stránka bez next_cursor nebo prázdná stránka. Kurzor nikdy neskládejte sami.

Lists return {"data": [...], "next_cursor": "..."}. The libraries walk the pages themselves – all items at once, or page by page; the end is a page without next_cursor or an empty page. Never build a cursor yourself.

# další stránka jen s next_cursor z předchozí odpovědi; kurzor nikdy neskládejte sami
curl "https://api.mujprofirest.cz/v2/restaurants/123/staff?limit=50" -H "Authorization: Bearer $ACCESS_TOKEN"
curl "https://api.mujprofirest.cz/v2/restaurants/123/staff?limit=50&cursor=$NEXT_CURSOR" -H "Authorization: Bearer $ACCESS_TOKEN"
# the next page only with next_cursor from the previous answer; never build a cursor yourself
curl "https://api.mujprofirest.cz/v2/restaurants/123/staff?limit=50" -H "Authorization: Bearer $ACCESS_TOKEN"
curl "https://api.mujprofirest.cz/v2/restaurants/123/staff?limit=50&cursor=$NEXT_CURSOR" -H "Authorization: Bearer $ACCESS_TOKEN"
const staff = await api.all('/restaurants/123/staff');               // všechny položky všech stránek
for await (const page of api.pages('/restaurants/123/staff', { query: { limit: 50 } })) {   // nebo stránku po stránce
  render(page.data);
}
const staff = await api.all('/restaurants/123/staff');               // all items of all pages
for await (const page of api.pages('/restaurants/123/staff', { query: { limit: 50 } })) {   // or page by page
  render(page.data);
}
const staff = await api.all(`/restaurants/${rid}/staff`);            // StaffMember[] – všechny položky všech stránek
for await (const page of api.pages(`/restaurants/${rid}/staff`, { query: { limit: 50 } })) {   // nebo stránku po stránce
  render(page.data);                                                   // StaffMemberPage
}
const staff = await api.all(`/restaurants/${rid}/staff`);            // StaffMember[] – all items of all pages
for await (const page of api.pages(`/restaurants/${rid}/staff`, { query: { limit: 50 } })) {   // or page by page
  render(page.data);                                                   // StaffMemberPage
}
$staff = $api->all('/restaurants/123/staff');                       // všechny položky všech stránek
foreach ($api->pages('/restaurants/123/staff', ['query' => ['limit' => 50]]) as $page) {   // nebo stránku po stránce
    render($page['data']);
}
$staff = $api->all('/restaurants/123/staff');                       // all items of all pages
foreach ($api->pages('/restaurants/123/staff', ['query' => ['limit' => 50]]) as $page) {   // or page by page
    render($page['data']);
}
List<StaffMember> staff = api.all("/restaurants/123/staff", null, StaffMember::fromJson);   // všechny položky všech stránek
for (StaffMemberPage page : api.pages("/restaurants/123/staff",
        RequestOptions.builder().query("limit", 50).build(), StaffMemberPage::fromJson)) {      // nebo stránku po stránce
    render(page.data);
}
List<StaffMember> staff = api.all("/restaurants/123/staff", null, StaffMember::fromJson);   // all items of all pages
for (StaffMemberPage page : api.pages("/restaurants/123/staff",
        RequestOptions.builder().query("limit", 50).build(), StaffMemberPage::fromJson)) {      // or page by page
    render(page.data);
}
val staff = api.all("/restaurants/123/staff", null, StaffMember::fromJson)                  // všechny položky všech stránek
for (page in api.pages("/restaurants/123/staff", RequestOptions.builder().query("limit", 50).build(),
        StaffMemberPage::fromJson)) {                                                           // nebo stránku po stránce
    render(page.data)
}
val staff = api.all("/restaurants/123/staff", null, StaffMember::fromJson)                  // all items of all pages
for (page in api.pages("/restaurants/123/staff", RequestOptions.builder().query("limit", 50).build(),
        StaffMemberPage::fromJson)) {                                                           // or page by page
    render(page.data)
}
List<StaffMember> staff = await api.AllAsync<StaffMember>("/restaurants/123/staff");        // všechny položky všech stránek
await foreach (StaffMemberPage page in api.PagesAsync<StaffMemberPage>("/restaurants/123/staff"))   // nebo stránku po stránce
{
    Render(page.Data);
}
List<StaffMember> staff = await api.AllAsync<StaffMember>("/restaurants/123/staff");        // all items of all pages
await foreach (StaffMemberPage page in api.PagesAsync<StaffMemberPage>("/restaurants/123/staff"))   // or page by page
{
    Render(page.Data);
}
staff = api.all('/restaurants/123/staff')                              # všechny položky všech stránek
for page in api.pages('/restaurants/123/staff', {'limit': 50}):        # nebo stránku po stránce
    render(page['data'])
staff = api.all('/restaurants/123/staff')                              # all items of all pages
for page in api.pages('/restaurants/123/staff', {'limit': 50}):        # or page by page
    render(page['data'])
let staff: [StaffMember] = try await api.all("/restaurants/123/staff")           // všechny položky všech stránek
for try await page in api.pages("/restaurants/123/staff", as: StaffMemberPage.self) {   // nebo stránku po stránce
    render(page.data)
}
let staff: [StaffMember] = try await api.all("/restaurants/123/staff")           // all items of all pages
for try await page in api.pages("/restaurants/123/staff", as: StaffMemberPage.self) {   // or page by page
    render(page.data)
}
final staff = await api.all('/restaurants/123/staff');                         // všechny položky všech stránek
await for (final page in api.pages('/restaurants/123/staff', query: {'limit': '50'})) {   // nebo stránku po stránce
  render(page['data']);
}
final staff = await api.all('/restaurants/123/staff');                         // all items of all pages
await for (final page in api.pages('/restaurants/123/staff', query: {'limit': '50'})) {   // or page by page
  render(page['data']);
}
staff, err := profirest.All[model.StaffMember](ctx, api, "/restaurants/123/staff", nil) // všechny položky všech stránek
for page, err := range api.Pages(ctx, "/restaurants/123/staff", &profirest.RequestOptions{Query: map[string]any{"limit": 50}}) { // nebo stránku po stránce
	if err != nil {
		return err
	}
	render(page.Data)
}
staff, err := profirest.All[model.StaffMember](ctx, api, "/restaurants/123/staff", nil) // all items of all pages
for page, err := range api.Pages(ctx, "/restaurants/123/staff", &profirest.RequestOptions{Query: map[string]any{"limit": 50}}) { // or page by page
	if err != nil {
		return err
	}
	render(page.Data)
}

Základy

Basics

Proud událostí

The event feed

GET /events vrací změny v pořadí, v jakém nastaly; next_cursor tu nikdy není null. Tytéž události posílá živě GET /events/stream (Server-Sent Events) – bez dotazování, se stejným kurzorem v id každé zprávy; když proud neběží (503, stream_url je null), čte se GET /events. Knihovny (watchEvents) mezi nimi přepínají samy: čtou proud, a když neběží, ptají se GET /events a o proud se pokusí znovu za Retry-After. Čtou dokola a kurzor uloží až po zpracování událostí – nic se tak neztratí, jen může přijít podruhé.

GET /events returns the changes in the order they happened; next_cursor is never null here. GET /events/stream (Server-Sent Events) sends the same events live – without polling, with the same cursor in the id of every message; when the stream is not running (503, stream_url is null), read GET /events. The libraries (watchEvents) switch between them by themselves: they read the stream, and when it does not run they ask GET /events and try the stream again after Retry-After. They read in a loop and store the cursor only after processing the events – nothing gets lost, an event may only come twice.

# bez kurzoru vrátí next_cursor na aktuálním konci; pak se ptejte s ním a ukládejte nový
curl "https://api.mujprofirest.cz/v2/events?restaurant_id=123" -H "Authorization: Bearer $ACCESS_TOKEN"
curl "https://api.mujprofirest.cz/v2/events?restaurant_id=123&cursor=$CURSOR" -H "Authorization: Bearer $ACCESS_TOKEN"
# živě (SSE): id každé zprávy je kurzor; po výpadku pokračujte s posledním v Last-Event-ID
curl -N "https://api.mujprofirest.cz/v2/events/stream?restaurant_id=123" -H "Authorization: Bearer $ACCESS_TOKEN" -H "Last-Event-ID: $CURSOR"
# without a cursor it returns next_cursor at the current end; then ask with it and store the new one
curl "https://api.mujprofirest.cz/v2/events?restaurant_id=123" -H "Authorization: Bearer $ACCESS_TOKEN"
curl "https://api.mujprofirest.cz/v2/events?restaurant_id=123&cursor=$CURSOR" -H "Authorization: Bearer $ACCESS_TOKEN"
# live (SSE): the id of every message is the cursor; after a disconnection continue with the last one in Last-Event-ID
curl -N "https://api.mujprofirest.cz/v2/events/stream?restaurant_id=123" -H "Authorization: Bearer $ACCESS_TOKEN" -H "Last-Event-ID: $CURSOR"
const feed = api.watchEvents({
  restaurantId: '123',
  onEvents: async (events) => {
    for (const event of events) handle(event);   // kurzor se uloží až po zpracování; neznámé typy přeskočte
  },
  onReset: () => reloadEverything(),             // 410 cursor_expired: načtěte stav znovu
});
feed.stop();                                     // čtení ukončí
const feed = api.watchEvents({
  restaurantId: '123',
  onEvents: async (events) => {
    for (const event of events) handle(event);   // the cursor is stored only after processing; skip unknown types
  },
  onReset: () => reloadEverything(),             // 410 cursor_expired: reload the state
});
feed.stop();                                     // ends the reading
const feed = api.watchEvents({
  restaurantId: '123',
  onEvents: async (events) => {                  // ProfirestApi.Models.Event[]
    for (const event of events) handle(event);   // kurzor se uloží až po zpracování; neznámé typy přeskočte
  },
  onReset: () => reloadEverything(),             // 410 cursor_expired: načtěte stav znovu
});
feed.stop();                                     // čtení ukončí
const feed = api.watchEvents({
  restaurantId: '123',
  onEvents: async (events) => {                  // ProfirestApi.Models.Event[]
    for (const event of events) handle(event);   // the cursor is stored only after processing; skip unknown types
  },
  onReset: () => reloadEverything(),             // 410 cursor_expired: reload the state
});
feed.stop();                                     // ends the reading
$watcher = $api->watchEvents([
    'restaurantId' => '123',
    'onEvents' => function (array $events): void {
        foreach ($events as $event) { handle($event); }   // kurzor se uloží až po zpracování; neznámé typy přeskočte
    },
    'onReset' => fn() => reloadEverything(),             // 410 cursor_expired: načtěte stav znovu
]);
$watcher->run();     // $watcher->stop() čtení ukončí; cron: $watcher->once()
$watcher = $api->watchEvents([
    'restaurantId' => '123',
    'onEvents' => function (array $events): void {
        foreach ($events as $event) { handle($event); }   // the cursor is stored only after processing; skip unknown types
    },
    'onReset' => fn() => reloadEverything(),             // 410 cursor_expired: reload the state
]);
$watcher->run();     // $watcher->stop() ends the reading; cron: $watcher->once()
EventWatcher feed = api.watchEvents(WatchOptions.builder()
        .restaurantId("123")
        .onEvents(events -> events.forEach(this::handle))   // kurzor se uloží až po zpracování; neznámé typy přeskočte
        .onReset(error -> reloadEverything())               // 410 cursor_expired: načtěte stav znovu
        .build());
feed.start();
feed.stop();                                                // čtení ukončí
EventWatcher feed = api.watchEvents(WatchOptions.builder()
        .restaurantId("123")
        .onEvents(events -> events.forEach(this::handle))   // the cursor is stored only after processing; skip unknown types
        .onReset(error -> reloadEverything())               // 410 cursor_expired: reload the state
        .build());
feed.start();
feed.stop();                                                // ends the reading
val feed = api.watchEvents(WatchOptions.builder()
    .restaurantId("123")
    .onEvents { events -> events.forEach { handle(it) } }   // kurzor se uloží až po zpracování; neznámé typy přeskočte
    .onReset { reloadEverything() }                          // 410 cursor_expired: načtěte stav znovu
    .build())
feed.start()
feed.stop()                                                  // čtení ukončí
val feed = api.watchEvents(WatchOptions.builder()
    .restaurantId("123")
    .onEvents { events -> events.forEach { handle(it) } }   // the cursor is stored only after processing; skip unknown types
    .onReset { reloadEverything() }                          // 410 cursor_expired: reload the state
    .build())
feed.start()
feed.stop()                                                  // ends the reading
await api.WatchEventsAsync(new WatchOptions
{
    RestaurantId = "123",
    OnEvents = async (events, ct) => { foreach (var e in events) await HandleAsync(e, ct); },   // kurzor se uloží až po zpracování; neznámé typy přeskočte
    OnReset = _ => ReloadEverythingAsync(),                                                    // 410 cursor_expired: načtěte stav znovu
}, stoppingToken);                                                                             // čtení ukončí: stoppingToken
await api.WatchEventsAsync(new WatchOptions
{
    RestaurantId = "123",
    OnEvents = async (events, ct) => { foreach (var e in events) await HandleAsync(e, ct); },   // the cursor is stored only after processing; skip unknown types
    OnReset = _ => ReloadEverythingAsync(),                                                    // 410 cursor_expired: reload the state
}, stoppingToken);                                                                             // ends the reading: stoppingToken
feed = api.watch_events(
    lambda events: [handle(e) for e in events],    # kurzor se uloží až po zpracování; neznámé typy přeskočte
    restaurant_id='123',
    on_reset=lambda error: reload_everything(),    # 410 cursor_expired: načtěte stav znovu
)
feed.start()
feed.stop()                                        # čtení ukončí
feed = api.watch_events(
    lambda events: [handle(e) for e in events],    # the cursor is stored only after processing; skip unknown types
    restaurant_id='123',
    on_reset=lambda error: reload_everything(),    # 410 cursor_expired: reload the state
)
feed.start()
feed.stop()                                        # ends the reading
let feed = api.watchEvents(.init(
    restaurantID: "123",
    onEvents: { events in for event in events { handle(event) } },   // kurzor se uloží až po zpracování; neznámé typy přeskočte
    onReset: { _ in reloadEverything() }                               // 410 cursor_expired: načtěte stav znovu
))
feed.cancel()                                                          // čtení ukončí
let feed = api.watchEvents(.init(
    restaurantID: "123",
    onEvents: { events in for event in events { handle(event) } },   // the cursor is stored only after processing; skip unknown types
    onReset: { _ in reloadEverything() }                               // 410 cursor_expired: reload the state
))
feed.cancel()                                                          // ends the reading
final feed = api.watchEvents(
  restaurantId: '123',
  onEvents: (events) async { for (final e in events) handle(e); },   // kurzor se uloží až po zpracování; neznámé typy přeskočte
  onReset: (error) => reloadEverything(),                           // 410 cursor_expired: načtěte stav znovu
)..start();
feed.stop();                                                        // čtení ukončí
final feed = api.watchEvents(
  restaurantId: '123',
  onEvents: (events) async { for (final e in events) handle(e); },   // the cursor is stored only after processing; skip unknown types
  onReset: (error) => reloadEverything(),                           // 410 cursor_expired: reload the state
)..start();
feed.stop();                                                        // ends the reading
ctx, stop := context.WithCancel(ctx)
err := api.WatchEvents(ctx, profirest.WatchOptions{
	RestaurantID: "123",
	OnEvents: func(ctx context.Context, events []model.Event) error {
		for _, e := range events {
			handle(e) // kurzor se uloží až po zpracování; neznámé typy přeskočte
		}
		return nil
	},
	OnReset: func(*profirest.APIError) { reloadEverything() }, // 410 cursor_expired: načtěte stav znovu
})
stop() // čtení ukončí
ctx, stop := context.WithCancel(ctx)
err := api.WatchEvents(ctx, profirest.WatchOptions{
	RestaurantID: "123",
	OnEvents: func(ctx context.Context, events []model.Event) error {
		for _, e := range events {
			handle(e) // the cursor is stored only after processing; skip unknown types
		}
		return nil
	},
	OnReset: func(*profirest.APIError) { reloadEverything() }, // 410 cursor_expired: reload the state
})
stop() // ends the reading

Scénář

Scenario

Objednávka z e-shopu

An order from an e-shop

Partner s vlastním serveremA partner with its own server

Aplikace partnera připojí restauraci, ukáže sortiment, spočítá košík a založí objednávku zaplacenou online. Ceny, dopravu i DPH počítá vždy server – aplikace je jen ukazuje. Tržbu do EET 2.0 eviduje Profirest sám (online platba se neeviduje, hotovost a karta kurýrovi při předání) – aplikace finanční správě nic neposílá.

A partner application connects a restaurant, shows the catalog, prices the basket and creates an order paid online. The server always computes prices, delivery and VAT – the application only shows them. Profirest records the sale in EET 2.0 itself (an online payment is not recorded, cash and card to the courier at the hand-over) – the application sends nothing to the tax administration.

  1. Pošlete majitele na souhlas

    Send the owner to the consent page

    GET /oauth/authorize · oauthAuthorize

    Přesměrujte prohlížeč na /oauth/authorize s PKCE (code_challenge = BASE64URL(SHA-256(code_verifier))) a náhodným state. Majitel vybere provozovny a potvrdí oprávnění; vrátí se na redirect_uri s code, state a iss. Ověřte state i iss.

    Redirect the browser to /oauth/authorize with PKCE (code_challenge = BASE64URL(SHA-256(code_verifier))) and a random state. The owner picks the restaurants and grants the scopes; the browser returns to redirect_uri with code, state and iss. Check both state and iss.

    Souhlas „Připojit přes Profirest“: majitel vybere provozovny a povolí, co aplikace smí.
    Souhlas „Připojit přes Profirest“: majitel vybere provozovny a povolí, co aplikace smí.The “Connect via Profirest” consent: the owner picks the restaurants and grants the scopes.
    # souhlas běží v prohlížeči majitele: adresu otevřete, nevolejte ji z kódu
    CODE_VERIFIER=$(openssl rand -base64 48 | tr '+/' '-_' | tr -d '=\n')
    CODE_CHALLENGE=$(printf '%s' "$CODE_VERIFIER" | openssl dgst -sha256 -binary | openssl base64 | tr '+/' '-_' | tr -d '=')
    echo "https://api.mujprofirest.cz/oauth/authorize?response_type=code&client_id=eshop-u-lipy&redirect_uri=https%3A%2F%2Fshop.example%2Fcallback&scope=restaurants%3Aread%20catalog%3Aread%20orders%3Awrite%20orders%3Aread&state=$(openssl rand -hex 16)&code_challenge=$CODE_CHALLENGE&code_challenge_method=S256"
    # consent runs in the owner's browser: open the address, do not call it from code
    CODE_VERIFIER=$(openssl rand -base64 48 | tr '+/' '-_' | tr -d '=\n')
    CODE_CHALLENGE=$(printf '%s' "$CODE_VERIFIER" | openssl dgst -sha256 -binary | openssl base64 | tr '+/' '-_' | tr -d '=')
    echo "https://api.mujprofirest.cz/oauth/authorize?response_type=code&client_id=eshop-u-lipy&redirect_uri=https%3A%2F%2Fshop.example%2Fcallback&scope=restaurants%3Aread%20catalog%3Aread%20orders%3Awrite%20orders%3Aread&state=$(openssl rand -hex 16)&code_challenge=$CODE_CHALLENGE&code_challenge_method=S256"
    // klient: viz /v2/docs/js
    // PKCE a state hlídá knihovna
    location.href = await api.authorizationUrl({
      redirectUri: 'https://shop.example/callback',
      scope: 'restaurants:read catalog:read orders:write orders:read',
    });
    // na redirect_uri:
    const connection = await api.completeAuthorization();
    // the client: see /v2/docs/js
    // the library handles PKCE and state
    location.href = await api.authorizationUrl({
      redirectUri: 'https://shop.example/callback',
      scope: 'restaurants:read catalog:read orders:write orders:read',
    });
    // on the redirect_uri:
    const connection = await api.completeAuthorization();
    // klient: viz /v2/docs/typescript
    // PKCE a state hlídá knihovna
    location.href = await api.authorizationUrl({
      redirectUri: 'https://shop.example/callback',
      scope: 'restaurants:read catalog:read orders:write orders:read',
    });
    // na redirect_uri:
    const connection = await api.completeAuthorization();
    // the client: see /v2/docs/typescript
    // the library handles PKCE and state
    location.href = await api.authorizationUrl({
      redirectUri: 'https://shop.example/callback',
      scope: 'restaurants:read catalog:read orders:write orders:read',
    });
    // on the redirect_uri:
    const connection = await api.completeAuthorization();
    // klient: viz /v2/docs/php
    // PKCE a state hlídá knihovna
    header('Location: ' . $api->authorizationUrl('https://shop.example/callback', 'restaurants:read catalog:read orders:write orders:read'));
    // na redirect_uri:
    $connection = $api->completeAuthorization($_GET);
    // the client: see /v2/docs/php
    // the library handles PKCE and state
    header('Location: ' . $api->authorizationUrl('https://shop.example/callback', 'restaurants:read catalog:read orders:write orders:read'));
    // on the redirect_uri:
    $connection = $api->completeAuthorization($_GET);
    // klient: viz /v2/docs/java
    // volání blokuje – na Androidu z pracovního vlákna (Dispatchers.IO)
    // PKCE a state hlídá knihovna
    response.sendRedirect(api.authorizationUrl("https://shop.example/callback", "restaurants:read catalog:read orders:write orders:read"));
    // na redirect_uri:
    Map<String, Object> connection = api.completeAuthorization(request.getRequestURL() + "?" + request.getQueryString());
    // the client: see /v2/docs/java
    // the call blocks – on Android from a worker thread (Dispatchers.IO)
    // the library handles PKCE and state
    response.sendRedirect(api.authorizationUrl("https://shop.example/callback", "restaurants:read catalog:read orders:write orders:read"));
    // on the redirect_uri:
    Map<String, Object> connection = api.completeAuthorization(request.getRequestURL() + "?" + request.getQueryString());
    // klient: viz /v2/docs/java
    // volání blokuje – na Androidu z pracovního vlákna (Dispatchers.IO)
    // PKCE a state hlídá knihovna
    val url = api.authorizationUrl("https://shop.example/callback", "restaurants:read catalog:read orders:write orders:read")
    // na redirect_uri:
    val connection = api.completeAuthorization(callbackUrl)
    // the client: see /v2/docs/java
    // the call blocks – on Android from a worker thread (Dispatchers.IO)
    // the library handles PKCE and state
    val url = api.authorizationUrl("https://shop.example/callback", "restaurants:read catalog:read orders:write orders:read")
    // on the redirect_uri:
    val connection = api.completeAuthorization(callbackUrl)
    // klient: viz /v2/docs/csharp
    // PKCE a state hlídá knihovna
    var url = api.AuthorizationUrl(new AuthorizationOptions
    {
        RedirectUri = "https://shop.example/callback",
        Scope = "restaurants:read catalog:read orders:write orders:read",
    });
    // na redirect_uri:
    Connection? connection = await api.CompleteAuthorizationAsync(callbackUrl);
    // the client: see /v2/docs/csharp
    // the library handles PKCE and state
    var url = api.AuthorizationUrl(new AuthorizationOptions
    {
        RedirectUri = "https://shop.example/callback",
        Scope = "restaurants:read catalog:read orders:write orders:read",
    });
    // on the redirect_uri:
    Connection? connection = await api.CompleteAuthorizationAsync(callbackUrl);
    # klient: viz /v2/docs/python
    # PKCE a state hlídá knihovna
    url = api.authorization_url(redirect_uri='https://shop.example/callback', scope='restaurants:read catalog:read orders:write orders:read')
    # na redirect_uri:
    connection = api.complete_authorization(request.url)
    # the client: see /v2/docs/python
    # the library handles PKCE and state
    url = api.authorization_url(redirect_uri='https://shop.example/callback', scope='restaurants:read catalog:read orders:write orders:read')
    # on the redirect_uri:
    connection = api.complete_authorization(request.url)
    // klient: viz /v2/docs/swift
    // PKCE a state hlídá knihovna
    let url = try api.authorizationURL(redirectURI: "profirest-shop://callback", scope: "restaurants:read catalog:read orders:write orders:read")
    // na redirect_uri: (ASWebAuthenticationSession)
    let connection = try await api.completeAuthorization(callbackURL)
    // the client: see /v2/docs/swift
    // the library handles PKCE and state
    let url = try api.authorizationURL(redirectURI: "profirest-shop://callback", scope: "restaurants:read catalog:read orders:write orders:read")
    // on the redirect_uri: (ASWebAuthenticationSession)
    let connection = try await api.completeAuthorization(callbackURL)
    // klient: viz /v2/docs/dart
    // PKCE a state hlídá knihovna
    final url = await api.authorizationUrl(redirectUri: 'https://shop.example/callback', scope: 'restaurants:read catalog:read orders:write orders:read');
    // na redirect_uri:
    final connection = await api.completeAuthorization(callbackUrl);
    // the client: see /v2/docs/dart
    // the library handles PKCE and state
    final url = await api.authorizationUrl(redirectUri: 'https://shop.example/callback', scope: 'restaurants:read catalog:read orders:write orders:read');
    // on the redirect_uri:
    final connection = await api.completeAuthorization(callbackUrl);
    // klient: viz /v2/docs/go
    // PKCE a state hlídá knihovna
    url, err := api.AuthorizationURL(profirest.AuthorizationOptions{
    	RedirectURI: "https://shop.example/callback",
    	Scope:       "restaurants:read catalog:read orders:write orders:read",
    })
    // na redirect_uri:
    connection, err := api.CompleteAuthorization(ctx, r.URL.String())
    // the client: see /v2/docs/go
    // the library handles PKCE and state
    url, err := api.AuthorizationURL(profirest.AuthorizationOptions{
    	RedirectURI: "https://shop.example/callback",
    	Scope:       "restaurants:read catalog:read orders:write orders:read",
    })
    // on the redirect_uri:
    connection, err := api.CompleteAuthorization(ctx, r.URL.String())
  2. Vyměňte kód za tokeny

    Exchange the code for tokens

    POST /oauth/token · oauthToken

    Na serveru, s tajemstvím klienta. Access token platí 30 minut, refresh token 90 dní od posledního použití; každá obnova (grant_type=refresh_token) vrátí nový refresh token. Tokeny ukládejte ke každému připojenému účtu zvlášť – v knihovnách vlastní instance s vlastním klíčem úložiště odvozeným z ID účtu ve vašem systému; výchozí klíč je jeden pro celou aplikaci a další připojení by přepsalo předchozí.

    On your server, with the client secret. The access token lives 30 minutes, the refresh token 90 days since its last use; every refresh (grant_type=refresh_token) returns a new refresh token. Store the tokens separately for every connected account – in the libraries a separate instance with its own storage key derived from the account ID in your system; the default key is one for the whole application and the next connection would overwrite the previous one.

    curl "https://api.mujprofirest.cz/oauth/token" \
      -u "$CLIENT_ID:$CLIENT_SECRET" \
      -d grant_type=authorization_code \
      -d code=pfc_VpTQii5T_8rgwxA-Wtb2B2q9lg6x-KVldwQLwQKPcCs \
      -d redirect_uri=https://shop.example/callback \
      -d code_verifier=dBjftJeZ4CVP-mB92K27uhbUJU1p1r_wW1gFWFOEjXk
    curl "https://api.mujprofirest.cz/oauth/token" \
      -u "$CLIENT_ID:$CLIENT_SECRET" \
      -d grant_type=authorization_code \
      -d code=pfc_VpTQii5T_8rgwxA-Wtb2B2q9lg6x-KVldwQLwQKPcCs \
      -d redirect_uri=https://shop.example/callback \
      -d code_verifier=dBjftJeZ4CVP-mB92K27uhbUJU1p1r_wW1gFWFOEjXk
    // klient: viz /v2/docs/js
    // tokeny vyzvedne a obnovuje knihovna sama (párování nebo dokončení souhlasu); obnova minutu před koncem, jen jednou
    const connection = await api.connection();
    // the client: see /v2/docs/js
    // the library picks up and refreshes the tokens itself (pairing or completing the consent); refreshed a minute early, once
    const connection = await api.connection();
    // klient: viz /v2/docs/typescript
    // tokeny vyzvedne a obnovuje knihovna sama (párování nebo dokončení souhlasu); obnova minutu před koncem, jen jednou
    const connection = await api.connection();
    // the client: see /v2/docs/typescript
    // the library picks up and refreshes the tokens itself (pairing or completing the consent); refreshed a minute early, once
    const connection = await api.connection();
    // klient: viz /v2/docs/php
    // tokeny vyzvedne a obnovuje knihovna sama (párování nebo dokončení souhlasu); obnova minutu před koncem, jen jednou
    $connection = $api->connection();
    // the client: see /v2/docs/php
    // the library picks up and refreshes the tokens itself (pairing or completing the consent); refreshed a minute early, once
    $connection = $api->connection();
    // klient: viz /v2/docs/java
    // volání blokuje – na Androidu z pracovního vlákna (Dispatchers.IO)
    // tokeny vyzvedne a obnovuje knihovna sama (párování nebo dokončení souhlasu); obnova minutu před koncem, jen jednou
    Map<String, Object> connection = api.connection();
    // the client: see /v2/docs/java
    // the call blocks – on Android from a worker thread (Dispatchers.IO)
    // the library picks up and refreshes the tokens itself (pairing or completing the consent); refreshed a minute early, once
    Map<String, Object> connection = api.connection();
    // klient: viz /v2/docs/java
    // volání blokuje – na Androidu z pracovního vlákna (Dispatchers.IO)
    // tokeny vyzvedne a obnovuje knihovna sama (párování nebo dokončení souhlasu); obnova minutu před koncem, jen jednou
    val connection = api.connection()
    // the client: see /v2/docs/java
    // the call blocks – on Android from a worker thread (Dispatchers.IO)
    // the library picks up and refreshes the tokens itself (pairing or completing the consent); refreshed a minute early, once
    val connection = api.connection()
    // klient: viz /v2/docs/csharp
    // tokeny vyzvedne a obnovuje knihovna sama (párování nebo dokončení souhlasu); obnova minutu před koncem, jen jednou
    Connection? connection = await api.ConnectionAsync();
    // the client: see /v2/docs/csharp
    // the library picks up and refreshes the tokens itself (pairing or completing the consent); refreshed a minute early, once
    Connection? connection = await api.ConnectionAsync();
    # klient: viz /v2/docs/python
    # tokeny vyzvedne a obnovuje knihovna sama (párování nebo dokončení souhlasu); obnova minutu před koncem, jen jednou
    connection = api.connection()
    # the client: see /v2/docs/python
    # the library picks up and refreshes the tokens itself (pairing or completing the consent); refreshed a minute early, once
    connection = api.connection()
    // klient: viz /v2/docs/swift
    // tokeny vyzvedne a obnovuje knihovna sama (párování nebo dokončení souhlasu); obnova minutu před koncem, jen jednou
    let connection = try await api.connection()
    // the client: see /v2/docs/swift
    // the library picks up and refreshes the tokens itself (pairing or completing the consent); refreshed a minute early, once
    let connection = try await api.connection()
    // klient: viz /v2/docs/dart
    // tokeny vyzvedne a obnovuje knihovna sama (párování nebo dokončení souhlasu); obnova minutu před koncem, jen jednou
    final connection = await api.connection();
    // the client: see /v2/docs/dart
    // the library picks up and refreshes the tokens itself (pairing or completing the consent); refreshed a minute early, once
    final connection = await api.connection();
    // klient: viz /v2/docs/go
    // tokeny vyzvedne a obnovuje knihovna sama (párování nebo dokončení souhlasu); obnova minutu před koncem, jen jednou
    connection, err := api.Connection(ctx)
    // the client: see /v2/docs/go
    // the library picks up and refreshes the tokens itself (pairing or completing the consent); refreshed a minute early, once
    connection, err := api.Connection(ctx)
    Příklad odpovědi 200Example answer 200
    {
      "access_token": "pfa_oFYf1knNtrqnhAVfBRuteW6gr-8X_KOCGVSd7rpOjBo",
      "token_type": "Bearer",
      "expires_in": 1800,
      "refresh_token": "pfr_1swKCIwHaDxlzSZoYMq42Us6GTexdCDZ2jDKKZwJ-3c",
      "refresh_token_expires_in": 7776000,
      "scope": "restaurants:read catalog:read orders:write orders:read"
    }
  3. Zjistěte provozovny

    Find the restaurants

    GET /restaurants · listRestaurants

    Jen ty, které majitel připojení svěřil. ordering říká, jestli provozovna právě přijímá objednávky.

    Only those the owner granted to the connection. ordering tells whether the restaurant takes orders right now.

    Integrace › Připojené aplikace: provozovny, oprávnění a kdo píše zákazníkům – majitel je může kdykoli změnit nebo připojení zrušit.
    Integrace › Připojené aplikace: provozovny, oprávnění a kdo píše zákazníkům – majitel je může kdykoli změnit nebo připojení zrušit.Integrations › Connected applications: restaurants, scopes and who messages the customers – the owner can change them or revoke the connection at any time.
    curl "https://api.mujprofirest.cz/v2/restaurants?limit=20" \
      -H "Authorization: Bearer $ACCESS_TOKEN"
    curl "https://api.mujprofirest.cz/v2/restaurants?limit=20" \
      -H "Authorization: Bearer $ACCESS_TOKEN"
    // klient: viz /v2/docs/js
    const { data, next_cursor } = await api.get('/restaurants', { query: { limit: 20 } }); // 200
    // the client: see /v2/docs/js
    const { data, next_cursor } = await api.get('/restaurants', { query: { limit: 20 } }); // 200
    // klient: viz /v2/docs/typescript
    const { data, next_cursor } = await api.get('/restaurants', { query: { limit: 20 } }); // 200 RestaurantPage
    // the client: see /v2/docs/typescript
    const { data, next_cursor } = await api.get('/restaurants', { query: { limit: 20 } }); // 200 RestaurantPage
    // klient: viz /v2/docs/php
    $page = $api->get('/restaurants', ['query' => ['limit' => 20]]); // $page['data'], $page['next_cursor']
    // the client: see /v2/docs/php
    $page = $api->get('/restaurants', ['query' => ['limit' => 20]]); // $page['data'], $page['next_cursor']
    // klient: viz /v2/docs/java
    // volání blokuje – na Androidu z pracovního vlákna (Dispatchers.IO)
    RestaurantPage listRestaurants = api.get(
        "/restaurants",
        RequestOptions.builder().query("limit", "20").build(),
        RestaurantPage::fromJson
    ); // 200
    // the client: see /v2/docs/java
    // the call blocks – on Android from a worker thread (Dispatchers.IO)
    RestaurantPage listRestaurants = api.get(
        "/restaurants",
        RequestOptions.builder().query("limit", "20").build(),
        RestaurantPage::fromJson
    ); // 200
    // klient: viz /v2/docs/java
    // volání blokuje – na Androidu z pracovního vlákna (Dispatchers.IO)
    val listRestaurants = api.get(
        "/restaurants",
        RequestOptions.builder().query("limit", "20").build(),
        RestaurantPage::fromJson,
    ) // 200
    // the client: see /v2/docs/java
    // the call blocks – on Android from a worker thread (Dispatchers.IO)
    val listRestaurants = api.get(
        "/restaurants",
        RequestOptions.builder().query("limit", "20").build(),
        RestaurantPage::fromJson,
    ) // 200
    // klient: viz /v2/docs/csharp
    var listRestaurants = await api.GetAsync<RestaurantPage>(
        "/restaurants",
        new RequestOptions { Query = new() { ["limit"] = "20" } }
    ); // 200
    // the client: see /v2/docs/csharp
    var listRestaurants = await api.GetAsync<RestaurantPage>(
        "/restaurants",
        new RequestOptions { Query = new() { ["limit"] = "20" } }
    ); // 200
    # klient: viz /v2/docs/python
    page = api.get('/restaurants', query={'limit': 20})  # page['data'], page['next_cursor']
    # the client: see /v2/docs/python
    page = api.get('/restaurants', query={'limit': 20})  # page['data'], page['next_cursor']
    // klient: viz /v2/docs/swift
    let listRestaurants: RestaurantPage = try await api.get("/restaurants", options: .init(query: ["limit": "20"])) // 200
    // the client: see /v2/docs/swift
    let listRestaurants: RestaurantPage = try await api.get("/restaurants", options: .init(query: ["limit": "20"])) // 200
    // klient: viz /v2/docs/dart
    final listRestaurants = pr.RestaurantPage.fromJson(await api.get('/restaurants', query: {'limit': '20'})); // 200
    // the client: see /v2/docs/dart
    final listRestaurants = pr.RestaurantPage.fromJson(await api.get('/restaurants', query: {'limit': '20'})); // 200
    // klient: viz /v2/docs/go
    res, err := api.Get(ctx, "/restaurants", &profirest.RequestOptions{Query: map[string]any{"limit": "20"}})
    var listRestaurants model.RestaurantPage // 200
    if err == nil {
    	err = res.Decode(&listRestaurants)
    }
    // the client: see /v2/docs/go
    res, err := api.Get(ctx, "/restaurants", &profirest.RequestOptions{Query: map[string]any{"limit": "20"}})
    var listRestaurants model.RestaurantPage // 200
    if err == nil {
    	err = res.Decode(&listRestaurants)
    }
    Příklad odpovědi 200Example answer 200
    {
      "data": [
        {
          "id": "123",
          "name": "Bistro U Lípy",
          "is_test": false,
          "address": {
            "street": "Vinohradská",
            "house_number": "1200/48",
            "city": "Praha 2",
            "postal_code": "120 00",
            "country": "CZ",
            "note": null,
            "formatted": "Vinohradská 1200/48, 120 00 Praha 2"
          },
          "location": {
            "lat": 50.0769,
            "lon": 14.4459
          },
          "phone": "+420222333444",
          "website": "https://www.bistroulipy.cz",
          "timezone": "Europe/Prague",
          "currency": "CZK",
          "ordering": {
            "accepting_orders": true,
            "open_now": true,
            "venue_open_now": true,
            "next_change_at": "2027-01-15T22:00:00+01:00",
            "delivery": {
              "enabled": true,
              "available_now": true
            },
            "pickup": {
              "enabled": true,
              "available_now": true
            },
            "scheduled_orders": {
              "enabled": true,
              "max_days_ahead": 7,
              "slot_minutes": 15,
              "lead_minutes": 90
            }
          },
          "portion_tracking": true,
          "external_id": "vinohrady",
          "metadata": {
            "branch": "praha-2"
          }
        },
        {
          "id": "124",
          "name": "Bistro U Lípy Karlín",
          "is_test": false,
          "address": {
            "street": "Sokolovská",
            "house_number": "316/101",
            "city": "Praha 8",
            "postal_code": "186 00",
            "country": "CZ",
            "note": null,
            "formatted": "Sokolovská 316/101, 186 00 Praha 8"
          },
          "location": {
            "lat": 50.0927,
            "lon": 14.4521
          },
          "phone": "+420222333555",
          "website": "https://www.bistroulipy.cz",
          "timezone": "Europe/Prague",
          "currency": "CZK",
          "ordering": {
            "accepting_orders": false,
            "open_now": false,
            "venue_open_now": false,
            "next_change_at": "2027-01-15T16:00:00+01:00",
            "delivery": {
              "enabled": true,
              "available_now": false
            },
            "pickup": {
              "enabled": true,
              "available_now": false
            },
            "scheduled_orders": {
              "enabled": true,
              "max_days_ahead": 7,
              "slot_minutes": 15,
              "lead_minutes": 90
            }
          },
          "portion_tracking": false,
          "external_id": "karlin",
          "metadata": {
            "branch": "praha-8"
          }
        }
      ],
      "next_cursor": null
    }
  4. Načtěte sortiment

    Load the catalog

    GET /restaurants/{restaurant_id}/catalog · getCatalog

    Jeden snímek s kategoriemi, produkty, přílohami, denním menu a alergeny – nestránkuje se. Pošlete If-None-Match s ETagem; když se nic nezměnilo, přijde 304. Jídla ve více velikostech (pizza Ø28cm / Ø32cm / Ø42cm) jsou samostatné produkty se stejným size.group_id – ukažte je jako jednu položku s přepínačem a objednejte id zvolené velikosti. Produkt s split jde složit do pizzy z půlek nebo čtvrtek (položka type split s parts, každý díl se svými přílohami); produkt s option_groups si zákazník skládá z voleb (vlastní pizza, povinný výběr těsta) – pošlete options s option_id a počtem porcí, meze i ingredience v ceně spočítá server. Víc porcí jedné přílohy (dvojitý sýr) je add_ons[].quantity. Suroviny z removable_ingredients si host smí odebrat (bez bazalky) – ukažte je zaškrtnuté a odškrtnuté pošlete v removed_ingredient_ids položky nebo dílu; cena se nemění.

    One snapshot with categories, products, add-ons, the daily menu and allergens – not paged. Send If-None-Match with the ETag; when nothing changed you get 304. Dishes sold in several sizes (pizza Ø28cm / Ø32cm / Ø42cm) are separate products with the same size.group_id – show them as one item with a size switcher and order the id of the chosen size. A product with split can be a part of a pizza from halves or quarters (an item of type split with parts, each part with its own add-ons); a product with option_groups is composed by the customer from options (a custom pizza, a required choice of dough) – send options with option_id and portions, the server checks the limits and the included toppings. More portions of one add-on (double cheese) are add_ons[].quantity. The guest may remove ingredients from removable_ingredients (without basil) – show them ticked and send the unticked ones in removed_ingredient_ids of the item or the part; the price does not change.

    curl "https://api.mujprofirest.cz/v2/restaurants/123/catalog?channel=web" \
      -H "Authorization: Bearer $ACCESS_TOKEN"
    curl "https://api.mujprofirest.cz/v2/restaurants/123/catalog?channel=web" \
      -H "Authorization: Bearer $ACCESS_TOKEN"
    // klient: viz /v2/docs/js
    const catalog = await api.get('/restaurants/123/catalog', { query: { channel: 'web' } }); // 200
    // the client: see /v2/docs/js
    const catalog = await api.get('/restaurants/123/catalog', { query: { channel: 'web' } }); // 200
    // klient: viz /v2/docs/typescript
    const catalog = await api.get('/restaurants/123/catalog', { query: { channel: 'web' } }); // 200 Catalog
    // the client: see /v2/docs/typescript
    const catalog = await api.get('/restaurants/123/catalog', { query: { channel: 'web' } }); // 200 Catalog
    // klient: viz /v2/docs/php
    $catalog = $api->get('/restaurants/123/catalog', ['query' => ['channel' => 'web']]); // 200
    // the client: see /v2/docs/php
    $catalog = $api->get('/restaurants/123/catalog', ['query' => ['channel' => 'web']]); // 200
    // klient: viz /v2/docs/java
    // volání blokuje – na Androidu z pracovního vlákna (Dispatchers.IO)
    Catalog catalog = api.get(
        "/restaurants/123/catalog",
        RequestOptions.builder().query("channel", "web").build(),
        Catalog::fromJson
    ); // 200
    // the client: see /v2/docs/java
    // the call blocks – on Android from a worker thread (Dispatchers.IO)
    Catalog catalog = api.get(
        "/restaurants/123/catalog",
        RequestOptions.builder().query("channel", "web").build(),
        Catalog::fromJson
    ); // 200
    // klient: viz /v2/docs/java
    // volání blokuje – na Androidu z pracovního vlákna (Dispatchers.IO)
    val catalog = api.get(
        "/restaurants/123/catalog",
        RequestOptions.builder().query("channel", "web").build(),
        Catalog::fromJson,
    ) // 200
    // the client: see /v2/docs/java
    // the call blocks – on Android from a worker thread (Dispatchers.IO)
    val catalog = api.get(
        "/restaurants/123/catalog",
        RequestOptions.builder().query("channel", "web").build(),
        Catalog::fromJson,
    ) // 200
    // klient: viz /v2/docs/csharp
    var catalog = await api.GetAsync<Catalog>(
        "/restaurants/123/catalog",
        new RequestOptions { Query = new() { ["channel"] = "web" } }
    ); // 200
    // the client: see /v2/docs/csharp
    var catalog = await api.GetAsync<Catalog>(
        "/restaurants/123/catalog",
        new RequestOptions { Query = new() { ["channel"] = "web" } }
    ); // 200
    # klient: viz /v2/docs/python
    catalog = api.get('/restaurants/123/catalog', query={'channel': 'web'})  # 200
    # the client: see /v2/docs/python
    catalog = api.get('/restaurants/123/catalog', query={'channel': 'web'})  # 200
    // klient: viz /v2/docs/swift
    let catalog: Catalog = try await api.get("/restaurants/123/catalog", options: .init(query: ["channel": "web"])) // 200
    // the client: see /v2/docs/swift
    let catalog: Catalog = try await api.get("/restaurants/123/catalog", options: .init(query: ["channel": "web"])) // 200
    // klient: viz /v2/docs/dart
    final catalog = pr.Catalog.fromJson(await api.get('/restaurants/123/catalog', query: {'channel': 'web'})); // 200
    // the client: see /v2/docs/dart
    final catalog = pr.Catalog.fromJson(await api.get('/restaurants/123/catalog', query: {'channel': 'web'})); // 200
    // klient: viz /v2/docs/go
    res, err := api.Get(
    	ctx,
    	"/restaurants/123/catalog",
    	&profirest.RequestOptions{Query: map[string]any{"channel": "web"}},
    )
    var catalog model.Catalog // 200
    if err == nil {
    	err = res.Decode(&catalog)
    }
    // the client: see /v2/docs/go
    res, err := api.Get(
    	ctx,
    	"/restaurants/123/catalog",
    	&profirest.RequestOptions{Query: map[string]any{"channel": "web"}},
    )
    var catalog model.Catalog // 200
    if err == nil {
    	err = res.Decode(&catalog)
    }
    Příklad odpovědi 200Example answer 200
    {
      "restaurant_id": "123",
      "currency": "CZK",
      "at": "2027-01-15T11:42:00+01:00",
      "generated_at": "2027-01-15T11:40:00+01:00",
      "next_change_at": "2027-01-15T15:00:00+01:00",
      "categories": [
        {
          "id": "312",
          "name": "Hlavní jídla",
          "description": null,
          "image_url": null,
          "color": "#e53935",
          "icon": "fa-utensils",
          "position": 1,
          "external_id": null,
          "metadata": {}
        },
        {
          "id": "315",
          "name": "Pizza",
          "description": "Pečeme v peci na dřevo.",
          "image_url": null,
          "color": "#fb8c00",
          "icon": "fa-pizza-slice",
          "position": 2,
          "external_id": null,
          "metadata": {}
        },
        {
          "id": "320",
          "name": "Nápoje",
          "description": null,
          "image_url": null,
          "color": "#1e88e5",
          "icon": null,
          "position": 3,
          "external_id": null,
          "metadata": {}
        }
      ],
      "products": [
        {
          "id": "4567",
          "category_id": "312",
          "name": "Svíčková na smetaně, houskový knedlík",
          "description": "Hovězí svíčková, smetanová omáčka, brusinky, šlehačka.",
          "image_url": "https://www.mujprofirest.cz/data/products/4567.jpg",
          "price": {
            "amount": 19900,
            "currency": "CZK"
          },
          "vat_rate": "12",
          "packaging_fee": null,
          "weight": 150,
          "allergens": [
            "1",
            "3",
            "7",
            "9"
          ],
          "labels": [
            "home_made"
          ],
          "age_restricted": false,
          "add_ons": [],
          "option_groups": [],
          "removable_ingredients": [],
          "split": null,
          "half_price": null,
          "position": 1,
          "ean": null,
          "kitchen_name": null,
          "size": null,
          "pos": null,
          "external_id": null,
          "metadata": {}
        },
        {
          "id": "4568",
          "category_id": "312",
          "name": "Smažený sýr, hranolky, tatarská omáčka",
          "description": "Eidam 120 g, hranolky, domácí tatarská omáčka.",
          "image_url": null,
          "price": {
            "amount": 17900,
            "currency": "CZK"
          },
          "vat_rate": "12",
          "packaging_fee": null,
          "weight": 120,
          "allergens": [
            "1",
            "3",
            "7"
          ],
          "labels": [],
          "age_restricted": false,
          "add_ons": [],
          "option_groups": [],
          "removable_ingredients": [],
          "split": null,
          "half_price": null,
          "position": 2,
          "ean": null,
          "kitchen_name": null,
          "size": null,
          "pos": null,
          "external_id": null,
          "metadata": {}
        },
        {
          "id": "4571",
          "category_id": "315",
          "name": "Pizza Margherita",
          "description": "Rajčata San Marzano, mozzarella, bazalka.",
          "image_url": null,
          "price": {
            "amount": 18900,
            "currency": "CZK"
          },
          "vat_rate": "12",
          "packaging_fee": null,
          "weight": 450,
          "allergens": [
            "1",
            "7"
          ],
          "labels": [
            "bestseller"
          ],
          "age_restricted": false,
          "add_ons": [
            {
              "product_id": "4602",
              "name": "Extra sýr",
              "price": {
                "amount": 3000,
                "currency": "CZK"
              },
              "vat_rate": "12",
              "allergens": [
                "7"
              ]
            }
          ],
          "option_groups": [],
          "removable_ingredients": [
            {
              "id": "9001",
              "name": "bazalka"
            },
            {
              "id": "9002",
              "name": "oregano"
            }
          ],
          "split": {
            "half_price": {
              "amount": 13300,
              "currency": "CZK"
            },
            "quarter_price": null
          },
          "half_price": null,
          "position": 1,
          "ean": null,
          "kitchen_name": null,
          "size": null,
          "pos": null,
          "external_id": null,
          "metadata": {}
        },
        {
          "id": "4590",
          "category_id": "315",
          "name": "Vlastní pizza Ø32cm",
          "description": "Složte si pizzu: těsto a až 8 ingrediencí, 4 jsou v ceně.",
          "image_url": null,
          "price": {
            "amount": 18900,
            "currency": "CZK"
          },
          "vat_rate": "12",
          "packaging_fee": null,
          "weight": 450,
          "allergens": [
            "1",
            "7"
          ],
          "labels": [],
          "age_restricted": false,
          "add_ons": [],
          "option_groups": [
            {
              "id": "71",
              "name": "Těsto",
              "min_quantity": 1,
              "max_quantity": 1,
              "max_per_option": 1,
              "included_quantity": 0,
              "options": [
                {
                  "id": "1001",
                  "product_id": "4591",
                  "name": "Klasické těsto",
                  "price": {
                    "amount": 0,
                    "currency": "CZK"
                  },
                  "base_price": null,
                  "vat_rate": "12",
                  "allergens": [
                    "1"
                  ]
                },
                {
                  "id": "1002",
                  "product_id": "4592",
                  "name": "Celozrnné těsto",
                  "price": {
                    "amount": 2000,
                    "currency": "CZK"
                  },
                  "base_price": null,
                  "vat_rate": "12",
                  "allergens": [
                    "1"
                  ]
                }
              ]
            },
            {
              "id": "72",
              "name": "Ingredience",
              "min_quantity": 0,
              "max_quantity": 8,
              "max_per_option": 2,
              "included_quantity": 4,
              "options": [
                {
                  "id": "1101",
                  "product_id": "4605",
                  "name": "Šunka",
                  "price": {
                    "amount": 2400,
                    "currency": "CZK"
                  },
                  "base_price": null,
                  "vat_rate": "12",
                  "allergens": []
                },
                {
                  "id": "1102",
                  "product_id": "4603",
                  "name": "Žampiony",
                  "price": {
                    "amount": 1900,
                    "currency": "CZK"
                  },
                  "base_price": null,
                  "vat_rate": "12",
                  "allergens": []
                },
                {
                  "id": "1103",
                  "product_id": "4604",
                  "name": "Krevety",
                  "price": {
                    "amount": 0,
                    "currency": "CZK"
                  },
                  "base_price": {
                    "amount": 20900,
                    "currency": "CZK"
                  },
                  "vat_rate": "12",
                  "allergens": [
                    "2"
                  ]
                },
                {
                  "id": "1104",
                  "product_id": "4606",
                  "name": "Olivy",
                  "price": {
                    "amount": 1500,
                    "currency": "CZK"
                  },
                  "base_price": null,
                  "vat_rate": "12",
                  "allergens": []
                }
              ]
            }
          ],
          "removable_ingredients": [],
          "split": null,
          "half_price": null,
          "position": 4,
          "ean": null,
          "kitchen_name": null,
          "size": null,
          "pos": null,
          "external_id": null,
          "metadata": {}
        },
        {
          "id": "4580",
          "category_id": "315",
          "name": "Ø32cm Prosciutto",
          "description": "Šunka, mozzarella, rajčata.",
          "image_url": null,
          "price": {
            "amount": 21900,
            "currency": "CZK"
          },
          "vat_rate": "12",
          "packaging_fee": null,
          "weight": 450,
          "allergens": [
            "1",
            "7"
          ],
          "labels": [],
          "age_restricted": false,
          "add_ons": [],
          "option_groups": [],
          "removable_ingredients": [],
          "split": null,
          "half_price": null,
          "position": 2,
          "ean": null,
          "kitchen_name": null,
          "size": {
            "group_id": "4580",
            "name": "Ø32cm",
            "dish_name": "Prosciutto",
            "position": 1,
            "base": true
          },
          "pos": null,
          "external_id": null,
          "metadata": {}
        },
        {
          "id": "4583",
          "category_id": "315",
          "name": "Ø42cm Prosciutto",
          "description": "Šunka, mozzarella, rajčata.",
          "image_url": null,
          "price": {
            "amount": 30900,
            "currency": "CZK"
          },
          "vat_rate": "12",
          "packaging_fee": null,
          "weight": 700,
          "allergens": [
            "1",
            "7"
          ],
          "labels": [],
          "age_restricted": false,
          "add_ons": [],
          "option_groups": [],
          "removable_ingredients": [],
          "split": null,
          "half_price": null,
          "position": 3,
          "ean": null,
          "kitchen_name": null,
          "size": {
            "group_id": "4580",
            "name": "Ø42cm",
            "dish_name": "Prosciutto",
            "position": 2,
            "base": false
          },
          "pos": null,
          "external_id": null,
          "metadata": {}
        },
        {
          "id": "4590",
          "category_id": "320",
          "name": "Pivo 12° 0,5 l",
          "description": null,
          "image_url": null,
          "price": {
            "amount": 6900,
            "currency": "CZK"
          },
          "vat_rate": "21",
          "packaging_fee": null,
          "weight": null,
          "allergens": [],
          "labels": [],
          "age_restricted": true,
          "add_ons": [],
          "option_groups": [],
          "removable_ingredients": [],
          "split": null,
          "half_price": null,
          "position": 1,
          "ean": null,
          "kitchen_name": null,
          "size": null,
          "pos": null,
          "external_id": null,
          "metadata": {}
        },
        {
          "id": "4593",
          "category_id": "320",
          "name": "Domácí limonáda 0,4 l",
          "description": "Citron, máta, třtinový cukr.",
          "image_url": null,
          "price": {
            "amount": 5900,
            "currency": "CZK"
          },
          "vat_rate": "12",
          "packaging_fee": null,
          "weight": null,
          "allergens": [],
          "labels": [],
          "age_restricted": false,
          "add_ons": [],
          "option_groups": [],
          "removable_ingredients": [],
          "split": null,
          "half_price": null,
          "position": 2,
          "ean": null,
          "kitchen_name": null,
          "size": null,
          "pos": null,
          "external_id": null,
          "metadata": {}
        }
      ],
      "daily_menu": {
        "date": "2027-01-15",
        "available_from": "11:00",
        "available_to": "15:00",
        "items": [
          {
            "product_id": "4567",
            "position": 1
          },
          {
            "product_id": "4568",
            "position": 2
          }
        ]
      },
      "allergens": [
        {
          "code": "1",
          "name": "Obiloviny obsahující lepek"
        },
        {
          "code": "3",
          "name": "Vejce"
        },
        {
          "code": "7",
          "name": "Mléko"
        },
        {
          "code": "9",
          "name": "Celer"
        }
      ]
    }
  5. Nabídněte čas

    Offer a time

    GET /restaurants/{restaurant_id}/time-slots · listTimeSlots

    Časy, kdy provozovna stihne rozvoz nebo vyzvednutí; asap říká, jestli jde „co nejdřív“.

    The times the restaurant can deliver or have the order ready; asap tells whether “as soon as possible” works.

    Nastavení › Objednávky z aplikací: příjem objednávek, rozvoz a odběr a objednávky na pozdější čas – pro každou provozovnu zvlášť.
    Nastavení › Objednávky z aplikací: příjem objednávek, rozvoz a odběr a objednávky na pozdější čas – pro každou provozovnu zvlášť.Settings › Orders from applications: accepting orders, delivery and pickup and orders for later – for every restaurant separately.
    curl "https://api.mujprofirest.cz/v2/restaurants/123/time-slots?type=delivery&date=2027-01-15&zone_id=21" \
      -H "Authorization: Bearer $ACCESS_TOKEN"
    curl "https://api.mujprofirest.cz/v2/restaurants/123/time-slots?type=delivery&date=2027-01-15&zone_id=21" \
      -H "Authorization: Bearer $ACCESS_TOKEN"
    // klient: viz /v2/docs/js
    const listTimeSlots = await api.get(
      '/restaurants/123/time-slots',
      { query: { type: 'delivery', date: '2027-01-15', zone_id: '21' } },
    ); // 200
    // the client: see /v2/docs/js
    const listTimeSlots = await api.get(
      '/restaurants/123/time-slots',
      { query: { type: 'delivery', date: '2027-01-15', zone_id: '21' } },
    ); // 200
    // klient: viz /v2/docs/typescript
    const listTimeSlots = await api.get(
      '/restaurants/123/time-slots',
      { query: { type: 'delivery', date: '2027-01-15', zone_id: '21' } },
    ); // 200 TimeSlots
    // the client: see /v2/docs/typescript
    const listTimeSlots = await api.get(
      '/restaurants/123/time-slots',
      { query: { type: 'delivery', date: '2027-01-15', zone_id: '21' } },
    ); // 200 TimeSlots
    // klient: viz /v2/docs/php
    $listTimeSlots = $api->get(
        '/restaurants/123/time-slots',
        ['query' => ['type' => 'delivery', 'date' => '2027-01-15', 'zone_id' => '21']],
    ); // 200
    // the client: see /v2/docs/php
    $listTimeSlots = $api->get(
        '/restaurants/123/time-slots',
        ['query' => ['type' => 'delivery', 'date' => '2027-01-15', 'zone_id' => '21']],
    ); // 200
    // klient: viz /v2/docs/java
    // volání blokuje – na Androidu z pracovního vlákna (Dispatchers.IO)
    TimeSlots listTimeSlots = api.get(
        "/restaurants/123/time-slots",
        RequestOptions.builder().query("type", "delivery").query("date", "2027-01-15").query("zone_id", "21").build(),
        TimeSlots::fromJson
    ); // 200
    // the client: see /v2/docs/java
    // the call blocks – on Android from a worker thread (Dispatchers.IO)
    TimeSlots listTimeSlots = api.get(
        "/restaurants/123/time-slots",
        RequestOptions.builder().query("type", "delivery").query("date", "2027-01-15").query("zone_id", "21").build(),
        TimeSlots::fromJson
    ); // 200
    // klient: viz /v2/docs/java
    // volání blokuje – na Androidu z pracovního vlákna (Dispatchers.IO)
    val listTimeSlots = api.get(
        "/restaurants/123/time-slots",
        RequestOptions.builder().query("type", "delivery").query("date", "2027-01-15").query("zone_id", "21").build(),
        TimeSlots::fromJson,
    ) // 200
    // the client: see /v2/docs/java
    // the call blocks – on Android from a worker thread (Dispatchers.IO)
    val listTimeSlots = api.get(
        "/restaurants/123/time-slots",
        RequestOptions.builder().query("type", "delivery").query("date", "2027-01-15").query("zone_id", "21").build(),
        TimeSlots::fromJson,
    ) // 200
    // klient: viz /v2/docs/csharp
    var listTimeSlots = await api.GetAsync<TimeSlots>(
        "/restaurants/123/time-slots",
        new RequestOptions { Query = new() { ["type"] = "delivery", ["date"] = "2027-01-15", ["zone_id"] = "21" } }
    ); // 200
    // the client: see /v2/docs/csharp
    var listTimeSlots = await api.GetAsync<TimeSlots>(
        "/restaurants/123/time-slots",
        new RequestOptions { Query = new() { ["type"] = "delivery", ["date"] = "2027-01-15", ["zone_id"] = "21" } }
    ); // 200
    # klient: viz /v2/docs/python
    list_time_slots = api.get(
        '/restaurants/123/time-slots',
        query={'type': 'delivery', 'date': '2027-01-15', 'zone_id': '21'},
    )  # 200
    # the client: see /v2/docs/python
    list_time_slots = api.get(
        '/restaurants/123/time-slots',
        query={'type': 'delivery', 'date': '2027-01-15', 'zone_id': '21'},
    )  # 200
    // klient: viz /v2/docs/swift
    let listTimeSlots: TimeSlots = try await api.get(
        "/restaurants/123/time-slots",
        options: .init(query: ["type": "delivery", "date": "2027-01-15", "zone_id": "21"])
    ) // 200
    // the client: see /v2/docs/swift
    let listTimeSlots: TimeSlots = try await api.get(
        "/restaurants/123/time-slots",
        options: .init(query: ["type": "delivery", "date": "2027-01-15", "zone_id": "21"])
    ) // 200
    // klient: viz /v2/docs/dart
    final listTimeSlots = pr.TimeSlots.fromJson(await api.get(
      '/restaurants/123/time-slots',
      query: {'type': 'delivery', 'date': '2027-01-15', 'zone_id': '21'},
    )); // 200
    // the client: see /v2/docs/dart
    final listTimeSlots = pr.TimeSlots.fromJson(await api.get(
      '/restaurants/123/time-slots',
      query: {'type': 'delivery', 'date': '2027-01-15', 'zone_id': '21'},
    )); // 200
    // klient: viz /v2/docs/go
    res, err := api.Get(
    	ctx,
    	"/restaurants/123/time-slots",
    	&profirest.RequestOptions{Query: map[string]any{"type": "delivery", "date": "2027-01-15", "zone_id": "21"}},
    )
    var listTimeSlots model.TimeSlots // 200
    if err == nil {
    	err = res.Decode(&listTimeSlots)
    }
    // the client: see /v2/docs/go
    res, err := api.Get(
    	ctx,
    	"/restaurants/123/time-slots",
    	&profirest.RequestOptions{Query: map[string]any{"type": "delivery", "date": "2027-01-15", "zone_id": "21"}},
    )
    var listTimeSlots model.TimeSlots // 200
    if err == nil {
    	err = res.Decode(&listTimeSlots)
    }
    Příklad odpovědi 200Example answer 200
    {
      "restaurant_id": "123",
      "type": "delivery",
      "date": "2027-01-15",
      "asap": {
        "available": true,
        "reason": null
      },
      "slots": [
        {
          "time": "2027-01-15T12:30:00+01:00"
        },
        {
          "time": "2027-01-15T12:45:00+01:00"
        },
        {
          "time": "2027-01-15T13:00:00+01:00"
        },
        {
          "time": "2027-01-15T13:15:00+01:00"
        }
      ]
    }
  6. Spočítejte košík

    Price the basket

    POST /restaurants/{restaurant_id}/quotes · createQuote

    Server spočítá ceny, dopravu, DPH, akce a slevové kódy i vouchery a ceny drží do expires_at. Nedostupný produkt nebo adresa mimo rozvoz přijdou jako 422 s kódem z katalogu chyb. Když má rozvozová zóna adresy delivery.express_fee, nabídněte „Expresní doručení +X Kč“ a při volbě spočítejte košík znovu s fulfillment.speed express – přibude poplatek express_delivery (jen rozvoz co nejdřív; kuchyň objednávku uvidí se štítkem EXPRES).

    The server computes prices, delivery, VAT, promotions and promo codes and vouchers and keeps the prices until expires_at. An unavailable product or an address outside delivery comes as 422 with a code from the error catalog. When the delivery zone of the address has delivery.express_fee, offer “Express delivery +X CZK” and on that choice price the basket again with fulfillment.speed express – the charge express_delivery is added (delivery as soon as possible only; the kitchen sees the order marked EXPRES).

    Produkty a sklady › Akce a slevové kódy: akce, které kalkulace uplatní sama, a slevové kódy, které zákazník zadá.
    Produkty a sklady › Akce a slevové kódy: akce, které kalkulace uplatní sama, a slevové kódy, které zákazník zadá.Products and stock › Promotions and promo codes: promotions the quote applies by itself and codes the customer enters.
    curl "https://api.mujprofirest.cz/v2/restaurants/123/quotes" \
      -H "Authorization: Bearer $ACCESS_TOKEN" \
      -H "Idempotency-Key: 01a318f0-a0c0-73e4-8e81-92356cdda12a" \
      -H "Content-Type: application/json" \
      -d '{"fulfillment": {"type": "pickup"}, "items": [{"product_id": "4567", "quantity": 2}]}'
    curl "https://api.mujprofirest.cz/v2/restaurants/123/quotes" \
      -H "Authorization: Bearer $ACCESS_TOKEN" \
      -H "Idempotency-Key: 01a318f0-a0c0-73e4-8e81-92356cdda12a" \
      -H "Content-Type: application/json" \
      -d '{"fulfillment": {"type": "pickup"}, "items": [{"product_id": "4567", "quantity": 2}]}'
    // klient: viz /v2/docs/js
    const quote = await api.post(
      '/restaurants/123/quotes',
      { fulfillment: { type: 'pickup' }, items: [{ product_id: '4567', quantity: 2 }] },
    ); // 201
    // the client: see /v2/docs/js
    const quote = await api.post(
      '/restaurants/123/quotes',
      { fulfillment: { type: 'pickup' }, items: [{ product_id: '4567', quantity: 2 }] },
    ); // 201
    // klient: viz /v2/docs/typescript
    const quote = await api.post(
      '/restaurants/123/quotes',
      { fulfillment: { type: 'pickup' }, items: [{ product_id: '4567', quantity: 2 }] },
    ); // 201 Quote
    // the client: see /v2/docs/typescript
    const quote = await api.post(
      '/restaurants/123/quotes',
      { fulfillment: { type: 'pickup' }, items: [{ product_id: '4567', quantity: 2 }] },
    ); // 201 Quote
    // klient: viz /v2/docs/php
    $quote = $api->post('/restaurants/123/quotes', [
        'fulfillment' => ['type' => 'pickup'],
        'items' => [['product_id' => '4567', 'quantity' => 2]],
    ]); // 201
    // the client: see /v2/docs/php
    $quote = $api->post('/restaurants/123/quotes', [
        'fulfillment' => ['type' => 'pickup'],
        'items' => [['product_id' => '4567', 'quantity' => 2]],
    ]); // 201
    // klient: viz /v2/docs/java
    // volání blokuje – na Androidu z pracovního vlákna (Dispatchers.IO)
    Quote quote = api.post("/restaurants/123/quotes", Json.parse("""
        {"fulfillment": {"type": "pickup"}, "items": [{"product_id": "4567", "quantity": 2}]}
        """), Quote::fromJson); // 201
    // the client: see /v2/docs/java
    // the call blocks – on Android from a worker thread (Dispatchers.IO)
    Quote quote = api.post("/restaurants/123/quotes", Json.parse("""
        {"fulfillment": {"type": "pickup"}, "items": [{"product_id": "4567", "quantity": 2}]}
        """), Quote::fromJson); // 201
    // klient: viz /v2/docs/java
    // volání blokuje – na Androidu z pracovního vlákna (Dispatchers.IO)
    val quote = api.post("/restaurants/123/quotes", mapOf(
        "fulfillment" to mapOf("type" to "pickup"),
        "items" to listOf(mapOf("product_id" to "4567", "quantity" to 2)),
    ), Quote::fromJson) // 201
    // the client: see /v2/docs/java
    // the call blocks – on Android from a worker thread (Dispatchers.IO)
    val quote = api.post("/restaurants/123/quotes", mapOf(
        "fulfillment" to mapOf("type" to "pickup"),
        "items" to listOf(mapOf("product_id" to "4567", "quantity" to 2)),
    ), Quote::fromJson) // 201
    // klient: viz /v2/docs/csharp
    var quote = await api.PostAsync<Quote>("/restaurants/123/quotes", new {
        fulfillment = new { type = "pickup" },
        items = new object[] { new { product_id = "4567", quantity = 2 } },
    }); // 201
    // the client: see /v2/docs/csharp
    var quote = await api.PostAsync<Quote>("/restaurants/123/quotes", new {
        fulfillment = new { type = "pickup" },
        items = new object[] { new { product_id = "4567", quantity = 2 } },
    }); // 201
    # klient: viz /v2/docs/python
    quote = api.post(
        '/restaurants/123/quotes',
        {'fulfillment': {'type': 'pickup'}, 'items': [{'product_id': '4567', 'quantity': 2}]},
    )  # 201
    # the client: see /v2/docs/python
    quote = api.post(
        '/restaurants/123/quotes',
        {'fulfillment': {'type': 'pickup'}, 'items': [{'product_id': '4567', 'quantity': 2}]},
    )  # 201
    // klient: viz /v2/docs/swift
    let quote: Quote = try await api.post(
        "/restaurants/123/quotes",
        body: ["fulfillment": ["type": "pickup"], "items": [["product_id": "4567", "quantity": 2]]]
    ) // 201
    // the client: see /v2/docs/swift
    let quote: Quote = try await api.post(
        "/restaurants/123/quotes",
        body: ["fulfillment": ["type": "pickup"], "items": [["product_id": "4567", "quantity": 2]]]
    ) // 201
    // klient: viz /v2/docs/dart
    final quote = pr.Quote.fromJson(await api.post(
      '/restaurants/123/quotes',
      {'fulfillment': {'type': 'pickup'}, 'items': [{'product_id': '4567', 'quantity': 2}]},
    )); // 201
    // the client: see /v2/docs/dart
    final quote = pr.Quote.fromJson(await api.post(
      '/restaurants/123/quotes',
      {'fulfillment': {'type': 'pickup'}, 'items': [{'product_id': '4567', 'quantity': 2}]},
    )); // 201
    // klient: viz /v2/docs/go
    res, err := api.Post(ctx, "/restaurants/123/quotes", map[string]any{
    	"fulfillment": map[string]any{"type": "pickup"},
    	"items": []any{map[string]any{"product_id": "4567", "quantity": 2}},
    }, nil)
    var quote model.Quote // 201
    if err == nil {
    	err = res.Decode(&quote)
    }
    // the client: see /v2/docs/go
    res, err := api.Post(ctx, "/restaurants/123/quotes", map[string]any{
    	"fulfillment": map[string]any{"type": "pickup"},
    	"items": []any{map[string]any{"product_id": "4567", "quantity": 2}},
    }, nil)
    var quote model.Quote // 201
    if err == nil {
    	err = res.Decode(&quote)
    }
    Příklad odpovědi 201Example answer 201
    {
      "id": "58213",
      "restaurant_id": "123",
      "created_at": "2027-01-15T11:42:10+01:00",
      "expires_at": "2027-01-15T11:57:10+01:00",
      "customer_id": null,
      "fulfillment": {
        "type": "pickup",
        "speed": "standard",
        "asap": true,
        "time": null,
        "estimated_at": "2027-01-15T12:05:00+01:00"
      },
      "delivery": null,
      "lines": [
        {
          "id": "1",
          "type": "product",
          "variant": "full",
          "product_id": "4567",
          "name": "Svíčková na smetaně, houskový knedlík",
          "quantity": 2,
          "base_unit_price": {
            "amount": 19900,
            "currency": "CZK"
          },
          "unit_price": {
            "amount": 19900,
            "currency": "CZK"
          },
          "packaging_unit_price": null,
          "vat_rate": "12",
          "add_ons": [],
          "options": [],
          "parts": null,
          "removed_ingredients": [],
          "note": null,
          "total": {
            "amount": 39800,
            "currency": "CZK"
          },
          "gift_of": null
        }
      ],
      "charges": [],
      "discounts": [],
      "totals": {
        "items": {
          "amount": 39800,
          "currency": "CZK"
        },
        "charges": {
          "amount": 0,
          "currency": "CZK"
        },
        "discounts": {
          "amount": 0,
          "currency": "CZK"
        },
        "rounding": {
          "amount": 0,
          "currency": "CZK"
        },
        "total": {
          "amount": 39800,
          "currency": "CZK"
        },
        "vat": [
          {
            "rate": "12",
            "base": {
              "amount": 35536,
              "currency": "CZK"
            },
            "vat": {
              "amount": 4264,
              "currency": "CZK"
            },
            "total": {
              "amount": 39800,
              "currency": "CZK"
            }
          }
        ]
      },
      "payments": [],
      "amount_due": {
        "amount": 39800,
        "currency": "CZK"
      }
    }
  7. Založte objednávku

    Create the order

    POST /restaurants/{restaurant_id}/orders · createOrder

    S platbou online jako pending: objednávka čeká ve stavu awaiting_payment, porce i vouchery jsou rezervované a kuchyň ji ještě nevidí. Platby musí dát dohromady amount_due nabídky.

    With an online payment as pending: the order waits in awaiting_payment, portions and vouchers are reserved and the kitchen does not see it yet. The payments must add up to the quote's amount_due.

    curl "https://api.mujprofirest.cz/v2/restaurants/123/orders" \
      -H "Authorization: Bearer $ACCESS_TOKEN" \
      -H "Idempotency-Key: 01a318f0-a0c0-7ef0-9ac6-6e2d9864c7d1" \
      -H "Content-Type: application/json" \
      -d '{
      "quote_id": "58213",
      "customer": {
        "name": "Jana Nováková",
        "phone": "+420777123456",
        "email": "jana.novakova@example.cz"
      },
      "payments": [
        {
          "method": "online",
          "status": "pending",
          "amount": {"amount": 39800, "currency": "CZK"},
          "provider": "gopay"
        }
      ],
      "external_id": "A-2027-000124"
    }'
    curl "https://api.mujprofirest.cz/v2/restaurants/123/orders" \
      -H "Authorization: Bearer $ACCESS_TOKEN" \
      -H "Idempotency-Key: 01a318f0-a0c0-7ef0-9ac6-6e2d9864c7d1" \
      -H "Content-Type: application/json" \
      -d '{
      "quote_id": "58213",
      "customer": {
        "name": "Jana Nováková",
        "phone": "+420777123456",
        "email": "jana.novakova@example.cz"
      },
      "payments": [
        {
          "method": "online",
          "status": "pending",
          "amount": {"amount": 39800, "currency": "CZK"},
          "provider": "gopay"
        }
      ],
      "external_id": "A-2027-000124"
    }'
    // klient: viz /v2/docs/js
    const order = await api.post('/restaurants/123/orders', {
      quote_id: '58213',
      customer: { name: 'Jana Nováková', phone: '+420777123456', email: 'jana.novakova@example.cz' },
      payments: [
        {
          method: 'online',
          status: 'pending',
          amount: { amount: 39800, currency: 'CZK' },
          provider: 'gopay',
        },
      ],
      external_id: 'A-2027-000124',
    }); // 201
    // the client: see /v2/docs/js
    const order = await api.post('/restaurants/123/orders', {
      quote_id: '58213',
      customer: { name: 'Jana Nováková', phone: '+420777123456', email: 'jana.novakova@example.cz' },
      payments: [
        {
          method: 'online',
          status: 'pending',
          amount: { amount: 39800, currency: 'CZK' },
          provider: 'gopay',
        },
      ],
      external_id: 'A-2027-000124',
    }); // 201
    // klient: viz /v2/docs/typescript
    const order = await api.post('/restaurants/123/orders', {
      quote_id: '58213',
      customer: { name: 'Jana Nováková', phone: '+420777123456', email: 'jana.novakova@example.cz' },
      payments: [
        {
          method: 'online',
          status: 'pending',
          amount: { amount: 39800, currency: 'CZK' },
          provider: 'gopay',
        },
      ],
      external_id: 'A-2027-000124',
    }); // 201 Order
    // the client: see /v2/docs/typescript
    const order = await api.post('/restaurants/123/orders', {
      quote_id: '58213',
      customer: { name: 'Jana Nováková', phone: '+420777123456', email: 'jana.novakova@example.cz' },
      payments: [
        {
          method: 'online',
          status: 'pending',
          amount: { amount: 39800, currency: 'CZK' },
          provider: 'gopay',
        },
      ],
      external_id: 'A-2027-000124',
    }); // 201 Order
    // klient: viz /v2/docs/php
    $order = $api->post('/restaurants/123/orders', [
        'quote_id' => '58213',
        'customer' => [
            'name' => 'Jana Nováková',
            'phone' => '+420777123456',
            'email' => 'jana.novakova@example.cz',
        ],
        'payments' => [
            [
                'method' => 'online',
                'status' => 'pending',
                'amount' => ['amount' => 39800, 'currency' => 'CZK'],
                'provider' => 'gopay',
            ],
        ],
        'external_id' => 'A-2027-000124',
    ]); // 201
    // the client: see /v2/docs/php
    $order = $api->post('/restaurants/123/orders', [
        'quote_id' => '58213',
        'customer' => [
            'name' => 'Jana Nováková',
            'phone' => '+420777123456',
            'email' => 'jana.novakova@example.cz',
        ],
        'payments' => [
            [
                'method' => 'online',
                'status' => 'pending',
                'amount' => ['amount' => 39800, 'currency' => 'CZK'],
                'provider' => 'gopay',
            ],
        ],
        'external_id' => 'A-2027-000124',
    ]); // 201
    // klient: viz /v2/docs/java
    // volání blokuje – na Androidu z pracovního vlákna (Dispatchers.IO)
    Order order = api.post("/restaurants/123/orders", Json.parse("""
        {
          "quote_id": "58213",
          "customer": {
            "name": "Jana Nováková",
            "phone": "+420777123456",
            "email": "jana.novakova@example.cz"
          },
          "payments": [
            {
              "method": "online",
              "status": "pending",
              "amount": {"amount": 39800, "currency": "CZK"},
              "provider": "gopay"
            }
          ],
          "external_id": "A-2027-000124"
        }
        """), Order::fromJson); // 201
    // the client: see /v2/docs/java
    // the call blocks – on Android from a worker thread (Dispatchers.IO)
    Order order = api.post("/restaurants/123/orders", Json.parse("""
        {
          "quote_id": "58213",
          "customer": {
            "name": "Jana Nováková",
            "phone": "+420777123456",
            "email": "jana.novakova@example.cz"
          },
          "payments": [
            {
              "method": "online",
              "status": "pending",
              "amount": {"amount": 39800, "currency": "CZK"},
              "provider": "gopay"
            }
          ],
          "external_id": "A-2027-000124"
        }
        """), Order::fromJson); // 201
    // klient: viz /v2/docs/java
    // volání blokuje – na Androidu z pracovního vlákna (Dispatchers.IO)
    val order = api.post("/restaurants/123/orders", mapOf(
        "quote_id" to "58213",
        "customer" to mapOf(
            "name" to "Jana Nováková",
            "phone" to "+420777123456",
            "email" to "jana.novakova@example.cz",
        ),
        "payments" to listOf(
            mapOf(
                "method" to "online",
                "status" to "pending",
                "amount" to mapOf("amount" to 39800, "currency" to "CZK"),
                "provider" to "gopay",
            ),
        ),
        "external_id" to "A-2027-000124",
    ), Order::fromJson) // 201
    // the client: see /v2/docs/java
    // the call blocks – on Android from a worker thread (Dispatchers.IO)
    val order = api.post("/restaurants/123/orders", mapOf(
        "quote_id" to "58213",
        "customer" to mapOf(
            "name" to "Jana Nováková",
            "phone" to "+420777123456",
            "email" to "jana.novakova@example.cz",
        ),
        "payments" to listOf(
            mapOf(
                "method" to "online",
                "status" to "pending",
                "amount" to mapOf("amount" to 39800, "currency" to "CZK"),
                "provider" to "gopay",
            ),
        ),
        "external_id" to "A-2027-000124",
    ), Order::fromJson) // 201
    // klient: viz /v2/docs/csharp
    var order = await api.PostAsync<Order>("/restaurants/123/orders", new {
        quote_id = "58213",
        customer = new {
            name = "Jana Nováková",
            phone = "+420777123456",
            email = "jana.novakova@example.cz",
        },
        payments = new object[] {
            new {
                method = "online",
                status = "pending",
                amount = new { amount = 39800, currency = "CZK" },
                provider = "gopay",
            },
        },
        external_id = "A-2027-000124",
    }); // 201
    // the client: see /v2/docs/csharp
    var order = await api.PostAsync<Order>("/restaurants/123/orders", new {
        quote_id = "58213",
        customer = new {
            name = "Jana Nováková",
            phone = "+420777123456",
            email = "jana.novakova@example.cz",
        },
        payments = new object[] {
            new {
                method = "online",
                status = "pending",
                amount = new { amount = 39800, currency = "CZK" },
                provider = "gopay",
            },
        },
        external_id = "A-2027-000124",
    }); // 201
    # klient: viz /v2/docs/python
    order = api.post('/restaurants/123/orders', {
        'quote_id': '58213',
        'customer': {
            'name': 'Jana Nováková',
            'phone': '+420777123456',
            'email': 'jana.novakova@example.cz',
        },
        'payments': [
            {
                'method': 'online',
                'status': 'pending',
                'amount': {'amount': 39800, 'currency': 'CZK'},
                'provider': 'gopay',
            },
        ],
        'external_id': 'A-2027-000124',
    })  # 201
    # the client: see /v2/docs/python
    order = api.post('/restaurants/123/orders', {
        'quote_id': '58213',
        'customer': {
            'name': 'Jana Nováková',
            'phone': '+420777123456',
            'email': 'jana.novakova@example.cz',
        },
        'payments': [
            {
                'method': 'online',
                'status': 'pending',
                'amount': {'amount': 39800, 'currency': 'CZK'},
                'provider': 'gopay',
            },
        ],
        'external_id': 'A-2027-000124',
    })  # 201
    // klient: viz /v2/docs/swift
    let order: Order = try await api.post("/restaurants/123/orders", body: [
        "quote_id": "58213",
        "customer": [
            "name": "Jana Nováková",
            "phone": "+420777123456",
            "email": "jana.novakova@example.cz",
        ],
        "payments": [
            [
                "method": "online",
                "status": "pending",
                "amount": ["amount": 39800, "currency": "CZK"],
                "provider": "gopay",
            ],
        ],
        "external_id": "A-2027-000124",
    ]) // 201
    // the client: see /v2/docs/swift
    let order: Order = try await api.post("/restaurants/123/orders", body: [
        "quote_id": "58213",
        "customer": [
            "name": "Jana Nováková",
            "phone": "+420777123456",
            "email": "jana.novakova@example.cz",
        ],
        "payments": [
            [
                "method": "online",
                "status": "pending",
                "amount": ["amount": 39800, "currency": "CZK"],
                "provider": "gopay",
            ],
        ],
        "external_id": "A-2027-000124",
    ]) // 201
    // klient: viz /v2/docs/dart
    final order = pr.Order.fromJson(await api.post('/restaurants/123/orders', {
      'quote_id': '58213',
      'customer': {
        'name': 'Jana Nováková',
        'phone': '+420777123456',
        'email': 'jana.novakova@example.cz',
      },
      'payments': [
        {
          'method': 'online',
          'status': 'pending',
          'amount': {'amount': 39800, 'currency': 'CZK'},
          'provider': 'gopay',
        },
      ],
      'external_id': 'A-2027-000124',
    })); // 201
    // the client: see /v2/docs/dart
    final order = pr.Order.fromJson(await api.post('/restaurants/123/orders', {
      'quote_id': '58213',
      'customer': {
        'name': 'Jana Nováková',
        'phone': '+420777123456',
        'email': 'jana.novakova@example.cz',
      },
      'payments': [
        {
          'method': 'online',
          'status': 'pending',
          'amount': {'amount': 39800, 'currency': 'CZK'},
          'provider': 'gopay',
        },
      ],
      'external_id': 'A-2027-000124',
    })); // 201
    // klient: viz /v2/docs/go
    res, err := api.Post(ctx, "/restaurants/123/orders", map[string]any{
    	"quote_id": "58213",
    	"customer": map[string]any{
    		"name": "Jana Nováková",
    		"phone": "+420777123456",
    		"email": "jana.novakova@example.cz",
    	},
    	"payments": []any{
    		map[string]any{
    			"method": "online",
    			"status": "pending",
    			"amount": map[string]any{"amount": 39800, "currency": "CZK"},
    			"provider": "gopay",
    		},
    	},
    	"external_id": "A-2027-000124",
    }, nil)
    var order model.Order // 201
    if err == nil {
    	err = res.Decode(&order)
    }
    // the client: see /v2/docs/go
    res, err := api.Post(ctx, "/restaurants/123/orders", map[string]any{
    	"quote_id": "58213",
    	"customer": map[string]any{
    		"name": "Jana Nováková",
    		"phone": "+420777123456",
    		"email": "jana.novakova@example.cz",
    	},
    	"payments": []any{
    		map[string]any{
    			"method": "online",
    			"status": "pending",
    			"amount": map[string]any{"amount": 39800, "currency": "CZK"},
    			"provider": "gopay",
    		},
    	},
    	"external_id": "A-2027-000124",
    }, nil)
    var order model.Order // 201
    if err == nil {
    	err = res.Decode(&order)
    }
    Příklad odpovědi 201Example answer 201
    {
      "id": "184224",
      "restaurant_id": "123",
      "kitchen_number": null,
      "status": "awaiting_payment",
      "status_changed_at": "2027-01-15T11:42:31+01:00",
      "created_at": "2027-01-15T11:42:31+01:00",
      "payment_deadline": "2027-01-15T12:12:31+01:00",
      "fulfillment": {
        "type": "pickup",
        "speed": "standard",
        "asap": true,
        "time": null,
        "estimated_at": "2027-01-15T12:05:00+01:00"
      },
      "customer": {
        "customer_id": null,
        "name": "Jana Nováková",
        "phone": "+420777123456",
        "email": "jana.novakova@example.cz"
      },
      "delivery": null,
      "lines": [
        {
          "id": "1",
          "type": "product",
          "variant": "full",
          "product_id": "4567",
          "name": "Svíčková na smetaně, houskový knedlík",
          "quantity": 2,
          "base_unit_price": {
            "amount": 19900,
            "currency": "CZK"
          },
          "unit_price": {
            "amount": 19900,
            "currency": "CZK"
          },
          "packaging_unit_price": null,
          "vat_rate": "12",
          "add_ons": [],
          "options": [],
          "parts": null,
          "removed_ingredients": [],
          "note": null,
          "total": {
            "amount": 39800,
            "currency": "CZK"
          },
          "gift_of": null
        }
      ],
      "charges": [],
      "discounts": [],
      "totals": {
        "items": {
          "amount": 39800,
          "currency": "CZK"
        },
        "charges": {
          "amount": 0,
          "currency": "CZK"
        },
        "discounts": {
          "amount": 0,
          "currency": "CZK"
        },
        "rounding": {
          "amount": 0,
          "currency": "CZK"
        },
        "total": {
          "amount": 39800,
          "currency": "CZK"
        },
        "vat": [
          {
            "rate": "12",
            "base": {
              "amount": 35536,
              "currency": "CZK"
            },
            "vat": {
              "amount": 4264,
              "currency": "CZK"
            },
            "total": {
              "amount": 39800,
              "currency": "CZK"
            }
          }
        ]
      },
      "payments": [
        {
          "id": "301878",
          "method": "online",
          "status": "pending",
          "amount": {
            "amount": 39800,
            "currency": "CZK"
          },
          "provider": "gopay",
          "reference": null,
          "voucher_code": null,
          "forfeited": null
        }
      ],
      "amount_to_collect": {
        "amount": 0,
        "currency": "CZK"
      },
      "loyalty_points_earned": null,
      "note": null,
      "cancellation": null,
      "eet": null,
      "external_id": "A-2027-000124",
      "metadata": {
        "branch": "praha-3"
      }
    }
  8. Potvrďte zaplacení

    Confirm the payment

    POST /restaurants/{restaurant_id}/orders/{order_id}/confirm-payment · confirmOrderPayment

    Až teď jde objednávka do kuchyně. Bez potvrzení se po payment_deadline sama zruší – zákazník tak nikdy nezaplatí za objednávku, která nevznikla.

    Only now the order goes to the kitchen. Without the confirmation it is cancelled after payment_deadline – a customer is never charged for an order that was not created.

    curl "https://api.mujprofirest.cz/v2/restaurants/123/orders/184224/confirm-payment" \
      -H "Authorization: Bearer $ACCESS_TOKEN" \
      -H "Idempotency-Key: 01a318f0-a0c0-711d-893c-093072f9b49d" \
      -H "Content-Type: application/json" \
      -d '{"provider": "gopay", "reference": "3260145812"}'
    curl "https://api.mujprofirest.cz/v2/restaurants/123/orders/184224/confirm-payment" \
      -H "Authorization: Bearer $ACCESS_TOKEN" \
      -H "Idempotency-Key: 01a318f0-a0c0-711d-893c-093072f9b49d" \
      -H "Content-Type: application/json" \
      -d '{"provider": "gopay", "reference": "3260145812"}'
    // klient: viz /v2/docs/js
    const orderPayment = await api.post(
      '/restaurants/123/orders/184224/confirm-payment',
      { provider: 'gopay', reference: '3260145812' },
    ); // 200
    // the client: see /v2/docs/js
    const orderPayment = await api.post(
      '/restaurants/123/orders/184224/confirm-payment',
      { provider: 'gopay', reference: '3260145812' },
    ); // 200
    // klient: viz /v2/docs/typescript
    const orderPayment = await api.post(
      '/restaurants/123/orders/184224/confirm-payment',
      { provider: 'gopay', reference: '3260145812' },
    ); // 200 Order
    // the client: see /v2/docs/typescript
    const orderPayment = await api.post(
      '/restaurants/123/orders/184224/confirm-payment',
      { provider: 'gopay', reference: '3260145812' },
    ); // 200 Order
    // klient: viz /v2/docs/php
    $orderPayment = $api->post(
        '/restaurants/123/orders/184224/confirm-payment',
        ['provider' => 'gopay', 'reference' => '3260145812'],
    ); // 200
    // the client: see /v2/docs/php
    $orderPayment = $api->post(
        '/restaurants/123/orders/184224/confirm-payment',
        ['provider' => 'gopay', 'reference' => '3260145812'],
    ); // 200
    // klient: viz /v2/docs/java
    // volání blokuje – na Androidu z pracovního vlákna (Dispatchers.IO)
    Order orderPayment = api.post("/restaurants/123/orders/184224/confirm-payment", Json.parse("""
        {"provider": "gopay", "reference": "3260145812"}
        """), Order::fromJson); // 200
    // the client: see /v2/docs/java
    // the call blocks – on Android from a worker thread (Dispatchers.IO)
    Order orderPayment = api.post("/restaurants/123/orders/184224/confirm-payment", Json.parse("""
        {"provider": "gopay", "reference": "3260145812"}
        """), Order::fromJson); // 200
    // klient: viz /v2/docs/java
    // volání blokuje – na Androidu z pracovního vlákna (Dispatchers.IO)
    val orderPayment = api.post(
        "/restaurants/123/orders/184224/confirm-payment",
        mapOf("provider" to "gopay", "reference" to "3260145812"),
        Order::fromJson,
    ) // 200
    // the client: see /v2/docs/java
    // the call blocks – on Android from a worker thread (Dispatchers.IO)
    val orderPayment = api.post(
        "/restaurants/123/orders/184224/confirm-payment",
        mapOf("provider" to "gopay", "reference" to "3260145812"),
        Order::fromJson,
    ) // 200
    // klient: viz /v2/docs/csharp
    var orderPayment = await api.PostAsync<Order>(
        "/restaurants/123/orders/184224/confirm-payment",
        new { provider = "gopay", reference = "3260145812" }
    ); // 200
    // the client: see /v2/docs/csharp
    var orderPayment = await api.PostAsync<Order>(
        "/restaurants/123/orders/184224/confirm-payment",
        new { provider = "gopay", reference = "3260145812" }
    ); // 200
    # klient: viz /v2/docs/python
    order_payment = api.post(
        '/restaurants/123/orders/184224/confirm-payment',
        {'provider': 'gopay', 'reference': '3260145812'},
    )  # 200
    # the client: see /v2/docs/python
    order_payment = api.post(
        '/restaurants/123/orders/184224/confirm-payment',
        {'provider': 'gopay', 'reference': '3260145812'},
    )  # 200
    // klient: viz /v2/docs/swift
    let orderPayment: Order = try await api.post(
        "/restaurants/123/orders/184224/confirm-payment",
        body: ["provider": "gopay", "reference": "3260145812"]
    ) // 200
    // the client: see /v2/docs/swift
    let orderPayment: Order = try await api.post(
        "/restaurants/123/orders/184224/confirm-payment",
        body: ["provider": "gopay", "reference": "3260145812"]
    ) // 200
    // klient: viz /v2/docs/dart
    final orderPayment = pr.Order.fromJson(await api.post(
      '/restaurants/123/orders/184224/confirm-payment',
      {'provider': 'gopay', 'reference': '3260145812'},
    )); // 200
    // the client: see /v2/docs/dart
    final orderPayment = pr.Order.fromJson(await api.post(
      '/restaurants/123/orders/184224/confirm-payment',
      {'provider': 'gopay', 'reference': '3260145812'},
    )); // 200
    // klient: viz /v2/docs/go
    res, err := api.Post(
    	ctx,
    	"/restaurants/123/orders/184224/confirm-payment",
    	map[string]any{"provider": "gopay", "reference": "3260145812"},
    	nil,
    )
    var orderPayment model.Order // 200
    if err == nil {
    	err = res.Decode(&orderPayment)
    }
    // the client: see /v2/docs/go
    res, err := api.Post(
    	ctx,
    	"/restaurants/123/orders/184224/confirm-payment",
    	map[string]any{"provider": "gopay", "reference": "3260145812"},
    	nil,
    )
    var orderPayment model.Order // 200
    if err == nil {
    	err = res.Decode(&orderPayment)
    }
    Příklad odpovědi 200Example answer 200
    {
      "id": "184224",
      "restaurant_id": "123",
      "kitchen_number": "028",
      "status": "received",
      "status_changed_at": "2027-01-15T11:43:40+01:00",
      "created_at": "2027-01-15T11:42:31+01:00",
      "payment_deadline": null,
      "fulfillment": {
        "type": "pickup",
        "speed": "standard",
        "asap": true,
        "time": null,
        "estimated_at": "2027-01-15T12:05:00+01:00"
      },
      "customer": {
        "customer_id": null,
        "name": "Jana Nováková",
        "phone": "+420777123456",
        "email": "jana.novakova@example.cz"
      },
      "delivery": null,
      "lines": [
        {
          "id": "1",
          "type": "product",
          "variant": "full",
          "product_id": "4567",
          "name": "Svíčková na smetaně, houskový knedlík",
          "quantity": 2,
          "base_unit_price": {
            "amount": 19900,
            "currency": "CZK"
          },
          "unit_price": {
            "amount": 19900,
            "currency": "CZK"
          },
          "packaging_unit_price": null,
          "vat_rate": "12",
          "add_ons": [],
          "options": [],
          "parts": null,
          "removed_ingredients": [],
          "note": null,
          "total": {
            "amount": 39800,
            "currency": "CZK"
          },
          "gift_of": null
        }
      ],
      "charges": [],
      "discounts": [],
      "totals": {
        "items": {
          "amount": 39800,
          "currency": "CZK"
        },
        "charges": {
          "amount": 0,
          "currency": "CZK"
        },
        "discounts": {
          "amount": 0,
          "currency": "CZK"
        },
        "rounding": {
          "amount": 0,
          "currency": "CZK"
        },
        "total": {
          "amount": 39800,
          "currency": "CZK"
        },
        "vat": [
          {
            "rate": "12",
            "base": {
              "amount": 35536,
              "currency": "CZK"
            },
            "vat": {
              "amount": 4264,
              "currency": "CZK"
            },
            "total": {
              "amount": 39800,
              "currency": "CZK"
            }
          }
        ]
      },
      "payments": [
        {
          "id": "301878",
          "method": "online",
          "status": "paid",
          "amount": {
            "amount": 39800,
            "currency": "CZK"
          },
          "provider": "gopay",
          "reference": "3260145812",
          "voucher_code": null,
          "forfeited": null
        }
      ],
      "amount_to_collect": {
        "amount": 0,
        "currency": "CZK"
      },
      "loyalty_points_earned": null,
      "note": null,
      "cancellation": null,
      "eet": null,
      "external_id": "A-2027-000124",
      "metadata": {
        "branch": "praha-3"
      }
    }
  9. Sledujte, co se děje

    Follow what happens

    GET /events · listEvents

    Ptejte se s posledním next_cursor (třeba každých pár sekund nebo po webhooku) a kurzor si uložte až po zpracování. Neznámé typy událostí přeskočte.

    Ask with the latest next_cursor (every few seconds or after a webhook) and store the cursor only after processing. Skip event types you do not know.

    curl "https://api.mujprofirest.cz/v2/events?cursor=eyJzZXEiOjkxMDU1MH0&restaurant_id=123&limit=100" \
      -H "Authorization: Bearer $ACCESS_TOKEN"
    curl "https://api.mujprofirest.cz/v2/events?cursor=eyJzZXEiOjkxMDU1MH0&restaurant_id=123&limit=100" \
      -H "Authorization: Bearer $ACCESS_TOKEN"
    // klient: viz /v2/docs/js
    const feed = api.watchEvents({
      restaurantId: '123',
      onEvents: async (events) => {
        for (const event of events) handle(event); // kurzor se posune až potom
      },
      onReset: () => reloadEverything(), // 410 cursor_expired: načtěte stav znovu
    });
    // the client: see /v2/docs/js
    const feed = api.watchEvents({
      restaurantId: '123',
      onEvents: async (events) => {
        for (const event of events) handle(event); // the cursor moves only afterwards
      },
      onReset: () => reloadEverything(), // 410 cursor_expired: reload the state
    });
    // klient: viz /v2/docs/typescript
    const feed = api.watchEvents({
      restaurantId: '123',
      onEvents: async (events) => {
        for (const event of events) handle(event); // kurzor se posune až potom
      },
      onReset: () => reloadEverything(), // 410 cursor_expired: načtěte stav znovu
    });
    // the client: see /v2/docs/typescript
    const feed = api.watchEvents({
      restaurantId: '123',
      onEvents: async (events) => {
        for (const event of events) handle(event); // the cursor moves only afterwards
      },
      onReset: () => reloadEverything(), // 410 cursor_expired: reload the state
    });
    // klient: viz /v2/docs/php
    $api->watchEvents([
        'restaurantId' => '123',
        'onEvents' => function (array $events): void {
            foreach ($events as $event) { handle($event); } // kurzor se posune až potom
        },
        'onReset' => fn() => reloadEverything(), // 410 cursor_expired: načtěte stav znovu
    ])->run();
    // the client: see /v2/docs/php
    $api->watchEvents([
        'restaurantId' => '123',
        'onEvents' => function (array $events): void {
            foreach ($events as $event) { handle($event); } // the cursor moves only afterwards
        },
        'onReset' => fn() => reloadEverything(), // 410 cursor_expired: reload the state
    ])->run();
    // klient: viz /v2/docs/java
    // volání blokuje – na Androidu z pracovního vlákna (Dispatchers.IO)
    EventWatcher feed = api.watchEvents(WatchOptions.builder()
            .restaurantId("123")
            .onEvents(events -> events.forEach(this::handle)) // kurzor se posune až potom
            .onReset(error -> reloadEverything()) // 410 cursor_expired: načtěte stav znovu
            .build());
    feed.start();
    // the client: see /v2/docs/java
    // the call blocks – on Android from a worker thread (Dispatchers.IO)
    EventWatcher feed = api.watchEvents(WatchOptions.builder()
            .restaurantId("123")
            .onEvents(events -> events.forEach(this::handle)) // the cursor moves only afterwards
            .onReset(error -> reloadEverything()) // 410 cursor_expired: reload the state
            .build());
    feed.start();
    // klient: viz /v2/docs/java
    // volání blokuje – na Androidu z pracovního vlákna (Dispatchers.IO)
    val feed = api.watchEvents(WatchOptions.builder()
        .restaurantId("123")
        .onEvents { events -> events.forEach { handle(it) } } // kurzor se posune až potom
        .onReset { reloadEverything() } // 410 cursor_expired: načtěte stav znovu
        .build())
    feed.start()
    // the client: see /v2/docs/java
    // the call blocks – on Android from a worker thread (Dispatchers.IO)
    val feed = api.watchEvents(WatchOptions.builder()
        .restaurantId("123")
        .onEvents { events -> events.forEach { handle(it) } } // the cursor moves only afterwards
        .onReset { reloadEverything() } // 410 cursor_expired: reload the state
        .build())
    feed.start()
    // klient: viz /v2/docs/csharp
    await api.WatchEventsAsync(new WatchOptions
    {
        RestaurantId = "123",
        OnEvents = async (events, ct) => { foreach (var e in events) await HandleAsync(e, ct); }, // kurzor se posune až potom
        OnReset = _ => ReloadEverythingAsync(), // 410 cursor_expired: načtěte stav znovu
    }, stoppingToken);
    // the client: see /v2/docs/csharp
    await api.WatchEventsAsync(new WatchOptions
    {
        RestaurantId = "123",
        OnEvents = async (events, ct) => { foreach (var e in events) await HandleAsync(e, ct); }, // the cursor moves only afterwards
        OnReset = _ => ReloadEverythingAsync(), // 410 cursor_expired: reload the state
    }, stoppingToken);
    # klient: viz /v2/docs/python
    feed = api.watch_events(
        lambda events: [handle(event) for event in events],  # kurzor se posune až potom
        restaurant_id='123',
        on_reset=lambda error: reload_everything(),  # 410 cursor_expired: načtěte stav znovu
    )
    feed.start()
    # the client: see /v2/docs/python
    feed = api.watch_events(
        lambda events: [handle(event) for event in events],  # the cursor moves only afterwards
        restaurant_id='123',
        on_reset=lambda error: reload_everything(),  # 410 cursor_expired: reload the state
    )
    feed.start()
    // klient: viz /v2/docs/swift
    let feed = api.watchEvents(.init(
        restaurantID: "123",
        onEvents: { events in for event in events { handle(event) } }, // kurzor se posune až potom
        onReset: { _ in reloadEverything() } // 410 cursor_expired: načtěte stav znovu
    ))
    // feed.cancel() čtení ukončí
    // the client: see /v2/docs/swift
    let feed = api.watchEvents(.init(
        restaurantID: "123",
        onEvents: { events in for event in events { handle(event) } }, // the cursor moves only afterwards
        onReset: { _ in reloadEverything() } // 410 cursor_expired: reload the state
    ))
    // feed.cancel() čtení ukončí
    // klient: viz /v2/docs/dart
    final feed = api.watchEvents(
      restaurantId: '123',
      onEvents: (events) async { for (final event in events) handle(event); }, // kurzor se posune až potom
      onReset: (error) => reloadEverything(), // 410 cursor_expired: načtěte stav znovu
    )..start();
    // the client: see /v2/docs/dart
    final feed = api.watchEvents(
      restaurantId: '123',
      onEvents: (events) async { for (final event in events) handle(event); }, // the cursor moves only afterwards
      onReset: (error) => reloadEverything(), // 410 cursor_expired: reload the state
    )..start();
    // klient: viz /v2/docs/go
    err := api.WatchEvents(ctx, profirest.WatchOptions{
    	RestaurantID: "123",
    	OnEvents: func(ctx context.Context, events []model.Event) error {
    		for _, event := range events {
    			handle(event) // kurzor se posune až potom
    		}
    		return nil
    	},
    	OnReset: func(*profirest.APIError) { reloadEverything() }, // 410 cursor_expired: načtěte stav znovu
    })
    // the client: see /v2/docs/go
    err := api.WatchEvents(ctx, profirest.WatchOptions{
    	RestaurantID: "123",
    	OnEvents: func(ctx context.Context, events []model.Event) error {
    		for _, event := range events {
    			handle(event) // the cursor moves only afterwards
    		}
    		return nil
    	},
    	OnReset: func(*profirest.APIError) { reloadEverything() }, // 410 cursor_expired: reload the state
    })
    Příklad odpovědi 200Example answer 200
    {
      "data": [
        {
          "id": "910551",
          "api_version": "2",
          "sequence": 910551,
          "type": "order.created",
          "occurred_at": "2027-01-15T11:42:31+01:00",
          "connection_id": "2208",
          "account_id": "7",
          "restaurant_id": "123",
          "data": {
            "id": "184223",
            "restaurant_id": "123",
            "kitchen_number": "027",
            "status": "received",
            "status_changed_at": "2027-01-15T11:42:31+01:00",
            "created_at": "2027-01-15T11:42:31+01:00",
            "payment_deadline": null,
            "fulfillment": {
              "type": "pickup",
              "speed": "standard",
              "asap": true,
              "time": null,
              "estimated_at": "2027-01-15T12:05:00+01:00"
            },
            "customer": {
              "customer_id": null,
              "name": "Jana Nováková",
              "phone": "+420777123456",
              "email": "jana.novakova@example.cz"
            },
            "delivery": null,
            "lines": [
              {
                "id": "1",
                "type": "product",
                "product_id": "4567",
                "name": "Svíčková na smetaně, houskový knedlík",
                "quantity": 2,
                "base_unit_price": {
                  "amount": 19900,
                  "currency": "CZK"
                },
                "unit_price": {
                  "amount": 19900,
                  "currency": "CZK"
                },
                "packaging_unit_price": null,
                "vat_rate": "12",
                "add_ons": [],
                "options": [],
                "parts": null,
                "removed_ingredients": [],
                "note": null,
                "total": {
                  "amount": 39800,
                  "currency": "CZK"
                },
                "gift_of": null
              }
            ],
            "charges": [],
            "discounts": [],
            "totals": {
              "items": {
                "amount": 39800,
                "currency": "CZK"
              },
              "charges": {
                "amount": 0,
                "currency": "CZK"
              },
              "discounts": {
                "amount": 0,
                "currency": "CZK"
              },
              "rounding": {
                "amount": 0,
                "currency": "CZK"
              },
              "total": {
                "amount": 39800,
                "currency": "CZK"
              },
              "vat": [
                {
                  "rate": "12",
                  "base": {
                    "amount": 35536,
                    "currency": "CZK"
                  },
                  "vat": {
                    "amount": 4264,
                    "currency": "CZK"
                  },
                  "total": {
                    "amount": 39800,
                    "currency": "CZK"
                  }
                }
              ]
            },
            "payments": [
              {
                "id": "301877",
                "method": "cash",
                "status": "unpaid",
                "amount": {
                  "amount": 39800,
                  "currency": "CZK"
                },
                "provider": null,
                "reference": null,
                "voucher_code": null,
                "forfeited": null
              }
            ],
            "amount_to_collect": {
              "amount": 39800,
              "currency": "CZK"
            },
            "loyalty_points_earned": null,
            "note": null,
            "cancellation": null,
            "external_id": "A-2027-000123",
            "metadata": {
              "branch": "praha-3"
            }
          }
        },
        {
          "id": "910563",
          "api_version": "2",
          "sequence": 910563,
          "type": "order.status_changed",
          "occurred_at": "2027-01-15T11:44:02+01:00",
          "connection_id": "2208",
          "account_id": "7",
          "restaurant_id": "123",
          "data": {
            "id": "184223",
            "restaurant_id": "123",
            "kitchen_number": "027",
            "status": "preparing",
            "status_changed_at": "2027-01-15T11:44:02+01:00",
            "created_at": "2027-01-15T11:42:31+01:00",
            "payment_deadline": null,
            "fulfillment": {
              "type": "pickup",
              "speed": "standard",
              "asap": true,
              "time": null,
              "estimated_at": "2027-01-15T12:05:00+01:00"
            },
            "customer": {
              "customer_id": null,
              "name": "Jana Nováková",
              "phone": "+420777123456",
              "email": "jana.novakova@example.cz"
            },
            "delivery": null,
            "lines": [
              {
                "id": "1",
                "type": "product",
                "product_id": "4567",
                "name": "Svíčková na smetaně, houskový knedlík",
                "quantity": 2,
                "base_unit_price": {
                  "amount": 19900,
                  "currency": "CZK"
                },
                "unit_price": {
                  "amount": 19900,
                  "currency": "CZK"
                },
                "packaging_unit_price": null,
                "vat_rate": "12",
                "add_ons": [],
                "options": [],
                "parts": null,
                "removed_ingredients": [],
                "note": null,
                "total": {
                  "amount": 39800,
                  "currency": "CZK"
                },
                "gift_of": null
              }
            ],
            "charges": [],
            "discounts": [],
            "totals": {
              "items": {
                "amount": 39800,
                "currency": "CZK"
              },
              "charges": {
                "amount": 0,
                "currency": "CZK"
              },
              "discounts": {
                "amount": 0,
                "currency": "CZK"
              },
              "rounding": {
                "amount": 0,
                "currency": "CZK"
              },
              "total": {
                "amount": 39800,
                "currency": "CZK"
              },
              "vat": [
                {
                  "rate": "12",
                  "base": {
                    "amount": 35536,
                    "currency": "CZK"
                  },
                  "vat": {
                    "amount": 4264,
                    "currency": "CZK"
                  },
                  "total": {
                    "amount": 39800,
                    "currency": "CZK"
                  }
                }
              ]
            },
            "payments": [
              {
                "id": "301877",
                "method": "cash",
                "status": "unpaid",
                "amount": {
                  "amount": 39800,
                  "currency": "CZK"
                },
                "provider": null,
                "reference": null,
                "voucher_code": null,
                "forfeited": null
              }
            ],
            "amount_to_collect": {
              "amount": 39800,
              "currency": "CZK"
            },
            "loyalty_points_earned": null,
            "note": null,
            "cancellation": null,
            "external_id": "A-2027-000123",
            "metadata": {
              "branch": "praha-3"
            }
          }
        },
        {
          "id": "910570",
          "api_version": "2",
          "sequence": 910570,
          "type": "availability.changed",
          "occurred_at": "2027-01-15T11:45:10+01:00",
          "connection_id": "2208",
          "account_id": "7",
          "restaurant_id": "123",
          "data": {
            "restaurant_id": "123"
          }
        }
      ],
      "next_cursor": "eyJzZXEiOjkxMDU3MH0"
    }

Scénář

Scenario

Pokladna

A cash register

Vlastní zařízení ProfirestuProfirest's own device

Pokladna se spáruje kódem, přihlásí obsluhu PINem, drží účty stolů, vystavuje účtenky a na konci dne uzavře směnu. Účtenky počítá i eviduje v EET 2.0 server – zařízení nepotřebuje certifikát.

A register pairs by code, signs the staff in with a PIN, keeps table tabs, issues receipts and closes the shift at the end of the day. The server computes the receipts and records them in EET 2.0 – the device needs no certificate.

  1. Spárujte pokladnu kódem

    Pair the register by code

    POST /oauth/device_authorization · oauthDeviceAuthorization

    Zařízení je veřejný klient bez tajemství. Ukažte user_code nebo QR kód verification_uri_complete; vedoucí ho potvrdí v administraci (Správa PC / zařízení → Připojit kódem) a vybere provozovnu. Kód platí 10 minut.

    A device is a public client without a secret. Show user_code or a QR code of verification_uri_complete; a manager confirms it in the administration and picks the restaurant. The code is valid for 10 minutes.

    Nastavení › Správa PC / zařízení › Připojit kódem: vedoucí potvrdí kód ze zařízení a vybere provozovnu.
    Nastavení › Správa PC / zařízení › Připojit kódem: vedoucí potvrdí kód ze zařízení a vybere provozovnu.Settings › PCs / devices › Connect by code: a manager confirms the code from the device and picks the restaurant.
    curl "https://api.mujprofirest.cz/oauth/device_authorization" \
      -d client_id=profirest-pos \
      --data-urlencode 'scope=restaurants:read catalog:read staff:read staff:authenticate receipts:read receipts:write' \
      --data-urlencode 'device_name=Pokladna u baru' \
      -d device_platform=android \
      -d app_version=3.4.1
    curl "https://api.mujprofirest.cz/oauth/device_authorization" \
      -d client_id=profirest-pos \
      --data-urlencode 'scope=restaurants:read catalog:read staff:read staff:authenticate receipts:read receipts:write' \
      --data-urlencode 'device_name=Pokladna u baru' \
      -d device_platform=android \
      -d app_version=3.4.1
    // klient: viz /v2/docs/js
    const pairing = await api.pair({
      scope: 'restaurants:read catalog:read staff:read staff:authenticate receipts:read receipts:write',
      deviceName: 'Pokladna u baru',
      appVersion: '3.4.1',
    });
    showCode(pairing.userCode, pairing.verificationUriComplete); // kód a QR na displej
    const connection = await pairing.connected; // po potvrzení v administraci
    // the client: see /v2/docs/js
    const pairing = await api.pair({
      scope: 'restaurants:read catalog:read staff:read staff:authenticate receipts:read receipts:write',
      deviceName: 'Pokladna u baru',
      appVersion: '3.4.1',
    });
    showCode(pairing.userCode, pairing.verificationUriComplete); // the code and a QR code on the screen
    const connection = await pairing.connected; // after the confirmation in the administration
    // klient: viz /v2/docs/typescript
    const pairing = await api.pair({
      scope: 'restaurants:read catalog:read staff:read staff:authenticate receipts:read receipts:write',
      deviceName: 'Pokladna u baru',
      appVersion: '3.4.1',
    });
    showCode(pairing.userCode, pairing.verificationUriComplete); // kód a QR na displej
    const connection = await pairing.connected; // po potvrzení v administraci
    // the client: see /v2/docs/typescript
    const pairing = await api.pair({
      scope: 'restaurants:read catalog:read staff:read staff:authenticate receipts:read receipts:write',
      deviceName: 'Pokladna u baru',
      appVersion: '3.4.1',
    });
    showCode(pairing.userCode, pairing.verificationUriComplete); // the code and a QR code on the screen
    const connection = await pairing.connected; // after the confirmation in the administration
    // klient: viz /v2/docs/php
    $pairing = $api->pair(scope: 'restaurants:read catalog:read staff:read staff:authenticate receipts:read receipts:write', deviceName: 'Pokladna u baru', appVersion: '3.4.1');
    showCode($pairing->userCode, $pairing->verificationUriComplete); // kód a QR na displej
    $connection = $pairing->wait(); // po potvrzení v administraci
    // the client: see /v2/docs/php
    $pairing = $api->pair(scope: 'restaurants:read catalog:read staff:read staff:authenticate receipts:read receipts:write', deviceName: 'Pokladna u baru', appVersion: '3.4.1');
    showCode($pairing->userCode, $pairing->verificationUriComplete); // the code and a QR code on the screen
    $connection = $pairing->wait(); // after the confirmation in the administration
    // klient: viz /v2/docs/java
    // volání blokuje – na Androidu z pracovního vlákna (Dispatchers.IO)
    Pairing pairing = api.pair(PairOptions.builder()
            .scope("restaurants:read catalog:read staff:read staff:authenticate receipts:read receipts:write")
            .deviceName("Pokladna u baru")
            .appVersion("3.4.1")
            .build());
    showCode(pairing.getUserCode(), pairing.getVerificationUriComplete()); // kód a QR na displej
    Map<String, Object> connection = pairing.awaitConnected(); // po potvrzení v administraci
    // the client: see /v2/docs/java
    // the call blocks – on Android from a worker thread (Dispatchers.IO)
    Pairing pairing = api.pair(PairOptions.builder()
            .scope("restaurants:read catalog:read staff:read staff:authenticate receipts:read receipts:write")
            .deviceName("Pokladna u baru")
            .appVersion("3.4.1")
            .build());
    showCode(pairing.getUserCode(), pairing.getVerificationUriComplete()); // the code and a QR code on the screen
    Map<String, Object> connection = pairing.awaitConnected(); // after the confirmation in the administration
    // klient: viz /v2/docs/java
    // volání blokuje – na Androidu z pracovního vlákna (Dispatchers.IO)
    val pairing = api.pair(PairOptions.builder()
        .scope("restaurants:read catalog:read staff:read staff:authenticate receipts:read receipts:write")
        .deviceName("Pokladna u baru")
        .appVersion("3.4.1")
        .build())
    showCode(pairing.userCode, pairing.verificationUriComplete) // kód a QR na displej
    val connection = pairing.awaitConnected() // po potvrzení v administraci
    // the client: see /v2/docs/java
    // the call blocks – on Android from a worker thread (Dispatchers.IO)
    val pairing = api.pair(PairOptions.builder()
        .scope("restaurants:read catalog:read staff:read staff:authenticate receipts:read receipts:write")
        .deviceName("Pokladna u baru")
        .appVersion("3.4.1")
        .build())
    showCode(pairing.userCode, pairing.verificationUriComplete) // the code and a QR code on the screen
    val connection = pairing.awaitConnected() // after the confirmation in the administration
    // klient: viz /v2/docs/csharp
    Pairing pairing = await api.PairAsync(new PairOptions
    {
        Scope = "restaurants:read catalog:read staff:read staff:authenticate receipts:read receipts:write",
        DeviceName = "Pokladna u baru",
        AppVersion = "3.4.1",
    });
    ShowCode(pairing.UserCode, pairing.VerificationUriComplete); // kód a QR na displej
    Connection? connection = await pairing.Connected; // po potvrzení v administraci
    // the client: see /v2/docs/csharp
    Pairing pairing = await api.PairAsync(new PairOptions
    {
        Scope = "restaurants:read catalog:read staff:read staff:authenticate receipts:read receipts:write",
        DeviceName = "Pokladna u baru",
        AppVersion = "3.4.1",
    });
    ShowCode(pairing.UserCode, pairing.VerificationUriComplete); // the code and a QR code on the screen
    Connection? connection = await pairing.Connected; // after the confirmation in the administration
    # klient: viz /v2/docs/python
    pairing = api.pair(scope='restaurants:read catalog:read staff:read staff:authenticate receipts:read receipts:write', device_name='Pokladna u baru', app_version='3.4.1')
    show_code(pairing.user_code, pairing.verification_uri_complete)  # kód a QR na displej
    connection = pairing.wait()  # po potvrzení v administraci
    # the client: see /v2/docs/python
    pairing = api.pair(scope='restaurants:read catalog:read staff:read staff:authenticate receipts:read receipts:write', device_name='Pokladna u baru', app_version='3.4.1')
    show_code(pairing.user_code, pairing.verification_uri_complete)  # the code and a QR code on the screen
    connection = pairing.wait()  # after the confirmation in the administration
    // klient: viz /v2/docs/swift
    let pairing = try await api.pair(scope: "restaurants:read catalog:read staff:read staff:authenticate receipts:read receipts:write", deviceName: "Pokladna u baru", appVersion: "3.4.1")
    showCode(pairing.userCode, pairing.verificationURIComplete) // kód a QR na displej
    let connection = try await pairing.connected() // po potvrzení v administraci
    // the client: see /v2/docs/swift
    let pairing = try await api.pair(scope: "restaurants:read catalog:read staff:read staff:authenticate receipts:read receipts:write", deviceName: "Pokladna u baru", appVersion: "3.4.1")
    showCode(pairing.userCode, pairing.verificationURIComplete) // the code and a QR code on the screen
    let connection = try await pairing.connected() // after the confirmation in the administration
    // klient: viz /v2/docs/dart
    final pairing = await api.pair(scope: 'restaurants:read catalog:read staff:read staff:authenticate receipts:read receipts:write', deviceName: 'Pokladna u baru', appVersion: '3.4.1');
    showCode(pairing.userCode, pairing.verificationUriComplete); // kód a QR na displej
    final connection = await pairing.connected; // po potvrzení v administraci
    // the client: see /v2/docs/dart
    final pairing = await api.pair(scope: 'restaurants:read catalog:read staff:read staff:authenticate receipts:read receipts:write', deviceName: 'Pokladna u baru', appVersion: '3.4.1');
    showCode(pairing.userCode, pairing.verificationUriComplete); // the code and a QR code on the screen
    final connection = await pairing.connected; // after the confirmation in the administration
    // klient: viz /v2/docs/go
    pairing, err := api.Pair(ctx, profirest.PairOptions{
    	Scope:      "restaurants:read catalog:read staff:read staff:authenticate receipts:read receipts:write",
    	DeviceName: "Pokladna u baru",
    	AppVersion: "3.4.1",
    })
    showCode(pairing.UserCode, pairing.VerificationURIComplete) // kód a QR na displej
    connection, err := pairing.Wait(ctx) // po potvrzení v administraci
    // the client: see /v2/docs/go
    pairing, err := api.Pair(ctx, profirest.PairOptions{
    	Scope:      "restaurants:read catalog:read staff:read staff:authenticate receipts:read receipts:write",
    	DeviceName: "Pokladna u baru",
    	AppVersion: "3.4.1",
    })
    showCode(pairing.UserCode, pairing.VerificationURIComplete) // the code and a QR code on the screen
    connection, err := pairing.Wait(ctx) // after the confirmation in the administration
    Příklad odpovědi 200Example answer 200
    {
      "device_code": "pfd_CkWGM50A5JhqtDG1-YhmK69pAlM0TblR7bOxnjTGxAQ",
      "user_code": "BCDF-GHJK",
      "verification_uri": "https://www.mujprofirest.cz/zarizeni",
      "verification_uri_complete": "https://www.mujprofirest.cz/zarizeni?code=BCDFGHJK",
      "expires_in": 600,
      "interval": 5
    }
  2. Vyzvedněte tokeny

    Pick up the tokens

    POST /oauth/token · oauthToken

    Ptejte se každých interval sekund. Do potvrzení přijde authorization_pending, při slow_down přidejte 5 sekund, access_denied znamená odmítnutí a expired_token propadlý kód.

    Ask every interval seconds. Until the confirmation you get authorization_pending; on slow_down add 5 seconds, access_denied means a refusal and expired_token an expired code.

    curl "https://api.mujprofirest.cz/oauth/token" \
      -d grant_type=urn:ietf:params:oauth:grant-type:device_code \
      -d device_code=pfd_CkWGM50A5JhqtDG1-YhmK69pAlM0TblR7bOxnjTGxAQ \
      -d client_id=profirest-pos
    curl "https://api.mujprofirest.cz/oauth/token" \
      -d grant_type=urn:ietf:params:oauth:grant-type:device_code \
      -d device_code=pfd_CkWGM50A5JhqtDG1-YhmK69pAlM0TblR7bOxnjTGxAQ \
      -d client_id=profirest-pos
    // klient: viz /v2/docs/js
    // tokeny vyzvedne a obnovuje knihovna sama (párování nebo dokončení souhlasu); obnova minutu před koncem, jen jednou
    const connection = await api.connection();
    // the client: see /v2/docs/js
    // the library picks up and refreshes the tokens itself (pairing or completing the consent); refreshed a minute early, once
    const connection = await api.connection();
    // klient: viz /v2/docs/typescript
    // tokeny vyzvedne a obnovuje knihovna sama (párování nebo dokončení souhlasu); obnova minutu před koncem, jen jednou
    const connection = await api.connection();
    // the client: see /v2/docs/typescript
    // the library picks up and refreshes the tokens itself (pairing or completing the consent); refreshed a minute early, once
    const connection = await api.connection();
    // klient: viz /v2/docs/php
    // tokeny vyzvedne a obnovuje knihovna sama (párování nebo dokončení souhlasu); obnova minutu před koncem, jen jednou
    $connection = $api->connection();
    // the client: see /v2/docs/php
    // the library picks up and refreshes the tokens itself (pairing or completing the consent); refreshed a minute early, once
    $connection = $api->connection();
    // klient: viz /v2/docs/java
    // volání blokuje – na Androidu z pracovního vlákna (Dispatchers.IO)
    // tokeny vyzvedne a obnovuje knihovna sama (párování nebo dokončení souhlasu); obnova minutu před koncem, jen jednou
    Map<String, Object> connection = api.connection();
    // the client: see /v2/docs/java
    // the call blocks – on Android from a worker thread (Dispatchers.IO)
    // the library picks up and refreshes the tokens itself (pairing or completing the consent); refreshed a minute early, once
    Map<String, Object> connection = api.connection();
    // klient: viz /v2/docs/java
    // volání blokuje – na Androidu z pracovního vlákna (Dispatchers.IO)
    // tokeny vyzvedne a obnovuje knihovna sama (párování nebo dokončení souhlasu); obnova minutu před koncem, jen jednou
    val connection = api.connection()
    // the client: see /v2/docs/java
    // the call blocks – on Android from a worker thread (Dispatchers.IO)
    // the library picks up and refreshes the tokens itself (pairing or completing the consent); refreshed a minute early, once
    val connection = api.connection()
    // klient: viz /v2/docs/csharp
    // tokeny vyzvedne a obnovuje knihovna sama (párování nebo dokončení souhlasu); obnova minutu před koncem, jen jednou
    Connection? connection = await api.ConnectionAsync();
    // the client: see /v2/docs/csharp
    // the library picks up and refreshes the tokens itself (pairing or completing the consent); refreshed a minute early, once
    Connection? connection = await api.ConnectionAsync();
    # klient: viz /v2/docs/python
    # tokeny vyzvedne a obnovuje knihovna sama (párování nebo dokončení souhlasu); obnova minutu před koncem, jen jednou
    connection = api.connection()
    # the client: see /v2/docs/python
    # the library picks up and refreshes the tokens itself (pairing or completing the consent); refreshed a minute early, once
    connection = api.connection()
    // klient: viz /v2/docs/swift
    // tokeny vyzvedne a obnovuje knihovna sama (párování nebo dokončení souhlasu); obnova minutu před koncem, jen jednou
    let connection = try await api.connection()
    // the client: see /v2/docs/swift
    // the library picks up and refreshes the tokens itself (pairing or completing the consent); refreshed a minute early, once
    let connection = try await api.connection()
    // klient: viz /v2/docs/dart
    // tokeny vyzvedne a obnovuje knihovna sama (párování nebo dokončení souhlasu); obnova minutu před koncem, jen jednou
    final connection = await api.connection();
    // the client: see /v2/docs/dart
    // the library picks up and refreshes the tokens itself (pairing or completing the consent); refreshed a minute early, once
    final connection = await api.connection();
    // klient: viz /v2/docs/go
    // tokeny vyzvedne a obnovuje knihovna sama (párování nebo dokončení souhlasu); obnova minutu před koncem, jen jednou
    connection, err := api.Connection(ctx)
    // the client: see /v2/docs/go
    // the library picks up and refreshes the tokens itself (pairing or completing the consent); refreshed a minute early, once
    connection, err := api.Connection(ctx)
    Příklad odpovědi 200Example answer 200
    {
      "access_token": "pfa_oFYf1knNtrqnhAVfBRuteW6gr-8X_KOCGVSd7rpOjBo",
      "token_type": "Bearer",
      "expires_in": 1800,
      "refresh_token": "pfr_1swKCIwHaDxlzSZoYMq42Us6GTexdCDZ2jDKKZwJ-3c",
      "refresh_token_expires_in": 7776000,
      "scope": "restaurants:read catalog:read orders:write orders:read"
    }
  3. Načtěte nastavení

    Load the settings

    GET /restaurants/{restaurant_id}/device-settings · getDeviceSettings

    Firma na účtenku, tiskárny, stanoviště, místnosti se stoly, EET 2.0 a funkce licence.

    The company for the receipt, printers, stations, rooms with tables, EET 2.0 and licence features.

    curl "https://api.mujprofirest.cz/v2/restaurants/123/device-settings" \
      -H "Authorization: Bearer $ACCESS_TOKEN"
    curl "https://api.mujprofirest.cz/v2/restaurants/123/device-settings" \
      -H "Authorization: Bearer $ACCESS_TOKEN"
    // klient: viz /v2/docs/js
    const deviceSettings = await api.get('/restaurants/123/device-settings'); // 200
    // the client: see /v2/docs/js
    const deviceSettings = await api.get('/restaurants/123/device-settings'); // 200
    // klient: viz /v2/docs/typescript
    const deviceSettings = await api.get('/restaurants/123/device-settings'); // 200 DeviceSettings
    // the client: see /v2/docs/typescript
    const deviceSettings = await api.get('/restaurants/123/device-settings'); // 200 DeviceSettings
    // klient: viz /v2/docs/php
    $deviceSettings = $api->get('/restaurants/123/device-settings'); // 200
    // the client: see /v2/docs/php
    $deviceSettings = $api->get('/restaurants/123/device-settings'); // 200
    // klient: viz /v2/docs/java
    // volání blokuje – na Androidu z pracovního vlákna (Dispatchers.IO)
    DeviceSettings deviceSettings = api.get("/restaurants/123/device-settings", DeviceSettings::fromJson); // 200
    // the client: see /v2/docs/java
    // the call blocks – on Android from a worker thread (Dispatchers.IO)
    DeviceSettings deviceSettings = api.get("/restaurants/123/device-settings", DeviceSettings::fromJson); // 200
    // klient: viz /v2/docs/java
    // volání blokuje – na Androidu z pracovního vlákna (Dispatchers.IO)
    val deviceSettings = api.get("/restaurants/123/device-settings", DeviceSettings::fromJson) // 200
    // the client: see /v2/docs/java
    // the call blocks – on Android from a worker thread (Dispatchers.IO)
    val deviceSettings = api.get("/restaurants/123/device-settings", DeviceSettings::fromJson) // 200
    // klient: viz /v2/docs/csharp
    var deviceSettings = await api.GetAsync<DeviceSettings>("/restaurants/123/device-settings"); // 200
    // the client: see /v2/docs/csharp
    var deviceSettings = await api.GetAsync<DeviceSettings>("/restaurants/123/device-settings"); // 200
    # klient: viz /v2/docs/python
    device_settings = api.get('/restaurants/123/device-settings')  # 200
    # the client: see /v2/docs/python
    device_settings = api.get('/restaurants/123/device-settings')  # 200
    // klient: viz /v2/docs/swift
    let deviceSettings: DeviceSettings = try await api.get("/restaurants/123/device-settings") // 200
    // the client: see /v2/docs/swift
    let deviceSettings: DeviceSettings = try await api.get("/restaurants/123/device-settings") // 200
    // klient: viz /v2/docs/dart
    final deviceSettings = pr.DeviceSettings.fromJson(await api.get('/restaurants/123/device-settings')); // 200
    // the client: see /v2/docs/dart
    final deviceSettings = pr.DeviceSettings.fromJson(await api.get('/restaurants/123/device-settings')); // 200
    // klient: viz /v2/docs/go
    res, err := api.Get(ctx, "/restaurants/123/device-settings", nil)
    var deviceSettings model.DeviceSettings // 200
    if err == nil {
    	err = res.Decode(&deviceSettings)
    }
    // the client: see /v2/docs/go
    res, err := api.Get(ctx, "/restaurants/123/device-settings", nil)
    var deviceSettings model.DeviceSettings // 200
    if err == nil {
    	err = res.Decode(&deviceSettings)
    }
    Příklad odpovědi 200Example answer 200
    {
      "restaurant": {
        "name": "Bistro U Lípy",
        "phone": "+420222333444",
        "website": "https://www.bistroulipy.cz",
        "address": {
          "street": "Vinohradská 1200/48",
          "city": "Praha 2",
          "postal_code": "120 00"
        },
        "location": {
          "lat": 50.0769,
          "lon": 14.4459
        },
        "currency": "CZK",
        "timezone": "Europe/Prague"
      },
      "company": {
        "name": "U Lípy gastro s.r.o.",
        "registration_number": "12345678",
        "vat_number": "CZ12345678",
        "vat_payer": true,
        "address": {
          "street": "Vinohradská 1200/48",
          "city": "Praha 2",
          "postal_code": "120 00"
        },
        "email": "ucetni@bistroulipy.cz"
      },
      "receipt_layouts": {
        "receipt": null,
        "takeaway": null
      },
      "predefined_notes": [
        {
          "id": "11",
          "text": "Bez cibule"
        },
        {
          "id": "12",
          "text": "Pálivé"
        },
        {
          "id": "13",
          "text": "S sebou"
        }
      ],
      "printers": [
        {
          "id": "5",
          "name": "Účtenky – bar",
          "sections": "all",
          "auto_print": false
        },
        {
          "id": "6",
          "name": "Bony – kuchyň",
          "sections": "kitchen",
          "auto_print": true
        }
      ],
      "kitchen_stations": [
        {
          "id": "2",
          "name": "Teplá kuchyně",
          "sections": "kitchen",
          "auto_print": false
        },
        {
          "id": "3",
          "name": "Pizza",
          "sections": "kitchen",
          "auto_print": false
        }
      ],
      "rooms": [
        {
          "id": "1",
          "name": "Restaurace",
          "width": 100,
          "height": 100,
          "tables": [
            {
              "id": "4",
              "name": "Stůl 4",
              "kind": "table",
              "code": "K7M2Q9XB",
              "left": 12,
              "top": 20,
              "width": 14,
              "height": 10
            },
            {
              "id": "7",
              "name": "Stůl 7",
              "kind": "table",
              "code": "3HFD8R2W",
              "left": 52,
              "top": 20,
              "width": 14,
              "height": 10
            },
            {
              "id": "30",
              "name": "Bar",
              "kind": "item",
              "code": null,
              "left": 80,
              "top": 70,
              "width": 18,
              "height": 25
            }
          ]
        }
      ],
      "kitchen": {
        "portion_mode": "local",
        "extra_ticket": false,
        "redirect_restaurant_id": null,
        "ready_sms": true
      },
      "eet": {
        "enabled": true,
        "premises_id": "273",
        "certificate_valid_to": "2029-12-31T23:59:59+01:00"
      },
      "features": {
        "kitchen": true,
        "multiple_cash_registers": true,
        "multiple_kitchen_devices": true,
        "other_devices": true,
        "attendance": true,
        "reservations": false,
        "lodging": false,
        "daily_menu": true,
        "table_map": true,
        "customer_database": true
      },
      "paid_until": "2027-12-31T23:59:59+01:00",
      "table_ordering": {
        "enabled": true,
        "confirm_mode": "first",
        "empty_table": "staff",
        "join_code_enabled": true,
        "max_quantity": 10,
        "expire_minutes": 10,
        "respect_opening_hours": true,
        "category_ids": [
          "320"
        ],
        "note_max_length": 32,
        "wifi_ssid": "U Lípy – hosté"
      },
      "pos": {
        "receipt_cancel_by": "staff",
        "takeaway_only": false,
        "calculator": {
          "enabled": true,
          "keys": [
            {
              "id": "17",
              "name": "Pečivo",
              "vat_rate": "12",
              "color": "#119b2d",
              "position": 1
            },
            {
              "id": "18",
              "name": "Zboží",
              "vat_rate": "21",
              "color": "#5b4ac0",
              "position": 2
            }
          ]
        }
      }
    }
  4. Sortiment pokladny

    The register's catalog

    GET /restaurants/{restaurant_id}/catalog · getCatalog

    S channel=pos přijde sortiment pokladny včetně ceny půlky, ceny pro zaměstnance a PLU (Product.pos).

    With channel=pos you get the register's catalog including the half price, the employee price and the PLU (Product.pos).

    curl "https://api.mujprofirest.cz/v2/restaurants/123/catalog?channel=pos" \
      -H "Authorization: Bearer $ACCESS_TOKEN"
    curl "https://api.mujprofirest.cz/v2/restaurants/123/catalog?channel=pos" \
      -H "Authorization: Bearer $ACCESS_TOKEN"
    // klient: viz /v2/docs/js
    const catalog = await api.get('/restaurants/123/catalog', { query: { channel: 'pos' } }); // 200
    // the client: see /v2/docs/js
    const catalog = await api.get('/restaurants/123/catalog', { query: { channel: 'pos' } }); // 200
    // klient: viz /v2/docs/typescript
    const catalog = await api.get('/restaurants/123/catalog', { query: { channel: 'pos' } }); // 200 Catalog
    // the client: see /v2/docs/typescript
    const catalog = await api.get('/restaurants/123/catalog', { query: { channel: 'pos' } }); // 200 Catalog
    // klient: viz /v2/docs/php
    $catalog = $api->get('/restaurants/123/catalog', ['query' => ['channel' => 'pos']]); // 200
    // the client: see /v2/docs/php
    $catalog = $api->get('/restaurants/123/catalog', ['query' => ['channel' => 'pos']]); // 200
    // klient: viz /v2/docs/java
    // volání blokuje – na Androidu z pracovního vlákna (Dispatchers.IO)
    Catalog catalog = api.get(
        "/restaurants/123/catalog",
        RequestOptions.builder().query("channel", "pos").build(),
        Catalog::fromJson
    ); // 200
    // the client: see /v2/docs/java
    // the call blocks – on Android from a worker thread (Dispatchers.IO)
    Catalog catalog = api.get(
        "/restaurants/123/catalog",
        RequestOptions.builder().query("channel", "pos").build(),
        Catalog::fromJson
    ); // 200
    // klient: viz /v2/docs/java
    // volání blokuje – na Androidu z pracovního vlákna (Dispatchers.IO)
    val catalog = api.get(
        "/restaurants/123/catalog",
        RequestOptions.builder().query("channel", "pos").build(),
        Catalog::fromJson,
    ) // 200
    // the client: see /v2/docs/java
    // the call blocks – on Android from a worker thread (Dispatchers.IO)
    val catalog = api.get(
        "/restaurants/123/catalog",
        RequestOptions.builder().query("channel", "pos").build(),
        Catalog::fromJson,
    ) // 200
    // klient: viz /v2/docs/csharp
    var catalog = await api.GetAsync<Catalog>(
        "/restaurants/123/catalog",
        new RequestOptions { Query = new() { ["channel"] = "pos" } }
    ); // 200
    // the client: see /v2/docs/csharp
    var catalog = await api.GetAsync<Catalog>(
        "/restaurants/123/catalog",
        new RequestOptions { Query = new() { ["channel"] = "pos" } }
    ); // 200
    # klient: viz /v2/docs/python
    catalog = api.get('/restaurants/123/catalog', query={'channel': 'pos'})  # 200
    # the client: see /v2/docs/python
    catalog = api.get('/restaurants/123/catalog', query={'channel': 'pos'})  # 200
    // klient: viz /v2/docs/swift
    let catalog: Catalog = try await api.get("/restaurants/123/catalog", options: .init(query: ["channel": "pos"])) // 200
    // the client: see /v2/docs/swift
    let catalog: Catalog = try await api.get("/restaurants/123/catalog", options: .init(query: ["channel": "pos"])) // 200
    // klient: viz /v2/docs/dart
    final catalog = pr.Catalog.fromJson(await api.get('/restaurants/123/catalog', query: {'channel': 'pos'})); // 200
    // the client: see /v2/docs/dart
    final catalog = pr.Catalog.fromJson(await api.get('/restaurants/123/catalog', query: {'channel': 'pos'})); // 200
    // klient: viz /v2/docs/go
    res, err := api.Get(
    	ctx,
    	"/restaurants/123/catalog",
    	&profirest.RequestOptions{Query: map[string]any{"channel": "pos"}},
    )
    var catalog model.Catalog // 200
    if err == nil {
    	err = res.Decode(&catalog)
    }
    // the client: see /v2/docs/go
    res, err := api.Get(
    	ctx,
    	"/restaurants/123/catalog",
    	&profirest.RequestOptions{Query: map[string]any{"channel": "pos"}},
    )
    var catalog model.Catalog // 200
    if err == nil {
    	err = res.Decode(&catalog)
    }
    Příklad odpovědi 200Example answer 200
    {
      "restaurant_id": "123",
      "currency": "CZK",
      "at": "2027-01-15T11:42:00+01:00",
      "generated_at": "2027-01-15T11:40:00+01:00",
      "next_change_at": "2027-01-15T15:00:00+01:00",
      "categories": [
        {
          "id": "312",
          "name": "Hlavní jídla",
          "description": null,
          "image_url": null,
          "color": "#e53935",
          "icon": "fa-utensils",
          "position": 1,
          "external_id": null,
          "metadata": {}
        },
        {
          "id": "315",
          "name": "Pizza",
          "description": "Pečeme v peci na dřevo.",
          "image_url": null,
          "color": "#fb8c00",
          "icon": "fa-pizza-slice",
          "position": 2,
          "external_id": null,
          "metadata": {}
        },
        {
          "id": "320",
          "name": "Nápoje",
          "description": null,
          "image_url": null,
          "color": "#1e88e5",
          "icon": null,
          "position": 3,
          "external_id": null,
          "metadata": {}
        }
      ],
      "products": [
        {
          "id": "4567",
          "category_id": "312",
          "name": "Svíčková na smetaně, houskový knedlík",
          "description": "Hovězí svíčková, smetanová omáčka, brusinky, šlehačka.",
          "image_url": "https://www.mujprofirest.cz/data/products/4567.jpg",
          "price": {
            "amount": 19900,
            "currency": "CZK"
          },
          "vat_rate": "12",
          "packaging_fee": null,
          "weight": 150,
          "allergens": [
            "1",
            "3",
            "7",
            "9"
          ],
          "labels": [
            "home_made"
          ],
          "age_restricted": false,
          "add_ons": [],
          "option_groups": [],
          "removable_ingredients": [],
          "split": null,
          "half_price": null,
          "position": 1,
          "ean": null,
          "kitchen_name": null,
          "size": null,
          "pos": null,
          "external_id": null,
          "metadata": {}
        },
        {
          "id": "4568",
          "category_id": "312",
          "name": "Smažený sýr, hranolky, tatarská omáčka",
          "description": "Eidam 120 g, hranolky, domácí tatarská omáčka.",
          "image_url": null,
          "price": {
            "amount": 17900,
            "currency": "CZK"
          },
          "vat_rate": "12",
          "packaging_fee": null,
          "weight": 120,
          "allergens": [
            "1",
            "3",
            "7"
          ],
          "labels": [],
          "age_restricted": false,
          "add_ons": [],
          "option_groups": [],
          "removable_ingredients": [],
          "split": null,
          "half_price": null,
          "position": 2,
          "ean": null,
          "kitchen_name": null,
          "size": null,
          "pos": null,
          "external_id": null,
          "metadata": {}
        },
        {
          "id": "4571",
          "category_id": "315",
          "name": "Pizza Margherita",
          "description": "Rajčata San Marzano, mozzarella, bazalka.",
          "image_url": null,
          "price": {
            "amount": 18900,
            "currency": "CZK"
          },
          "vat_rate": "12",
          "packaging_fee": null,
          "weight": 450,
          "allergens": [
            "1",
            "7"
          ],
          "labels": [
            "bestseller"
          ],
          "age_restricted": false,
          "add_ons": [
            {
              "product_id": "4602",
              "name": "Extra sýr",
              "price": {
                "amount": 3000,
                "currency": "CZK"
              },
              "vat_rate": "12",
              "allergens": [
                "7"
              ]
            }
          ],
          "option_groups": [],
          "removable_ingredients": [
            {
              "id": "9001",
              "name": "bazalka"
            },
            {
              "id": "9002",
              "name": "oregano"
            }
          ],
          "split": {
            "half_price": {
              "amount": 13300,
              "currency": "CZK"
            },
            "quarter_price": null
          },
          "half_price": null,
          "position": 1,
          "ean": null,
          "kitchen_name": null,
          "size": null,
          "pos": null,
          "external_id": null,
          "metadata": {}
        },
        {
          "id": "4590",
          "category_id": "315",
          "name": "Vlastní pizza Ø32cm",
          "description": "Složte si pizzu: těsto a až 8 ingrediencí, 4 jsou v ceně.",
          "image_url": null,
          "price": {
            "amount": 18900,
            "currency": "CZK"
          },
          "vat_rate": "12",
          "packaging_fee": null,
          "weight": 450,
          "allergens": [
            "1",
            "7"
          ],
          "labels": [],
          "age_restricted": false,
          "add_ons": [],
          "option_groups": [
            {
              "id": "71",
              "name": "Těsto",
              "min_quantity": 1,
              "max_quantity": 1,
              "max_per_option": 1,
              "included_quantity": 0,
              "options": [
                {
                  "id": "1001",
                  "product_id": "4591",
                  "name": "Klasické těsto",
                  "price": {
                    "amount": 0,
                    "currency": "CZK"
                  },
                  "base_price": null,
                  "vat_rate": "12",
                  "allergens": [
                    "1"
                  ]
                },
                {
                  "id": "1002",
                  "product_id": "4592",
                  "name": "Celozrnné těsto",
                  "price": {
                    "amount": 2000,
                    "currency": "CZK"
                  },
                  "base_price": null,
                  "vat_rate": "12",
                  "allergens": [
                    "1"
                  ]
                }
              ]
            },
            {
              "id": "72",
              "name": "Ingredience",
              "min_quantity": 0,
              "max_quantity": 8,
              "max_per_option": 2,
              "included_quantity": 4,
              "options": [
                {
                  "id": "1101",
                  "product_id": "4605",
                  "name": "Šunka",
                  "price": {
                    "amount": 2400,
                    "currency": "CZK"
                  },
                  "base_price": null,
                  "vat_rate": "12",
                  "allergens": []
                },
                {
                  "id": "1102",
                  "product_id": "4603",
                  "name": "Žampiony",
                  "price": {
                    "amount": 1900,
                    "currency": "CZK"
                  },
                  "base_price": null,
                  "vat_rate": "12",
                  "allergens": []
                },
                {
                  "id": "1103",
                  "product_id": "4604",
                  "name": "Krevety",
                  "price": {
                    "amount": 0,
                    "currency": "CZK"
                  },
                  "base_price": {
                    "amount": 20900,
                    "currency": "CZK"
                  },
                  "vat_rate": "12",
                  "allergens": [
                    "2"
                  ]
                },
                {
                  "id": "1104",
                  "product_id": "4606",
                  "name": "Olivy",
                  "price": {
                    "amount": 1500,
                    "currency": "CZK"
                  },
                  "base_price": null,
                  "vat_rate": "12",
                  "allergens": []
                }
              ]
            }
          ],
          "removable_ingredients": [],
          "split": null,
          "half_price": null,
          "position": 4,
          "ean": null,
          "kitchen_name": null,
          "size": null,
          "pos": null,
          "external_id": null,
          "metadata": {}
        },
        {
          "id": "4580",
          "category_id": "315",
          "name": "Ø32cm Prosciutto",
          "description": "Šunka, mozzarella, rajčata.",
          "image_url": null,
          "price": {
            "amount": 21900,
            "currency": "CZK"
          },
          "vat_rate": "12",
          "packaging_fee": null,
          "weight": 450,
          "allergens": [
            "1",
            "7"
          ],
          "labels": [],
          "age_restricted": false,
          "add_ons": [],
          "option_groups": [],
          "removable_ingredients": [],
          "split": null,
          "half_price": null,
          "position": 2,
          "ean": null,
          "kitchen_name": null,
          "size": {
            "group_id": "4580",
            "name": "Ø32cm",
            "dish_name": "Prosciutto",
            "position": 1,
            "base": true
          },
          "pos": null,
          "external_id": null,
          "metadata": {}
        },
        {
          "id": "4583",
          "category_id": "315",
          "name": "Ø42cm Prosciutto",
          "description": "Šunka, mozzarella, rajčata.",
          "image_url": null,
          "price": {
            "amount": 30900,
            "currency": "CZK"
          },
          "vat_rate": "12",
          "packaging_fee": null,
          "weight": 700,
          "allergens": [
            "1",
            "7"
          ],
          "labels": [],
          "age_restricted": false,
          "add_ons": [],
          "option_groups": [],
          "removable_ingredients": [],
          "split": null,
          "half_price": null,
          "position": 3,
          "ean": null,
          "kitchen_name": null,
          "size": {
            "group_id": "4580",
            "name": "Ø42cm",
            "dish_name": "Prosciutto",
            "position": 2,
            "base": false
          },
          "pos": null,
          "external_id": null,
          "metadata": {}
        },
        {
          "id": "4590",
          "category_id": "320",
          "name": "Pivo 12° 0,5 l",
          "description": null,
          "image_url": null,
          "price": {
            "amount": 6900,
            "currency": "CZK"
          },
          "vat_rate": "21",
          "packaging_fee": null,
          "weight": null,
          "allergens": [],
          "labels": [],
          "age_restricted": true,
          "add_ons": [],
          "option_groups": [],
          "removable_ingredients": [],
          "split": null,
          "half_price": null,
          "position": 1,
          "ean": null,
          "kitchen_name": null,
          "size": null,
          "pos": null,
          "external_id": null,
          "metadata": {}
        },
        {
          "id": "4593",
          "category_id": "320",
          "name": "Domácí limonáda 0,4 l",
          "description": "Citron, máta, třtinový cukr.",
          "image_url": null,
          "price": {
            "amount": 5900,
            "currency": "CZK"
          },
          "vat_rate": "12",
          "packaging_fee": null,
          "weight": null,
          "allergens": [],
          "labels": [],
          "age_restricted": false,
          "add_ons": [],
          "option_groups": [],
          "removable_ingredients": [],
          "split": null,
          "half_price": null,
          "position": 2,
          "ean": null,
          "kitchen_name": null,
          "size": null,
          "pos": null,
          "external_id": null,
          "metadata": {}
        }
      ],
      "daily_menu": {
        "date": "2027-01-15",
        "available_from": "11:00",
        "available_to": "15:00",
        "items": [
          {
            "product_id": "4567",
            "position": 1
          },
          {
            "product_id": "4568",
            "position": 2
          }
        ]
      },
      "allergens": [
        {
          "code": "1",
          "name": "Obiloviny obsahující lepek"
        },
        {
          "code": "3",
          "name": "Vejce"
        },
        {
          "code": "7",
          "name": "Mléko"
        },
        {
          "code": "9",
          "name": "Celer"
        }
      ]
    }
  5. Přihlaste obsluhu

    Sign the staff in

    POST /restaurants/{restaurant_id}/staff-sessions · createStaffSession

    PINem nebo čipem. Odpověď nese token zaměstnance – posílejte ho v hlavičce Profirest-Staff-Token. Když stejný PIN má víc lidí, přijde 409 staff_ambiguous s candidates.

    With a PIN or a card. The answer carries the employee's token – send it in the Profirest-Staff-Token header. When several people share the PIN you get 409 staff_ambiguous with candidates.

    curl "https://api.mujprofirest.cz/v2/restaurants/123/staff-sessions" \
      -H "Authorization: Bearer $ACCESS_TOKEN" \
      -H "Content-Type: application/json" \
      -d '{"method": "pin", "secret": "4321"}'
    curl "https://api.mujprofirest.cz/v2/restaurants/123/staff-sessions" \
      -H "Authorization: Bearer $ACCESS_TOKEN" \
      -H "Content-Type: application/json" \
      -d '{"method": "pin", "secret": "4321"}'
    // klient: viz /v2/docs/js
    try {
      const session = await api.signInStaff('123', { method: 'pin', secret: '4321' });
    } catch (e) {
      if (e instanceof ProfirestApi.ApiError && e.code === 'staff_ambiguous') {
        // stejný PIN má víc lidí: nechte vybrat z kandidátů a pošlete znovu s employee_id
      }
    }
    // the client: see /v2/docs/js
    try {
      const session = await api.signInStaff('123', { method: 'pin', secret: '4321' });
    } catch (e) {
      if (e instanceof ProfirestApi.ApiError && e.code === 'staff_ambiguous') {
        // several people share the PIN: let them pick from the candidates and send it again with employee_id
      }
    }
    // klient: viz /v2/docs/typescript
    try {
      const session = await api.signInStaff('123', { method: 'pin', secret: '4321' });
    } catch (e) {
      if (e instanceof ProfirestApi.ApiError && e.code === 'staff_ambiguous') {
        // stejný PIN má víc lidí: nechte vybrat z kandidátů a pošlete znovu s employee_id
      }
    }
    // the client: see /v2/docs/typescript
    try {
      const session = await api.signInStaff('123', { method: 'pin', secret: '4321' });
    } catch (e) {
      if (e instanceof ProfirestApi.ApiError && e.code === 'staff_ambiguous') {
        // several people share the PIN: let them pick from the candidates and send it again with employee_id
      }
    }
    // klient: viz /v2/docs/php
    try {
        $session = $api->signInStaff('123', ['method' => 'pin', 'secret' => '4321']);
    } catch (\Profirest\Api\ApiError $e) {
        if ($e->errorCode === 'staff_ambiguous') {
            // stejný PIN má víc lidí: nechte vybrat z kandidátů a pošlete znovu s employee_id – $e->candidates
        }
    }
    // the client: see /v2/docs/php
    try {
        $session = $api->signInStaff('123', ['method' => 'pin', 'secret' => '4321']);
    } catch (\Profirest\Api\ApiError $e) {
        if ($e->errorCode === 'staff_ambiguous') {
            // several people share the PIN: let them pick from the candidates and send it again with employee_id – $e->candidates
        }
    }
    // klient: viz /v2/docs/java
    // volání blokuje – na Androidu z pracovního vlákna (Dispatchers.IO)
    try {
        Map<String, Object> session = api.signInStaff("123", Json.parse("{\"method\": \"pin\", \"secret\": \"4321\"}"));
    } catch (ApiException e) {
        if ("staff_ambiguous".equals(e.getCode())) {
            // stejný PIN má víc lidí: nechte vybrat z kandidátů a pošlete znovu s employee_id – e.getCandidates()
        }
    }
    // the client: see /v2/docs/java
    // the call blocks – on Android from a worker thread (Dispatchers.IO)
    try {
        Map<String, Object> session = api.signInStaff("123", Json.parse("{\"method\": \"pin\", \"secret\": \"4321\"}"));
    } catch (ApiException e) {
        if ("staff_ambiguous".equals(e.getCode())) {
            // several people share the PIN: let them pick from the candidates and send it again with employee_id – e.getCandidates()
        }
    }
    // klient: viz /v2/docs/java
    // volání blokuje – na Androidu z pracovního vlákna (Dispatchers.IO)
    try {
        val session = api.signInStaff("123", mapOf("method" to "pin", "secret" to "4321"))
    } catch (e: ApiException) {
        if (e.code == "staff_ambiguous") {
            // stejný PIN má víc lidí: nechte vybrat z kandidátů a pošlete znovu s employee_id – e.candidates
        }
    }
    // the client: see /v2/docs/java
    // the call blocks – on Android from a worker thread (Dispatchers.IO)
    try {
        val session = api.signInStaff("123", mapOf("method" to "pin", "secret" to "4321"))
    } catch (e: ApiException) {
        if (e.code == "staff_ambiguous") {
            // several people share the PIN: let them pick from the candidates and send it again with employee_id – e.candidates
        }
    }
    // klient: viz /v2/docs/csharp
    try
    {
        StaffSession session = await api.SignInStaffAsync("123", new StaffCredential { Method = "pin", Secret = "4321" });
    }
    catch (ProfirestApiException e) when (e.Code == ErrorCodes.StaffAmbiguous)
    {
        // stejný PIN má víc lidí: nechte vybrat z kandidátů a pošlete znovu s employee_id – e.Candidates
    }
    // the client: see /v2/docs/csharp
    try
    {
        StaffSession session = await api.SignInStaffAsync("123", new StaffCredential { Method = "pin", Secret = "4321" });
    }
    catch (ProfirestApiException e) when (e.Code == ErrorCodes.StaffAmbiguous)
    {
        // several people share the PIN: let them pick from the candidates and send it again with employee_id – e.Candidates
    }
    # klient: viz /v2/docs/python
    try:
        session = api.sign_in_staff('123', {'method': 'pin', 'secret': '4321'})
    except ApiError as e:
        if e.code == 'staff_ambiguous':
            pass  # stejný PIN má víc lidí: nechte vybrat z kandidátů a pošlete znovu s employee_id – e.candidates
    # the client: see /v2/docs/python
    try:
        session = api.sign_in_staff('123', {'method': 'pin', 'secret': '4321'})
    except ApiError as e:
        if e.code == 'staff_ambiguous':
            pass  # several people share the PIN: let them pick from the candidates and send it again with employee_id – e.candidates
    // klient: viz /v2/docs/swift
    do {
        let session = try await api.signInStaff(restaurantID: "123", credential: StaffCredential(method: "pin", secret: "4321"))
    } catch let error as ProfirestAPIError where error.code == ErrorCode.staffAmbiguous {
        // stejný PIN má víc lidí: nechte vybrat z kandidátů a pošlete znovu s employee_id – error.candidates
    }
    // the client: see /v2/docs/swift
    do {
        let session = try await api.signInStaff(restaurantID: "123", credential: StaffCredential(method: "pin", secret: "4321"))
    } catch let error as ProfirestAPIError where error.code == ErrorCode.staffAmbiguous {
        // several people share the PIN: let them pick from the candidates and send it again with employee_id – error.candidates
    }
    // klient: viz /v2/docs/dart
    try {
      final session = await api.signInStaff('123', {'method': 'pin', 'secret': '4321'});
    } on ApiError catch (e) {
      if (e.code == 'staff_ambiguous') {
        // stejný PIN má víc lidí: nechte vybrat z kandidátů a pošlete znovu s employee_id – e.candidates
      }
    }
    // the client: see /v2/docs/dart
    try {
      final session = await api.signInStaff('123', {'method': 'pin', 'secret': '4321'});
    } on ApiError catch (e) {
      if (e.code == 'staff_ambiguous') {
        // several people share the PIN: let them pick from the candidates and send it again with employee_id – e.candidates
      }
    }
    // klient: viz /v2/docs/go
    session, err := api.SignInStaff(ctx, "123", model.StaffCredential{Method: "pin", Secret: "4321"})
    var apiErr *profirest.APIError
    if errors.As(err, &apiErr) && apiErr.Code == profirest.CodeStaffAmbiguous {
    	// stejný PIN má víc lidí: nechte vybrat z kandidátů a pošlete znovu s employee_id – apiErr.Candidates
    }
    // the client: see /v2/docs/go
    session, err := api.SignInStaff(ctx, "123", model.StaffCredential{Method: "pin", Secret: "4321"})
    var apiErr *profirest.APIError
    if errors.As(err, &apiErr) && apiErr.Code == profirest.CodeStaffAmbiguous {
    	// several people share the PIN: let them pick from the candidates and send it again with employee_id – apiErr.Candidates
    }
    Příklad odpovědi 201Example answer 201
    {
      "token": "pfe_xfJc1S39DYennALz7S7F_mZZyQTbS0VzjnJDKTXKoQc",
      "expires_at": "2027-01-15T12:08:18+01:00",
      "max_expires_at": "2027-01-15T23:59:59+01:00",
      "idle_timeout_seconds": 300,
      "employee": {
        "id": "58",
        "name": "Jana Dvořáková",
        "roles": [
          "pos"
        ],
        "attendance": {
          "enabled": true
        },
        "sign_in": {
          "pin": true,
          "card": true
        },
        "offline_approval": {
          "salt": "pHk3r9QnW1xY0aBcDeFgHw",
          "iterations": 100000,
          "check": 141
        },
        "offline_sign_in": {
          "salt": "pHk3r9QnW1xY0aBcDeFgHw",
          "iterations": 100000,
          "check": 141
        }
      }
    }
  6. Účet stolu

    A table tab

    PUT /restaurants/{restaurant_id}/tabs/{tab_id} · putTab

    Celý účet stolu se ukládá najednou s If-Match; když ho mezitím změnilo jiné zařízení, přijde 412 – načtěte ho znovu a rozhodněte.

    The whole tab is stored at once with If-Match; when another device changed it meanwhile you get 412 – read it again and decide.

    curl -X PUT "https://api.mujprofirest.cz/v2/restaurants/123/tabs/01a318f0-a0c0-7834-8f31-7973aa8bb418" \
      -H "Authorization: Bearer $ACCESS_TOKEN" \
      -H "Profirest-Staff-Token: $STAFF_TOKEN" \
      -H 'If-Match: "tab-2"' \
      -H "Content-Type: application/json" \
      -d '{
      "table_name": "Stůl 4",
      "items": [
        {
          "id": "l-1",
          "product_id": "4567",
          "quantity": 1,
          "course": 1,
          "sent_to_kitchen": true
        },
        {"id": "l-2", "product_id": "4590", "quantity": 2}
      ]
    }'
    curl -X PUT "https://api.mujprofirest.cz/v2/restaurants/123/tabs/01a318f0-a0c0-7834-8f31-7973aa8bb418" \
      -H "Authorization: Bearer $ACCESS_TOKEN" \
      -H "Profirest-Staff-Token: $STAFF_TOKEN" \
      -H 'If-Match: "tab-2"' \
      -H "Content-Type: application/json" \
      -d '{
      "table_name": "Stůl 4",
      "items": [
        {
          "id": "l-1",
          "product_id": "4567",
          "quantity": 1,
          "course": 1,
          "sent_to_kitchen": true
        },
        {"id": "l-2", "product_id": "4590", "quantity": 2}
      ]
    }'
    // klient: viz /v2/docs/js
    // token zaměstnance přidá knihovna sama (po přihlášení zaměstnance)
    const tab = await api.put('/restaurants/123/tabs/01a318f0-a0c0-7834-8f31-7973aa8bb418', {
      table_name: 'Stůl 4',
      items: [
        { id: 'l-1', product_id: '4567', quantity: 1, course: 1, sent_to_kitchen: true },
        { id: 'l-2', product_id: '4590', quantity: 2 },
      ],
    }, { ifMatch: '"tab-2"' }); // 201
    // the client: see /v2/docs/js
    // the library adds the employee's token itself (after the employee signs in)
    const tab = await api.put('/restaurants/123/tabs/01a318f0-a0c0-7834-8f31-7973aa8bb418', {
      table_name: 'Stůl 4',
      items: [
        { id: 'l-1', product_id: '4567', quantity: 1, course: 1, sent_to_kitchen: true },
        { id: 'l-2', product_id: '4590', quantity: 2 },
      ],
    }, { ifMatch: '"tab-2"' }); // 201
    // klient: viz /v2/docs/typescript
    // token zaměstnance přidá knihovna sama (po přihlášení zaměstnance)
    const tab = await api.put('/restaurants/123/tabs/01a318f0-a0c0-7834-8f31-7973aa8bb418', {
      table_name: 'Stůl 4',
      items: [
        { id: 'l-1', product_id: '4567', quantity: 1, course: 1, sent_to_kitchen: true },
        { id: 'l-2', product_id: '4590', quantity: 2 },
      ],
    }, { ifMatch: '"tab-2"' }); // 201 Tab
    // the client: see /v2/docs/typescript
    // the library adds the employee's token itself (after the employee signs in)
    const tab = await api.put('/restaurants/123/tabs/01a318f0-a0c0-7834-8f31-7973aa8bb418', {
      table_name: 'Stůl 4',
      items: [
        { id: 'l-1', product_id: '4567', quantity: 1, course: 1, sent_to_kitchen: true },
        { id: 'l-2', product_id: '4590', quantity: 2 },
      ],
    }, { ifMatch: '"tab-2"' }); // 201 Tab
    // klient: viz /v2/docs/php
    // token zaměstnance přidá knihovna sama (po přihlášení zaměstnance)
    $tab = $api->put('/restaurants/123/tabs/01a318f0-a0c0-7834-8f31-7973aa8bb418', [
        'table_name' => 'Stůl 4',
        'items' => [
            [
                'id' => 'l-1',
                'product_id' => '4567',
                'quantity' => 1,
                'course' => 1,
                'sent_to_kitchen' => true,
            ],
            ['id' => 'l-2', 'product_id' => '4590', 'quantity' => 2],
        ],
    ], ['ifMatch' => '"tab-2"']); // 201
    // the client: see /v2/docs/php
    // the library adds the employee's token itself (after the employee signs in)
    $tab = $api->put('/restaurants/123/tabs/01a318f0-a0c0-7834-8f31-7973aa8bb418', [
        'table_name' => 'Stůl 4',
        'items' => [
            [
                'id' => 'l-1',
                'product_id' => '4567',
                'quantity' => 1,
                'course' => 1,
                'sent_to_kitchen' => true,
            ],
            ['id' => 'l-2', 'product_id' => '4590', 'quantity' => 2],
        ],
    ], ['ifMatch' => '"tab-2"']); // 201
    // klient: viz /v2/docs/java
    // volání blokuje – na Androidu z pracovního vlákna (Dispatchers.IO)
    // token zaměstnance přidá knihovna sama (po přihlášení zaměstnance)
    Tab tab = api.put("/restaurants/123/tabs/01a318f0-a0c0-7834-8f31-7973aa8bb418", Json.parse("""
        {
          "table_name": "Stůl 4",
          "items": [
            {
              "id": "l-1",
              "product_id": "4567",
              "quantity": 1,
              "course": 1,
              "sent_to_kitchen": true
            },
            {"id": "l-2", "product_id": "4590", "quantity": 2}
          ]
        }
        """), RequestOptions.builder().ifMatch("\"tab-2\"").build(), Tab::fromJson); // 201
    // the client: see /v2/docs/java
    // the call blocks – on Android from a worker thread (Dispatchers.IO)
    // the library adds the employee's token itself (after the employee signs in)
    Tab tab = api.put("/restaurants/123/tabs/01a318f0-a0c0-7834-8f31-7973aa8bb418", Json.parse("""
        {
          "table_name": "Stůl 4",
          "items": [
            {
              "id": "l-1",
              "product_id": "4567",
              "quantity": 1,
              "course": 1,
              "sent_to_kitchen": true
            },
            {"id": "l-2", "product_id": "4590", "quantity": 2}
          ]
        }
        """), RequestOptions.builder().ifMatch("\"tab-2\"").build(), Tab::fromJson); // 201
    // klient: viz /v2/docs/java
    // volání blokuje – na Androidu z pracovního vlákna (Dispatchers.IO)
    // token zaměstnance přidá knihovna sama (po přihlášení zaměstnance)
    val tab = api.put("/restaurants/123/tabs/01a318f0-a0c0-7834-8f31-7973aa8bb418", mapOf(
        "table_name" to "Stůl 4",
        "items" to listOf(
            mapOf(
                "id" to "l-1",
                "product_id" to "4567",
                "quantity" to 1,
                "course" to 1,
                "sent_to_kitchen" to true,
            ),
            mapOf("id" to "l-2", "product_id" to "4590", "quantity" to 2),
        ),
    ), RequestOptions.builder().ifMatch("\"tab-2\"").build(), Tab::fromJson) // 201
    // the client: see /v2/docs/java
    // the call blocks – on Android from a worker thread (Dispatchers.IO)
    // the library adds the employee's token itself (after the employee signs in)
    val tab = api.put("/restaurants/123/tabs/01a318f0-a0c0-7834-8f31-7973aa8bb418", mapOf(
        "table_name" to "Stůl 4",
        "items" to listOf(
            mapOf(
                "id" to "l-1",
                "product_id" to "4567",
                "quantity" to 1,
                "course" to 1,
                "sent_to_kitchen" to true,
            ),
            mapOf("id" to "l-2", "product_id" to "4590", "quantity" to 2),
        ),
    ), RequestOptions.builder().ifMatch("\"tab-2\"").build(), Tab::fromJson) // 201
    // klient: viz /v2/docs/csharp
    // token zaměstnance přidá knihovna sama (po přihlášení zaměstnance)
    var tab = await api.PutAsync<Tab>("/restaurants/123/tabs/01a318f0-a0c0-7834-8f31-7973aa8bb418", new {
        table_name = "Stůl 4",
        items = new object[] {
            new {
                id = "l-1",
                product_id = "4567",
                quantity = 1,
                course = 1,
                sent_to_kitchen = true,
            },
            new { id = "l-2", product_id = "4590", quantity = 2 },
        },
    }, new RequestOptions { IfMatch = "\"tab-2\"" }); // 201
    // the client: see /v2/docs/csharp
    // the library adds the employee's token itself (after the employee signs in)
    var tab = await api.PutAsync<Tab>("/restaurants/123/tabs/01a318f0-a0c0-7834-8f31-7973aa8bb418", new {
        table_name = "Stůl 4",
        items = new object[] {
            new {
                id = "l-1",
                product_id = "4567",
                quantity = 1,
                course = 1,
                sent_to_kitchen = true,
            },
            new { id = "l-2", product_id = "4590", quantity = 2 },
        },
    }, new RequestOptions { IfMatch = "\"tab-2\"" }); // 201
    # klient: viz /v2/docs/python
    # token zaměstnance přidá knihovna sama (po přihlášení zaměstnance)
    tab = api.put('/restaurants/123/tabs/01a318f0-a0c0-7834-8f31-7973aa8bb418', {
        'table_name': 'Stůl 4',
        'items': [
            {
                'id': 'l-1',
                'product_id': '4567',
                'quantity': 1,
                'course': 1,
                'sent_to_kitchen': True,
            },
            {'id': 'l-2', 'product_id': '4590', 'quantity': 2},
        ],
    }, if_match='"tab-2"')  # 201
    # the client: see /v2/docs/python
    # the library adds the employee's token itself (after the employee signs in)
    tab = api.put('/restaurants/123/tabs/01a318f0-a0c0-7834-8f31-7973aa8bb418', {
        'table_name': 'Stůl 4',
        'items': [
            {
                'id': 'l-1',
                'product_id': '4567',
                'quantity': 1,
                'course': 1,
                'sent_to_kitchen': True,
            },
            {'id': 'l-2', 'product_id': '4590', 'quantity': 2},
        ],
    }, if_match='"tab-2"')  # 201
    // klient: viz /v2/docs/swift
    // token zaměstnance přidá knihovna sama (po přihlášení zaměstnance)
    let tab: Tab = try await api.put("/restaurants/123/tabs/01a318f0-a0c0-7834-8f31-7973aa8bb418", body: [
        "table_name": "Stůl 4",
        "items": [
            [
                "id": "l-1",
                "product_id": "4567",
                "quantity": 1,
                "course": 1,
                "sent_to_kitchen": true,
            ],
            ["id": "l-2", "product_id": "4590", "quantity": 2],
        ],
    ], options: .init(ifMatch: "\"tab-2\"")) // 201
    // the client: see /v2/docs/swift
    // the library adds the employee's token itself (after the employee signs in)
    let tab: Tab = try await api.put("/restaurants/123/tabs/01a318f0-a0c0-7834-8f31-7973aa8bb418", body: [
        "table_name": "Stůl 4",
        "items": [
            [
                "id": "l-1",
                "product_id": "4567",
                "quantity": 1,
                "course": 1,
                "sent_to_kitchen": true,
            ],
            ["id": "l-2", "product_id": "4590", "quantity": 2],
        ],
    ], options: .init(ifMatch: "\"tab-2\"")) // 201
    // klient: viz /v2/docs/dart
    // token zaměstnance přidá knihovna sama (po přihlášení zaměstnance)
    final tab = pr.Tab.fromJson(await api.put('/restaurants/123/tabs/01a318f0-a0c0-7834-8f31-7973aa8bb418', {
      'table_name': 'Stůl 4',
      'items': [
        {
          'id': 'l-1',
          'product_id': '4567',
          'quantity': 1,
          'course': 1,
          'sent_to_kitchen': true,
        },
        {'id': 'l-2', 'product_id': '4590', 'quantity': 2},
      ],
    }, ifMatch: '"tab-2"')); // 201
    // the client: see /v2/docs/dart
    // the library adds the employee's token itself (after the employee signs in)
    final tab = pr.Tab.fromJson(await api.put('/restaurants/123/tabs/01a318f0-a0c0-7834-8f31-7973aa8bb418', {
      'table_name': 'Stůl 4',
      'items': [
        {
          'id': 'l-1',
          'product_id': '4567',
          'quantity': 1,
          'course': 1,
          'sent_to_kitchen': true,
        },
        {'id': 'l-2', 'product_id': '4590', 'quantity': 2},
      ],
    }, ifMatch: '"tab-2"')); // 201
    // klient: viz /v2/docs/go
    // token zaměstnance přidá knihovna sama (po přihlášení zaměstnance)
    res, err := api.Put(ctx, "/restaurants/123/tabs/01a318f0-a0c0-7834-8f31-7973aa8bb418", map[string]any{
    	"table_name": "Stůl 4",
    	"items": []any{
    		map[string]any{
    			"id": "l-1",
    			"product_id": "4567",
    			"quantity": 1,
    			"course": 1,
    			"sent_to_kitchen": true,
    		},
    		map[string]any{"id": "l-2", "product_id": "4590", "quantity": 2},
    	},
    }, &profirest.RequestOptions{IfMatch: "\"tab-2\""})
    var tab model.Tab // 201
    if err == nil {
    	err = res.Decode(&tab)
    }
    // the client: see /v2/docs/go
    // the library adds the employee's token itself (after the employee signs in)
    res, err := api.Put(ctx, "/restaurants/123/tabs/01a318f0-a0c0-7834-8f31-7973aa8bb418", map[string]any{
    	"table_name": "Stůl 4",
    	"items": []any{
    		map[string]any{
    			"id": "l-1",
    			"product_id": "4567",
    			"quantity": 1,
    			"course": 1,
    			"sent_to_kitchen": true,
    		},
    		map[string]any{"id": "l-2", "product_id": "4590", "quantity": 2},
    	},
    }, &profirest.RequestOptions{IfMatch: "\"tab-2\""})
    var tab model.Tab // 201
    if err == nil {
    	err = res.Decode(&tab)
    }
    Příklad odpovědi 200Example answer 200
    {
      "id": "01a318f0-a0c0-7834-8f31-7973aa8bb418",
      "restaurant_id": "123",
      "table_name": "Stůl 4",
      "note": null,
      "opened_at": "2027-01-15T11:48:02+01:00",
      "opened_by": {
        "id": "58",
        "name": "Jana Dvořáková"
      },
      "updated_by": {
        "id": "58",
        "name": "Jana Dvořáková"
      },
      "lines": [
        {
          "id": "l-1",
          "product_id": "4567",
          "name": "Svíčková na smetaně, houskový knedlík",
          "variant": "full",
          "quantity": 1,
          "ordered_at": "2027-01-15T11:51:40+01:00",
          "unit_price": {
            "amount": 19900,
            "currency": "CZK"
          },
          "add_ons": [],
          "removed_ingredients": [],
          "note": null,
          "course": 1,
          "sent_to_kitchen": true,
          "total": {
            "amount": 19900,
            "currency": "CZK"
          }
        },
        {
          "id": "l-2",
          "product_id": "4590",
          "name": "Pivo 12° 0,5 l",
          "variant": "full",
          "quantity": 2,
          "ordered_at": "2027-01-15T11:49:15+01:00",
          "unit_price": {
            "amount": 6900,
            "currency": "CZK"
          },
          "add_ons": [],
          "removed_ingredients": [],
          "note": null,
          "course": 0,
          "sent_to_kitchen": false,
          "total": {
            "amount": 13800,
            "currency": "CZK"
          }
        }
      ],
      "totals": {
        "items": {
          "amount": 33700,
          "currency": "CZK"
        },
        "total": {
          "amount": 33700,
          "currency": "CZK"
        }
      },
      "version": 3,
      "status": "open",
      "updated_at": "2027-01-15T11:51:40+01:00",
      "device_id": "512",
      "closed_at": null,
      "receipt_id": null
    }
  7. Spočítejte účtenku

    Price the receipt

    POST /restaurants/{restaurant_id}/receipts/preview · previewReceipt

    Stejné položky a slevy jako u vystavení; vrátí součty, DPH a cash_amount_due po zaokrouhlení hotovosti.

    The same items and discounts as for issuing; returns the totals, VAT and cash_amount_due after cash rounding.

    curl "https://api.mujprofirest.cz/v2/restaurants/123/receipts/preview" \
      -H "Authorization: Bearer $ACCESS_TOKEN" \
      -H "Profirest-Staff-Token: $STAFF_TOKEN" \
      -H "Content-Type: application/json" \
      -d '{
      "order_type": "dine_in",
      "items": [
        {"product_id": "4567", "quantity": 1, "course": 1},
        {"product_id": "4590", "quantity": 2}
      ]
    }'
    curl "https://api.mujprofirest.cz/v2/restaurants/123/receipts/preview" \
      -H "Authorization: Bearer $ACCESS_TOKEN" \
      -H "Profirest-Staff-Token: $STAFF_TOKEN" \
      -H "Content-Type: application/json" \
      -d '{
      "order_type": "dine_in",
      "items": [
        {"product_id": "4567", "quantity": 1, "course": 1},
        {"product_id": "4590", "quantity": 2}
      ]
    }'
    // klient: viz /v2/docs/js
    // token zaměstnance přidá knihovna sama (po přihlášení zaměstnance)
    const receipt = await api.post('/restaurants/123/receipts/preview', {
      order_type: 'dine_in',
      items: [{ product_id: '4567', quantity: 1, course: 1 }, { product_id: '4590', quantity: 2 }],
    }); // 200
    // the client: see /v2/docs/js
    // the library adds the employee's token itself (after the employee signs in)
    const receipt = await api.post('/restaurants/123/receipts/preview', {
      order_type: 'dine_in',
      items: [{ product_id: '4567', quantity: 1, course: 1 }, { product_id: '4590', quantity: 2 }],
    }); // 200
    // klient: viz /v2/docs/typescript
    // token zaměstnance přidá knihovna sama (po přihlášení zaměstnance)
    const receipt = await api.post('/restaurants/123/receipts/preview', {
      order_type: 'dine_in',
      items: [{ product_id: '4567', quantity: 1, course: 1 }, { product_id: '4590', quantity: 2 }],
    }); // 200 ReceiptPreview
    // the client: see /v2/docs/typescript
    // the library adds the employee's token itself (after the employee signs in)
    const receipt = await api.post('/restaurants/123/receipts/preview', {
      order_type: 'dine_in',
      items: [{ product_id: '4567', quantity: 1, course: 1 }, { product_id: '4590', quantity: 2 }],
    }); // 200 ReceiptPreview
    // klient: viz /v2/docs/php
    // token zaměstnance přidá knihovna sama (po přihlášení zaměstnance)
    $receipt = $api->post('/restaurants/123/receipts/preview', [
        'order_type' => 'dine_in',
        'items' => [
            ['product_id' => '4567', 'quantity' => 1, 'course' => 1],
            ['product_id' => '4590', 'quantity' => 2],
        ],
    ]); // 200
    // the client: see /v2/docs/php
    // the library adds the employee's token itself (after the employee signs in)
    $receipt = $api->post('/restaurants/123/receipts/preview', [
        'order_type' => 'dine_in',
        'items' => [
            ['product_id' => '4567', 'quantity' => 1, 'course' => 1],
            ['product_id' => '4590', 'quantity' => 2],
        ],
    ]); // 200
    // klient: viz /v2/docs/java
    // volání blokuje – na Androidu z pracovního vlákna (Dispatchers.IO)
    // token zaměstnance přidá knihovna sama (po přihlášení zaměstnance)
    ReceiptPreview receipt = api.post("/restaurants/123/receipts/preview", Json.parse("""
        {
          "order_type": "dine_in",
          "items": [
            {"product_id": "4567", "quantity": 1, "course": 1},
            {"product_id": "4590", "quantity": 2}
          ]
        }
        """), ReceiptPreview::fromJson); // 200
    // the client: see /v2/docs/java
    // the call blocks – on Android from a worker thread (Dispatchers.IO)
    // the library adds the employee's token itself (after the employee signs in)
    ReceiptPreview receipt = api.post("/restaurants/123/receipts/preview", Json.parse("""
        {
          "order_type": "dine_in",
          "items": [
            {"product_id": "4567", "quantity": 1, "course": 1},
            {"product_id": "4590", "quantity": 2}
          ]
        }
        """), ReceiptPreview::fromJson); // 200
    // klient: viz /v2/docs/java
    // volání blokuje – na Androidu z pracovního vlákna (Dispatchers.IO)
    // token zaměstnance přidá knihovna sama (po přihlášení zaměstnance)
    val receipt = api.post("/restaurants/123/receipts/preview", mapOf(
        "order_type" to "dine_in",
        "items" to listOf(
            mapOf("product_id" to "4567", "quantity" to 1, "course" to 1),
            mapOf("product_id" to "4590", "quantity" to 2),
        ),
    ), ReceiptPreview::fromJson) // 200
    // the client: see /v2/docs/java
    // the call blocks – on Android from a worker thread (Dispatchers.IO)
    // the library adds the employee's token itself (after the employee signs in)
    val receipt = api.post("/restaurants/123/receipts/preview", mapOf(
        "order_type" to "dine_in",
        "items" to listOf(
            mapOf("product_id" to "4567", "quantity" to 1, "course" to 1),
            mapOf("product_id" to "4590", "quantity" to 2),
        ),
    ), ReceiptPreview::fromJson) // 200
    // klient: viz /v2/docs/csharp
    // token zaměstnance přidá knihovna sama (po přihlášení zaměstnance)
    var receipt = await api.PostAsync<ReceiptPreview>("/restaurants/123/receipts/preview", new {
        order_type = "dine_in",
        items = new object[] {
            new { product_id = "4567", quantity = 1, course = 1 },
            new { product_id = "4590", quantity = 2 },
        },
    }); // 200
    // the client: see /v2/docs/csharp
    // the library adds the employee's token itself (after the employee signs in)
    var receipt = await api.PostAsync<ReceiptPreview>("/restaurants/123/receipts/preview", new {
        order_type = "dine_in",
        items = new object[] {
            new { product_id = "4567", quantity = 1, course = 1 },
            new { product_id = "4590", quantity = 2 },
        },
    }); // 200
    # klient: viz /v2/docs/python
    # token zaměstnance přidá knihovna sama (po přihlášení zaměstnance)
    receipt = api.post('/restaurants/123/receipts/preview', {
        'order_type': 'dine_in',
        'items': [
            {'product_id': '4567', 'quantity': 1, 'course': 1},
            {'product_id': '4590', 'quantity': 2},
        ],
    })  # 200
    # the client: see /v2/docs/python
    # the library adds the employee's token itself (after the employee signs in)
    receipt = api.post('/restaurants/123/receipts/preview', {
        'order_type': 'dine_in',
        'items': [
            {'product_id': '4567', 'quantity': 1, 'course': 1},
            {'product_id': '4590', 'quantity': 2},
        ],
    })  # 200
    // klient: viz /v2/docs/swift
    // token zaměstnance přidá knihovna sama (po přihlášení zaměstnance)
    let receipt: ReceiptPreview = try await api.post("/restaurants/123/receipts/preview", body: [
        "order_type": "dine_in",
        "items": [
            ["product_id": "4567", "quantity": 1, "course": 1],
            ["product_id": "4590", "quantity": 2],
        ],
    ]) // 200
    // the client: see /v2/docs/swift
    // the library adds the employee's token itself (after the employee signs in)
    let receipt: ReceiptPreview = try await api.post("/restaurants/123/receipts/preview", body: [
        "order_type": "dine_in",
        "items": [
            ["product_id": "4567", "quantity": 1, "course": 1],
            ["product_id": "4590", "quantity": 2],
        ],
    ]) // 200
    // klient: viz /v2/docs/dart
    // token zaměstnance přidá knihovna sama (po přihlášení zaměstnance)
    final receipt = pr.ReceiptPreview.fromJson(await api.post('/restaurants/123/receipts/preview', {
      'order_type': 'dine_in',
      'items': [
        {'product_id': '4567', 'quantity': 1, 'course': 1},
        {'product_id': '4590', 'quantity': 2},
      ],
    })); // 200
    // the client: see /v2/docs/dart
    // the library adds the employee's token itself (after the employee signs in)
    final receipt = pr.ReceiptPreview.fromJson(await api.post('/restaurants/123/receipts/preview', {
      'order_type': 'dine_in',
      'items': [
        {'product_id': '4567', 'quantity': 1, 'course': 1},
        {'product_id': '4590', 'quantity': 2},
      ],
    })); // 200
    // klient: viz /v2/docs/go
    // token zaměstnance přidá knihovna sama (po přihlášení zaměstnance)
    res, err := api.Post(ctx, "/restaurants/123/receipts/preview", map[string]any{
    	"order_type": "dine_in",
    	"items": []any{
    		map[string]any{"product_id": "4567", "quantity": 1, "course": 1},
    		map[string]any{"product_id": "4590", "quantity": 2},
    	},
    }, nil)
    var receipt model.ReceiptPreview // 200
    if err == nil {
    	err = res.Decode(&receipt)
    }
    // the client: see /v2/docs/go
    // the library adds the employee's token itself (after the employee signs in)
    res, err := api.Post(ctx, "/restaurants/123/receipts/preview", map[string]any{
    	"order_type": "dine_in",
    	"items": []any{
    		map[string]any{"product_id": "4567", "quantity": 1, "course": 1},
    		map[string]any{"product_id": "4590", "quantity": 2},
    	},
    }, nil)
    var receipt model.ReceiptPreview // 200
    if err == nil {
    	err = res.Decode(&receipt)
    }
    Příklad odpovědi 200Example answer 200
    {
      "lines": [
        {
          "id": "1",
          "type": "product",
          "product_id": "4567",
          "name": "Svíčková na smetaně, houskový knedlík",
          "variant": "full",
          "quantity": 1,
          "unit_price": {
            "amount": 19900,
            "currency": "CZK"
          },
          "catalog_unit_price": {
            "amount": 19900,
            "currency": "CZK"
          },
          "price_source": "catalog",
          "at_employee_price": false,
          "packaging_unit_price": null,
          "vat_rate": "12",
          "add_ons": [],
          "note": null,
          "course": 1,
          "total": {
            "amount": 19900,
            "currency": "CZK"
          },
          "voucher_code": null
        },
        {
          "id": "2",
          "type": "product",
          "product_id": "4590",
          "name": "Pivo 12° 0,5 l",
          "variant": "full",
          "quantity": 2,
          "unit_price": {
            "amount": 6900,
            "currency": "CZK"
          },
          "catalog_unit_price": {
            "amount": 6900,
            "currency": "CZK"
          },
          "price_source": "catalog",
          "at_employee_price": false,
          "packaging_unit_price": null,
          "vat_rate": "21",
          "add_ons": [],
          "note": null,
          "course": 0,
          "total": {
            "amount": 13800,
            "currency": "CZK"
          },
          "voucher_code": null
        }
      ],
      "discounts": [],
      "totals": {
        "items": {
          "amount": 33700,
          "currency": "CZK"
        },
        "charges": {
          "amount": 0,
          "currency": "CZK"
        },
        "discounts": {
          "amount": 0,
          "currency": "CZK"
        },
        "rounding": {
          "amount": 0,
          "currency": "CZK"
        },
        "total": {
          "amount": 33700,
          "currency": "CZK"
        },
        "vat": [
          {
            "rate": "21",
            "base": {
              "amount": 11405,
              "currency": "CZK"
            },
            "vat": {
              "amount": 2395,
              "currency": "CZK"
            },
            "total": {
              "amount": 13800,
              "currency": "CZK"
            }
          },
          {
            "rate": "12",
            "base": {
              "amount": 17768,
              "currency": "CZK"
            },
            "vat": {
              "amount": 2132,
              "currency": "CZK"
            },
            "total": {
              "amount": 19900,
              "currency": "CZK"
            }
          }
        ]
      },
      "price_differences": [],
      "cash_amount_due": {
        "amount": 33700,
        "currency": "CZK"
      },
      "eet_recorded": true
    }
  8. Vystavte účtenku

    Issue the receipt

    POST /restaurants/{restaurant_id}/receipts · createReceipt

    id je UUID ze zařízení: opakování (i po výpadku sítě) účtenku nezdvojí a vrátí ji se stavem 200. Server ji zaeviduje v EET 2.0 sám.

    id is a UUID made on the device: a repeat (even after a network outage) never issues it twice and returns it with 200. The server records it in EET 2.0 itself.

    curl "https://api.mujprofirest.cz/v2/restaurants/123/receipts" \
      -H "Authorization: Bearer $ACCESS_TOKEN" \
      -H "Profirest-Staff-Token: $STAFF_TOKEN" \
      -H "Content-Type: application/json" \
      -d '{
      "id": "01a318f0-a0c0-750d-8c36-65b69d55462d",
      "number": 1001,
      "issued_at": "2027-01-15T12:03:18+01:00",
      "table_name": "Stůl 4",
      "order_type": "dine_in",
      "tab_id": "01a318f0-a0c0-7834-8f31-7973aa8bb418",
      "tab_version": 3,
      "items": [
        {"product_id": "4567", "quantity": 1, "course": 1},
        {"product_id": "4590", "quantity": 2}
      ],
      "payments": [
        {
          "method": "cash",
          "amount": {"amount": 33700, "currency": "CZK"},
          "tendered": {"amount": 40000, "currency": "CZK"}
        }
      ]
    }'
    curl "https://api.mujprofirest.cz/v2/restaurants/123/receipts" \
      -H "Authorization: Bearer $ACCESS_TOKEN" \
      -H "Profirest-Staff-Token: $STAFF_TOKEN" \
      -H "Content-Type: application/json" \
      -d '{
      "id": "01a318f0-a0c0-750d-8c36-65b69d55462d",
      "number": 1001,
      "issued_at": "2027-01-15T12:03:18+01:00",
      "table_name": "Stůl 4",
      "order_type": "dine_in",
      "tab_id": "01a318f0-a0c0-7834-8f31-7973aa8bb418",
      "tab_version": 3,
      "items": [
        {"product_id": "4567", "quantity": 1, "course": 1},
        {"product_id": "4590", "quantity": 2}
      ],
      "payments": [
        {
          "method": "cash",
          "amount": {"amount": 33700, "currency": "CZK"},
          "tendered": {"amount": 40000, "currency": "CZK"}
        }
      ]
    }'
    // klient: viz /v2/docs/js
    // token zaměstnance přidá knihovna sama (po přihlášení zaměstnance)
    const receipt = await api.post('/restaurants/123/receipts', {
      id: '01a318f0-a0c0-750d-8c36-65b69d55462d',
      number: 1001,
      issued_at: '2027-01-15T12:03:18+01:00',
      table_name: 'Stůl 4',
      order_type: 'dine_in',
      tab_id: '01a318f0-a0c0-7834-8f31-7973aa8bb418',
      tab_version: 3,
      items: [{ product_id: '4567', quantity: 1, course: 1 }, { product_id: '4590', quantity: 2 }],
      payments: [
        {
          method: 'cash',
          amount: { amount: 33700, currency: 'CZK' },
          tendered: { amount: 40000, currency: 'CZK' },
        },
      ],
    }); // 201
    // the client: see /v2/docs/js
    // the library adds the employee's token itself (after the employee signs in)
    const receipt = await api.post('/restaurants/123/receipts', {
      id: '01a318f0-a0c0-750d-8c36-65b69d55462d',
      number: 1001,
      issued_at: '2027-01-15T12:03:18+01:00',
      table_name: 'Stůl 4',
      order_type: 'dine_in',
      tab_id: '01a318f0-a0c0-7834-8f31-7973aa8bb418',
      tab_version: 3,
      items: [{ product_id: '4567', quantity: 1, course: 1 }, { product_id: '4590', quantity: 2 }],
      payments: [
        {
          method: 'cash',
          amount: { amount: 33700, currency: 'CZK' },
          tendered: { amount: 40000, currency: 'CZK' },
        },
      ],
    }); // 201
    // klient: viz /v2/docs/typescript
    // token zaměstnance přidá knihovna sama (po přihlášení zaměstnance)
    const receipt = await api.post('/restaurants/123/receipts', {
      id: '01a318f0-a0c0-750d-8c36-65b69d55462d',
      number: 1001,
      issued_at: '2027-01-15T12:03:18+01:00',
      table_name: 'Stůl 4',
      order_type: 'dine_in',
      tab_id: '01a318f0-a0c0-7834-8f31-7973aa8bb418',
      tab_version: 3,
      items: [{ product_id: '4567', quantity: 1, course: 1 }, { product_id: '4590', quantity: 2 }],
      payments: [
        {
          method: 'cash',
          amount: { amount: 33700, currency: 'CZK' },
          tendered: { amount: 40000, currency: 'CZK' },
        },
      ],
    }); // 201 Receipt
    // the client: see /v2/docs/typescript
    // the library adds the employee's token itself (after the employee signs in)
    const receipt = await api.post('/restaurants/123/receipts', {
      id: '01a318f0-a0c0-750d-8c36-65b69d55462d',
      number: 1001,
      issued_at: '2027-01-15T12:03:18+01:00',
      table_name: 'Stůl 4',
      order_type: 'dine_in',
      tab_id: '01a318f0-a0c0-7834-8f31-7973aa8bb418',
      tab_version: 3,
      items: [{ product_id: '4567', quantity: 1, course: 1 }, { product_id: '4590', quantity: 2 }],
      payments: [
        {
          method: 'cash',
          amount: { amount: 33700, currency: 'CZK' },
          tendered: { amount: 40000, currency: 'CZK' },
        },
      ],
    }); // 201 Receipt
    // klient: viz /v2/docs/php
    // token zaměstnance přidá knihovna sama (po přihlášení zaměstnance)
    $receipt = $api->post('/restaurants/123/receipts', [
        'id' => '01a318f0-a0c0-750d-8c36-65b69d55462d',
        'number' => 1001,
        'issued_at' => '2027-01-15T12:03:18+01:00',
        'table_name' => 'Stůl 4',
        'order_type' => 'dine_in',
        'tab_id' => '01a318f0-a0c0-7834-8f31-7973aa8bb418',
        'tab_version' => 3,
        'items' => [
            ['product_id' => '4567', 'quantity' => 1, 'course' => 1],
            ['product_id' => '4590', 'quantity' => 2],
        ],
        'payments' => [
            [
                'method' => 'cash',
                'amount' => ['amount' => 33700, 'currency' => 'CZK'],
                'tendered' => ['amount' => 40000, 'currency' => 'CZK'],
            ],
        ],
    ]); // 201
    // the client: see /v2/docs/php
    // the library adds the employee's token itself (after the employee signs in)
    $receipt = $api->post('/restaurants/123/receipts', [
        'id' => '01a318f0-a0c0-750d-8c36-65b69d55462d',
        'number' => 1001,
        'issued_at' => '2027-01-15T12:03:18+01:00',
        'table_name' => 'Stůl 4',
        'order_type' => 'dine_in',
        'tab_id' => '01a318f0-a0c0-7834-8f31-7973aa8bb418',
        'tab_version' => 3,
        'items' => [
            ['product_id' => '4567', 'quantity' => 1, 'course' => 1],
            ['product_id' => '4590', 'quantity' => 2],
        ],
        'payments' => [
            [
                'method' => 'cash',
                'amount' => ['amount' => 33700, 'currency' => 'CZK'],
                'tendered' => ['amount' => 40000, 'currency' => 'CZK'],
            ],
        ],
    ]); // 201
    // klient: viz /v2/docs/java
    // volání blokuje – na Androidu z pracovního vlákna (Dispatchers.IO)
    // token zaměstnance přidá knihovna sama (po přihlášení zaměstnance)
    Receipt receipt = api.post("/restaurants/123/receipts", Json.parse("""
        {
          "id": "01a318f0-a0c0-750d-8c36-65b69d55462d",
          "number": 1001,
          "issued_at": "2027-01-15T12:03:18+01:00",
          "table_name": "Stůl 4",
          "order_type": "dine_in",
          "tab_id": "01a318f0-a0c0-7834-8f31-7973aa8bb418",
          "tab_version": 3,
          "items": [
            {"product_id": "4567", "quantity": 1, "course": 1},
            {"product_id": "4590", "quantity": 2}
          ],
          "payments": [
            {
              "method": "cash",
              "amount": {"amount": 33700, "currency": "CZK"},
              "tendered": {"amount": 40000, "currency": "CZK"}
            }
          ]
        }
        """), Receipt::fromJson); // 201
    // the client: see /v2/docs/java
    // the call blocks – on Android from a worker thread (Dispatchers.IO)
    // the library adds the employee's token itself (after the employee signs in)
    Receipt receipt = api.post("/restaurants/123/receipts", Json.parse("""
        {
          "id": "01a318f0-a0c0-750d-8c36-65b69d55462d",
          "number": 1001,
          "issued_at": "2027-01-15T12:03:18+01:00",
          "table_name": "Stůl 4",
          "order_type": "dine_in",
          "tab_id": "01a318f0-a0c0-7834-8f31-7973aa8bb418",
          "tab_version": 3,
          "items": [
            {"product_id": "4567", "quantity": 1, "course": 1},
            {"product_id": "4590", "quantity": 2}
          ],
          "payments": [
            {
              "method": "cash",
              "amount": {"amount": 33700, "currency": "CZK"},
              "tendered": {"amount": 40000, "currency": "CZK"}
            }
          ]
        }
        """), Receipt::fromJson); // 201
    // klient: viz /v2/docs/java
    // volání blokuje – na Androidu z pracovního vlákna (Dispatchers.IO)
    // token zaměstnance přidá knihovna sama (po přihlášení zaměstnance)
    val receipt = api.post("/restaurants/123/receipts", mapOf(
        "id" to "01a318f0-a0c0-750d-8c36-65b69d55462d",
        "number" to 1001,
        "issued_at" to "2027-01-15T12:03:18+01:00",
        "table_name" to "Stůl 4",
        "order_type" to "dine_in",
        "tab_id" to "01a318f0-a0c0-7834-8f31-7973aa8bb418",
        "tab_version" to 3,
        "items" to listOf(
            mapOf("product_id" to "4567", "quantity" to 1, "course" to 1),
            mapOf("product_id" to "4590", "quantity" to 2),
        ),
        "payments" to listOf(
            mapOf(
                "method" to "cash",
                "amount" to mapOf("amount" to 33700, "currency" to "CZK"),
                "tendered" to mapOf("amount" to 40000, "currency" to "CZK"),
            ),
        ),
    ), Receipt::fromJson) // 201
    // the client: see /v2/docs/java
    // the call blocks – on Android from a worker thread (Dispatchers.IO)
    // the library adds the employee's token itself (after the employee signs in)
    val receipt = api.post("/restaurants/123/receipts", mapOf(
        "id" to "01a318f0-a0c0-750d-8c36-65b69d55462d",
        "number" to 1001,
        "issued_at" to "2027-01-15T12:03:18+01:00",
        "table_name" to "Stůl 4",
        "order_type" to "dine_in",
        "tab_id" to "01a318f0-a0c0-7834-8f31-7973aa8bb418",
        "tab_version" to 3,
        "items" to listOf(
            mapOf("product_id" to "4567", "quantity" to 1, "course" to 1),
            mapOf("product_id" to "4590", "quantity" to 2),
        ),
        "payments" to listOf(
            mapOf(
                "method" to "cash",
                "amount" to mapOf("amount" to 33700, "currency" to "CZK"),
                "tendered" to mapOf("amount" to 40000, "currency" to "CZK"),
            ),
        ),
    ), Receipt::fromJson) // 201
    // klient: viz /v2/docs/csharp
    // token zaměstnance přidá knihovna sama (po přihlášení zaměstnance)
    var receipt = await api.PostAsync<Receipt>("/restaurants/123/receipts", new {
        id = "01a318f0-a0c0-750d-8c36-65b69d55462d",
        number = 1001,
        issued_at = "2027-01-15T12:03:18+01:00",
        table_name = "Stůl 4",
        order_type = "dine_in",
        tab_id = "01a318f0-a0c0-7834-8f31-7973aa8bb418",
        tab_version = 3,
        items = new object[] {
            new { product_id = "4567", quantity = 1, course = 1 },
            new { product_id = "4590", quantity = 2 },
        },
        payments = new object[] {
            new {
                method = "cash",
                amount = new { amount = 33700, currency = "CZK" },
                tendered = new { amount = 40000, currency = "CZK" },
            },
        },
    }); // 201
    // the client: see /v2/docs/csharp
    // the library adds the employee's token itself (after the employee signs in)
    var receipt = await api.PostAsync<Receipt>("/restaurants/123/receipts", new {
        id = "01a318f0-a0c0-750d-8c36-65b69d55462d",
        number = 1001,
        issued_at = "2027-01-15T12:03:18+01:00",
        table_name = "Stůl 4",
        order_type = "dine_in",
        tab_id = "01a318f0-a0c0-7834-8f31-7973aa8bb418",
        tab_version = 3,
        items = new object[] {
            new { product_id = "4567", quantity = 1, course = 1 },
            new { product_id = "4590", quantity = 2 },
        },
        payments = new object[] {
            new {
                method = "cash",
                amount = new { amount = 33700, currency = "CZK" },
                tendered = new { amount = 40000, currency = "CZK" },
            },
        },
    }); // 201
    # klient: viz /v2/docs/python
    # token zaměstnance přidá knihovna sama (po přihlášení zaměstnance)
    receipt = api.post('/restaurants/123/receipts', {
        'id': '01a318f0-a0c0-750d-8c36-65b69d55462d',
        'number': 1001,
        'issued_at': '2027-01-15T12:03:18+01:00',
        'table_name': 'Stůl 4',
        'order_type': 'dine_in',
        'tab_id': '01a318f0-a0c0-7834-8f31-7973aa8bb418',
        'tab_version': 3,
        'items': [
            {'product_id': '4567', 'quantity': 1, 'course': 1},
            {'product_id': '4590', 'quantity': 2},
        ],
        'payments': [
            {
                'method': 'cash',
                'amount': {'amount': 33700, 'currency': 'CZK'},
                'tendered': {'amount': 40000, 'currency': 'CZK'},
            },
        ],
    })  # 201
    # the client: see /v2/docs/python
    # the library adds the employee's token itself (after the employee signs in)
    receipt = api.post('/restaurants/123/receipts', {
        'id': '01a318f0-a0c0-750d-8c36-65b69d55462d',
        'number': 1001,
        'issued_at': '2027-01-15T12:03:18+01:00',
        'table_name': 'Stůl 4',
        'order_type': 'dine_in',
        'tab_id': '01a318f0-a0c0-7834-8f31-7973aa8bb418',
        'tab_version': 3,
        'items': [
            {'product_id': '4567', 'quantity': 1, 'course': 1},
            {'product_id': '4590', 'quantity': 2},
        ],
        'payments': [
            {
                'method': 'cash',
                'amount': {'amount': 33700, 'currency': 'CZK'},
                'tendered': {'amount': 40000, 'currency': 'CZK'},
            },
        ],
    })  # 201
    // klient: viz /v2/docs/swift
    // token zaměstnance přidá knihovna sama (po přihlášení zaměstnance)
    let receipt: Receipt = try await api.post("/restaurants/123/receipts", body: [
        "id": "01a318f0-a0c0-750d-8c36-65b69d55462d",
        "number": 1001,
        "issued_at": "2027-01-15T12:03:18+01:00",
        "table_name": "Stůl 4",
        "order_type": "dine_in",
        "tab_id": "01a318f0-a0c0-7834-8f31-7973aa8bb418",
        "tab_version": 3,
        "items": [
            ["product_id": "4567", "quantity": 1, "course": 1],
            ["product_id": "4590", "quantity": 2],
        ],
        "payments": [
            [
                "method": "cash",
                "amount": ["amount": 33700, "currency": "CZK"],
                "tendered": ["amount": 40000, "currency": "CZK"],
            ],
        ],
    ]) // 201
    // the client: see /v2/docs/swift
    // the library adds the employee's token itself (after the employee signs in)
    let receipt: Receipt = try await api.post("/restaurants/123/receipts", body: [
        "id": "01a318f0-a0c0-750d-8c36-65b69d55462d",
        "number": 1001,
        "issued_at": "2027-01-15T12:03:18+01:00",
        "table_name": "Stůl 4",
        "order_type": "dine_in",
        "tab_id": "01a318f0-a0c0-7834-8f31-7973aa8bb418",
        "tab_version": 3,
        "items": [
            ["product_id": "4567", "quantity": 1, "course": 1],
            ["product_id": "4590", "quantity": 2],
        ],
        "payments": [
            [
                "method": "cash",
                "amount": ["amount": 33700, "currency": "CZK"],
                "tendered": ["amount": 40000, "currency": "CZK"],
            ],
        ],
    ]) // 201
    // klient: viz /v2/docs/dart
    // token zaměstnance přidá knihovna sama (po přihlášení zaměstnance)
    final receipt = pr.Receipt.fromJson(await api.post('/restaurants/123/receipts', {
      'id': '01a318f0-a0c0-750d-8c36-65b69d55462d',
      'number': 1001,
      'issued_at': '2027-01-15T12:03:18+01:00',
      'table_name': 'Stůl 4',
      'order_type': 'dine_in',
      'tab_id': '01a318f0-a0c0-7834-8f31-7973aa8bb418',
      'tab_version': 3,
      'items': [
        {'product_id': '4567', 'quantity': 1, 'course': 1},
        {'product_id': '4590', 'quantity': 2},
      ],
      'payments': [
        {
          'method': 'cash',
          'amount': {'amount': 33700, 'currency': 'CZK'},
          'tendered': {'amount': 40000, 'currency': 'CZK'},
        },
      ],
    })); // 201
    // the client: see /v2/docs/dart
    // the library adds the employee's token itself (after the employee signs in)
    final receipt = pr.Receipt.fromJson(await api.post('/restaurants/123/receipts', {
      'id': '01a318f0-a0c0-750d-8c36-65b69d55462d',
      'number': 1001,
      'issued_at': '2027-01-15T12:03:18+01:00',
      'table_name': 'Stůl 4',
      'order_type': 'dine_in',
      'tab_id': '01a318f0-a0c0-7834-8f31-7973aa8bb418',
      'tab_version': 3,
      'items': [
        {'product_id': '4567', 'quantity': 1, 'course': 1},
        {'product_id': '4590', 'quantity': 2},
      ],
      'payments': [
        {
          'method': 'cash',
          'amount': {'amount': 33700, 'currency': 'CZK'},
          'tendered': {'amount': 40000, 'currency': 'CZK'},
        },
      ],
    })); // 201
    // klient: viz /v2/docs/go
    // token zaměstnance přidá knihovna sama (po přihlášení zaměstnance)
    res, err := api.Post(ctx, "/restaurants/123/receipts", map[string]any{
    	"id": "01a318f0-a0c0-750d-8c36-65b69d55462d",
    	"number": 1001,
    	"issued_at": "2027-01-15T12:03:18+01:00",
    	"table_name": "Stůl 4",
    	"order_type": "dine_in",
    	"tab_id": "01a318f0-a0c0-7834-8f31-7973aa8bb418",
    	"tab_version": 3,
    	"items": []any{
    		map[string]any{"product_id": "4567", "quantity": 1, "course": 1},
    		map[string]any{"product_id": "4590", "quantity": 2},
    	},
    	"payments": []any{
    		map[string]any{
    			"method": "cash",
    			"amount": map[string]any{"amount": 33700, "currency": "CZK"},
    			"tendered": map[string]any{"amount": 40000, "currency": "CZK"},
    		},
    	},
    }, nil)
    var receipt model.Receipt // 201
    if err == nil {
    	err = res.Decode(&receipt)
    }
    // the client: see /v2/docs/go
    // the library adds the employee's token itself (after the employee signs in)
    res, err := api.Post(ctx, "/restaurants/123/receipts", map[string]any{
    	"id": "01a318f0-a0c0-750d-8c36-65b69d55462d",
    	"number": 1001,
    	"issued_at": "2027-01-15T12:03:18+01:00",
    	"table_name": "Stůl 4",
    	"order_type": "dine_in",
    	"tab_id": "01a318f0-a0c0-7834-8f31-7973aa8bb418",
    	"tab_version": 3,
    	"items": []any{
    		map[string]any{"product_id": "4567", "quantity": 1, "course": 1},
    		map[string]any{"product_id": "4590", "quantity": 2},
    	},
    	"payments": []any{
    		map[string]any{
    			"method": "cash",
    			"amount": map[string]any{"amount": 33700, "currency": "CZK"},
    			"tendered": map[string]any{"amount": 40000, "currency": "CZK"},
    		},
    	},
    }, nil)
    var receipt model.Receipt // 201
    if err == nil {
    	err = res.Decode(&receipt)
    }
    Příklad odpovědi 200Example answer 200
    {
      "id": "01a318f0-a0c0-750d-8c36-65b69d55462d",
      "restaurant_id": "123",
      "device_id": "512",
      "number": 1001,
      "kind": "sale",
      "status": "issued",
      "issued_at": "2027-01-15T12:03:18+01:00",
      "received_at": "2027-01-15T12:03:19+01:00",
      "offline": false,
      "issued_by": {
        "id": "58",
        "name": "Jana Dvořáková"
      },
      "approved_by": null,
      "table_name": "Stůl 4",
      "order_type": "dine_in",
      "customer_id": null,
      "note": null,
      "lines": [
        {
          "id": "1",
          "type": "product",
          "product_id": "4567",
          "name": "Svíčková na smetaně, houskový knedlík",
          "variant": "full",
          "quantity": 1,
          "unit_price": {
            "amount": 19900,
            "currency": "CZK"
          },
          "catalog_unit_price": {
            "amount": 19900,
            "currency": "CZK"
          },
          "price_source": "catalog",
          "at_employee_price": false,
          "packaging_unit_price": null,
          "vat_rate": "12",
          "add_ons": [],
          "note": null,
          "course": 1,
          "total": {
            "amount": 19900,
            "currency": "CZK"
          },
          "voucher_code": null
        },
        {
          "id": "2",
          "type": "product",
          "product_id": "4590",
          "name": "Pivo 12° 0,5 l",
          "variant": "full",
          "quantity": 2,
          "unit_price": {
            "amount": 6900,
            "currency": "CZK"
          },
          "catalog_unit_price": {
            "amount": 6900,
            "currency": "CZK"
          },
          "price_source": "catalog",
          "at_employee_price": false,
          "packaging_unit_price": null,
          "vat_rate": "21",
          "add_ons": [],
          "note": null,
          "course": 0,
          "total": {
            "amount": 13800,
            "currency": "CZK"
          },
          "voucher_code": null
        }
      ],
      "discounts": [],
      "totals": {
        "items": {
          "amount": 33700,
          "currency": "CZK"
        },
        "charges": {
          "amount": 0,
          "currency": "CZK"
        },
        "discounts": {
          "amount": 0,
          "currency": "CZK"
        },
        "rounding": {
          "amount": 0,
          "currency": "CZK"
        },
        "total": {
          "amount": 33700,
          "currency": "CZK"
        },
        "vat": [
          {
            "rate": "21",
            "base": {
              "amount": 11405,
              "currency": "CZK"
            },
            "vat": {
              "amount": 2395,
              "currency": "CZK"
            },
            "total": {
              "amount": 13800,
              "currency": "CZK"
            }
          },
          {
            "rate": "12",
            "base": {
              "amount": 17768,
              "currency": "CZK"
            },
            "vat": {
              "amount": 2132,
              "currency": "CZK"
            },
            "total": {
              "amount": 19900,
              "currency": "CZK"
            }
          }
        ]
      },
      "payments": [
        {
          "id": "1",
          "method": "cash",
          "amount": {
            "amount": 33700,
            "currency": "CZK"
          },
          "tip": {
            "amount": 0,
            "currency": "CZK"
          },
          "tendered": {
            "amount": 40000,
            "currency": "CZK"
          },
          "change": {
            "amount": 6300,
            "currency": "CZK"
          },
          "voucher_code": null,
          "reference": null,
          "terminal": null
        }
      ],
      "tips": {
        "amount": 0,
        "currency": "CZK"
      },
      "price_differences": [],
      "kitchen_number": null,
      "cancels": null,
      "cancelled_by": null,
      "eet": {
        "status": "accepted",
        "total": {
          "amount": 33700,
          "currency": "CZK"
        },
        "prepaid_issued": null,
        "prepaid_used": null,
        "register_id": "POS-512",
        "sequence": "1001",
        "unit_id": "273",
        "sold_at": "2027-01-15T12:03:18+01:00",
        "pok": "6a1f0c2e-58b3-4d7e-9a41-0f2c7b9d3e5a-03",
        "environment": "production",
        "error": null,
        "warnings": [],
        "deadline_at": "2027-01-17T12:03:18+01:00"
      },
      "shift_closed_at": null
    }
  9. Storno

    A cancellation

    POST /restaurants/{restaurant_id}/receipts/{receipt_id}/storno · cancelReceipt

    Kdo smí stornovat, nastavuje provozovna (pos.receipt_cancel_by v nastavení zařízení): obsluha, nebo jen vedoucí pokladny (role pos_manager nebo jeho PIN v manager_credential). Vznikne storno doklad se zápornými částkami.

    Who may cancel is set by the restaurant (pos.receipt_cancel_by in the device settings): the staff, or only a register manager (the pos_manager role or their PIN in manager_credential). It creates a cancellation document with negative amounts.

    curl "https://api.mujprofirest.cz/v2/restaurants/123/receipts/01a318f0-a0c0-750d-8c36-65b69d55462d/storno" \
      -H "Authorization: Bearer $ACCESS_TOKEN" \
      -H "Profirest-Staff-Token: $STAFF_TOKEN" \
      -H "Content-Type: application/json" \
      -d '{
      "id": "01a318f0-a0c0-70e0-bba9-8720b58925a1",
      "number": 1003,
      "reason": "Chybně namarkováno – patří ke stolu 5",
      "restock": true
    }'
    curl "https://api.mujprofirest.cz/v2/restaurants/123/receipts/01a318f0-a0c0-750d-8c36-65b69d55462d/storno" \
      -H "Authorization: Bearer $ACCESS_TOKEN" \
      -H "Profirest-Staff-Token: $STAFF_TOKEN" \
      -H "Content-Type: application/json" \
      -d '{
      "id": "01a318f0-a0c0-70e0-bba9-8720b58925a1",
      "number": 1003,
      "reason": "Chybně namarkováno – patří ke stolu 5",
      "restock": true
    }'
    // klient: viz /v2/docs/js
    // token zaměstnance přidá knihovna sama (po přihlášení zaměstnance)
    const receipt = await api.post('/restaurants/123/receipts/01a318f0-a0c0-750d-8c36-65b69d55462d/storno', {
      id: '01a318f0-a0c0-70e0-bba9-8720b58925a1',
      number: 1003,
      reason: 'Chybně namarkováno – patří ke stolu 5',
      restock: true,
    }); // 201
    // the client: see /v2/docs/js
    // the library adds the employee's token itself (after the employee signs in)
    const receipt = await api.post('/restaurants/123/receipts/01a318f0-a0c0-750d-8c36-65b69d55462d/storno', {
      id: '01a318f0-a0c0-70e0-bba9-8720b58925a1',
      number: 1003,
      reason: 'Chybně namarkováno – patří ke stolu 5',
      restock: true,
    }); // 201
    // klient: viz /v2/docs/typescript
    // token zaměstnance přidá knihovna sama (po přihlášení zaměstnance)
    const receipt = await api.post('/restaurants/123/receipts/01a318f0-a0c0-750d-8c36-65b69d55462d/storno', {
      id: '01a318f0-a0c0-70e0-bba9-8720b58925a1',
      number: 1003,
      reason: 'Chybně namarkováno – patří ke stolu 5',
      restock: true,
    }); // 201 Receipt
    // the client: see /v2/docs/typescript
    // the library adds the employee's token itself (after the employee signs in)
    const receipt = await api.post('/restaurants/123/receipts/01a318f0-a0c0-750d-8c36-65b69d55462d/storno', {
      id: '01a318f0-a0c0-70e0-bba9-8720b58925a1',
      number: 1003,
      reason: 'Chybně namarkováno – patří ke stolu 5',
      restock: true,
    }); // 201 Receipt
    // klient: viz /v2/docs/php
    // token zaměstnance přidá knihovna sama (po přihlášení zaměstnance)
    $receipt = $api->post('/restaurants/123/receipts/01a318f0-a0c0-750d-8c36-65b69d55462d/storno', [
        'id' => '01a318f0-a0c0-70e0-bba9-8720b58925a1',
        'number' => 1003,
        'reason' => 'Chybně namarkováno – patří ke stolu 5',
        'restock' => true,
    ]); // 201
    // the client: see /v2/docs/php
    // the library adds the employee's token itself (after the employee signs in)
    $receipt = $api->post('/restaurants/123/receipts/01a318f0-a0c0-750d-8c36-65b69d55462d/storno', [
        'id' => '01a318f0-a0c0-70e0-bba9-8720b58925a1',
        'number' => 1003,
        'reason' => 'Chybně namarkováno – patří ke stolu 5',
        'restock' => true,
    ]); // 201
    // klient: viz /v2/docs/java
    // volání blokuje – na Androidu z pracovního vlákna (Dispatchers.IO)
    // token zaměstnance přidá knihovna sama (po přihlášení zaměstnance)
    Receipt receipt = api.post("/restaurants/123/receipts/01a318f0-a0c0-750d-8c36-65b69d55462d/storno", Json.parse("""
        {
          "id": "01a318f0-a0c0-70e0-bba9-8720b58925a1",
          "number": 1003,
          "reason": "Chybně namarkováno – patří ke stolu 5",
          "restock": true
        }
        """), Receipt::fromJson); // 201
    // the client: see /v2/docs/java
    // the call blocks – on Android from a worker thread (Dispatchers.IO)
    // the library adds the employee's token itself (after the employee signs in)
    Receipt receipt = api.post("/restaurants/123/receipts/01a318f0-a0c0-750d-8c36-65b69d55462d/storno", Json.parse("""
        {
          "id": "01a318f0-a0c0-70e0-bba9-8720b58925a1",
          "number": 1003,
          "reason": "Chybně namarkováno – patří ke stolu 5",
          "restock": true
        }
        """), Receipt::fromJson); // 201
    // klient: viz /v2/docs/java
    // volání blokuje – na Androidu z pracovního vlákna (Dispatchers.IO)
    // token zaměstnance přidá knihovna sama (po přihlášení zaměstnance)
    val receipt = api.post("/restaurants/123/receipts/01a318f0-a0c0-750d-8c36-65b69d55462d/storno", mapOf(
        "id" to "01a318f0-a0c0-70e0-bba9-8720b58925a1",
        "number" to 1003,
        "reason" to "Chybně namarkováno – patří ke stolu 5",
        "restock" to true,
    ), Receipt::fromJson) // 201
    // the client: see /v2/docs/java
    // the call blocks – on Android from a worker thread (Dispatchers.IO)
    // the library adds the employee's token itself (after the employee signs in)
    val receipt = api.post("/restaurants/123/receipts/01a318f0-a0c0-750d-8c36-65b69d55462d/storno", mapOf(
        "id" to "01a318f0-a0c0-70e0-bba9-8720b58925a1",
        "number" to 1003,
        "reason" to "Chybně namarkováno – patří ke stolu 5",
        "restock" to true,
    ), Receipt::fromJson) // 201
    // klient: viz /v2/docs/csharp
    // token zaměstnance přidá knihovna sama (po přihlášení zaměstnance)
    var receipt = await api.PostAsync<Receipt>("/restaurants/123/receipts/01a318f0-a0c0-750d-8c36-65b69d55462d/storno", new {
        id = "01a318f0-a0c0-70e0-bba9-8720b58925a1",
        number = 1003,
        reason = "Chybně namarkováno – patří ke stolu 5",
        restock = true,
    }); // 201
    // the client: see /v2/docs/csharp
    // the library adds the employee's token itself (after the employee signs in)
    var receipt = await api.PostAsync<Receipt>("/restaurants/123/receipts/01a318f0-a0c0-750d-8c36-65b69d55462d/storno", new {
        id = "01a318f0-a0c0-70e0-bba9-8720b58925a1",
        number = 1003,
        reason = "Chybně namarkováno – patří ke stolu 5",
        restock = true,
    }); // 201
    # klient: viz /v2/docs/python
    # token zaměstnance přidá knihovna sama (po přihlášení zaměstnance)
    receipt = api.post('/restaurants/123/receipts/01a318f0-a0c0-750d-8c36-65b69d55462d/storno', {
        'id': '01a318f0-a0c0-70e0-bba9-8720b58925a1',
        'number': 1003,
        'reason': 'Chybně namarkováno – patří ke stolu 5',
        'restock': True,
    })  # 201
    # the client: see /v2/docs/python
    # the library adds the employee's token itself (after the employee signs in)
    receipt = api.post('/restaurants/123/receipts/01a318f0-a0c0-750d-8c36-65b69d55462d/storno', {
        'id': '01a318f0-a0c0-70e0-bba9-8720b58925a1',
        'number': 1003,
        'reason': 'Chybně namarkováno – patří ke stolu 5',
        'restock': True,
    })  # 201
    // klient: viz /v2/docs/swift
    // token zaměstnance přidá knihovna sama (po přihlášení zaměstnance)
    let receipt: Receipt = try await api.post("/restaurants/123/receipts/01a318f0-a0c0-750d-8c36-65b69d55462d/storno", body: [
        "id": "01a318f0-a0c0-70e0-bba9-8720b58925a1",
        "number": 1003,
        "reason": "Chybně namarkováno – patří ke stolu 5",
        "restock": true,
    ]) // 201
    // the client: see /v2/docs/swift
    // the library adds the employee's token itself (after the employee signs in)
    let receipt: Receipt = try await api.post("/restaurants/123/receipts/01a318f0-a0c0-750d-8c36-65b69d55462d/storno", body: [
        "id": "01a318f0-a0c0-70e0-bba9-8720b58925a1",
        "number": 1003,
        "reason": "Chybně namarkováno – patří ke stolu 5",
        "restock": true,
    ]) // 201
    // klient: viz /v2/docs/dart
    // token zaměstnance přidá knihovna sama (po přihlášení zaměstnance)
    final receipt = pr.Receipt.fromJson(await api.post('/restaurants/123/receipts/01a318f0-a0c0-750d-8c36-65b69d55462d/storno', {
      'id': '01a318f0-a0c0-70e0-bba9-8720b58925a1',
      'number': 1003,
      'reason': 'Chybně namarkováno – patří ke stolu 5',
      'restock': true,
    })); // 201
    // the client: see /v2/docs/dart
    // the library adds the employee's token itself (after the employee signs in)
    final receipt = pr.Receipt.fromJson(await api.post('/restaurants/123/receipts/01a318f0-a0c0-750d-8c36-65b69d55462d/storno', {
      'id': '01a318f0-a0c0-70e0-bba9-8720b58925a1',
      'number': 1003,
      'reason': 'Chybně namarkováno – patří ke stolu 5',
      'restock': true,
    })); // 201
    // klient: viz /v2/docs/go
    // token zaměstnance přidá knihovna sama (po přihlášení zaměstnance)
    res, err := api.Post(ctx, "/restaurants/123/receipts/01a318f0-a0c0-750d-8c36-65b69d55462d/storno", map[string]any{
    	"id": "01a318f0-a0c0-70e0-bba9-8720b58925a1",
    	"number": 1003,
    	"reason": "Chybně namarkováno – patří ke stolu 5",
    	"restock": true,
    }, nil)
    var receipt model.Receipt // 201
    if err == nil {
    	err = res.Decode(&receipt)
    }
    // the client: see /v2/docs/go
    // the library adds the employee's token itself (after the employee signs in)
    res, err := api.Post(ctx, "/restaurants/123/receipts/01a318f0-a0c0-750d-8c36-65b69d55462d/storno", map[string]any{
    	"id": "01a318f0-a0c0-70e0-bba9-8720b58925a1",
    	"number": 1003,
    	"reason": "Chybně namarkováno – patří ke stolu 5",
    	"restock": true,
    }, nil)
    var receipt model.Receipt // 201
    if err == nil {
    	err = res.Decode(&receipt)
    }
    Příklad odpovědi 200Example answer 200
    {
      "id": "01a318f0-a0c0-70e0-bba9-8720b58925a1",
      "restaurant_id": "123",
      "device_id": "512",
      "number": 1003,
      "kind": "storno",
      "status": "issued",
      "issued_at": "2027-01-15T12:10:44+01:00",
      "received_at": "2027-01-15T12:10:44+01:00",
      "offline": false,
      "issued_by": {
        "id": "61",
        "name": "Petr Novák"
      },
      "approved_by": null,
      "table_name": "Stůl 4",
      "order_type": "dine_in",
      "customer_id": null,
      "note": null,
      "lines": [
        {
          "id": "1",
          "type": "product",
          "product_id": "4567",
          "name": "Svíčková na smetaně, houskový knedlík",
          "variant": "full",
          "quantity": -1,
          "unit_price": {
            "amount": 19900,
            "currency": "CZK"
          },
          "catalog_unit_price": {
            "amount": 19900,
            "currency": "CZK"
          },
          "price_source": "catalog",
          "at_employee_price": false,
          "packaging_unit_price": null,
          "vat_rate": "12",
          "add_ons": [],
          "note": null,
          "course": 1,
          "total": {
            "amount": -19900,
            "currency": "CZK"
          },
          "voucher_code": null
        },
        {
          "id": "2",
          "type": "product",
          "product_id": "4590",
          "name": "Pivo 12° 0,5 l",
          "variant": "full",
          "quantity": -2,
          "unit_price": {
            "amount": 6900,
            "currency": "CZK"
          },
          "catalog_unit_price": {
            "amount": 6900,
            "currency": "CZK"
          },
          "price_source": "catalog",
          "at_employee_price": false,
          "packaging_unit_price": null,
          "vat_rate": "21",
          "add_ons": [],
          "note": null,
          "course": 0,
          "total": {
            "amount": -13800,
            "currency": "CZK"
          },
          "voucher_code": null
        }
      ],
      "discounts": [],
      "totals": {
        "items": {
          "amount": -33700,
          "currency": "CZK"
        },
        "charges": {
          "amount": 0,
          "currency": "CZK"
        },
        "discounts": {
          "amount": 0,
          "currency": "CZK"
        },
        "rounding": {
          "amount": 0,
          "currency": "CZK"
        },
        "total": {
          "amount": -33700,
          "currency": "CZK"
        },
        "vat": [
          {
            "rate": "21",
            "base": {
              "amount": -11405,
              "currency": "CZK"
            },
            "vat": {
              "amount": -2395,
              "currency": "CZK"
            },
            "total": {
              "amount": -13800,
              "currency": "CZK"
            }
          },
          {
            "rate": "12",
            "base": {
              "amount": -17768,
              "currency": "CZK"
            },
            "vat": {
              "amount": -2132,
              "currency": "CZK"
            },
            "total": {
              "amount": -19900,
              "currency": "CZK"
            }
          }
        ]
      },
      "payments": [
        {
          "id": "1",
          "method": "cash",
          "amount": {
            "amount": -33700,
            "currency": "CZK"
          },
          "tip": {
            "amount": 0,
            "currency": "CZK"
          },
          "tendered": null,
          "change": null,
          "voucher_code": null,
          "reference": null,
          "terminal": null
        }
      ],
      "tips": {
        "amount": 0,
        "currency": "CZK"
      },
      "price_differences": [],
      "kitchen_number": null,
      "cancels": "01a318f0-a0c0-750d-8c36-65b69d55462d",
      "cancelled_by": null,
      "eet": {
        "status": "accepted",
        "total": {
          "amount": -33700,
          "currency": "CZK"
        },
        "prepaid_issued": null,
        "prepaid_used": null,
        "register_id": "POS-512",
        "sequence": "1003",
        "unit_id": "273",
        "sold_at": "2027-01-15T12:10:44+01:00",
        "pok": "3d7b1a90-6c2e-4f85-b1d3-9e0a7c5f2b46-03",
        "environment": "production",
        "error": null,
        "warnings": [],
        "deadline_at": "2027-01-17T12:10:44+01:00"
      },
      "shift_closed_at": null
    }
  10. Změna platby

    Changing the payment

    POST /restaurants/{restaurant_id}/receipts/{receipt_id}/payment-change · changeReceiptPayment

    Zvolila obsluha hotovost a zákazník platil kartou? Platbu změňte bez storna – účtenka si nechá číslo i částku. Mění se platby hotově, stravenkami, na firemní účet a fakturou, do uzávěrky směny; platby kartou a dárkovým voucherem zůstávají.

    The employee chose cash and the customer paid by card? Change the payment without a cancellation – the receipt keeps its number and amount. Cash, meal voucher, company account and invoice payments change, until the shift close; card and gift voucher payments stay.

    curl "https://api.mujprofirest.cz/v2/restaurants/123/receipts/01a318f0-a0c0-750d-8c36-65b69d55462d/payment-change" \
      -H "Authorization: Bearer $ACCESS_TOKEN" \
      -H "Profirest-Staff-Token: $STAFF_TOKEN" \
      -H "Content-Type: application/json" \
      -d '{
      "id": "01a318f0-a0c0-7b2e-b422-5663a54604b9",
      "reason": "Omylem hotově, platil kartou",
      "payments": [
        {
          "method": "card",
          "amount": {"amount": 33700, "currency": "CZK"},
          "terminal": {
            "provider": "csob",
            "transaction_id": "0011245611",
            "card_number_masked": "**** **** **** 1187",
            "auth_code": "B3M8T1",
            "response_code": "00"
          }
        }
      ]
    }'
    curl "https://api.mujprofirest.cz/v2/restaurants/123/receipts/01a318f0-a0c0-750d-8c36-65b69d55462d/payment-change" \
      -H "Authorization: Bearer $ACCESS_TOKEN" \
      -H "Profirest-Staff-Token: $STAFF_TOKEN" \
      -H "Content-Type: application/json" \
      -d '{
      "id": "01a318f0-a0c0-7b2e-b422-5663a54604b9",
      "reason": "Omylem hotově, platil kartou",
      "payments": [
        {
          "method": "card",
          "amount": {"amount": 33700, "currency": "CZK"},
          "terminal": {
            "provider": "csob",
            "transaction_id": "0011245611",
            "card_number_masked": "**** **** **** 1187",
            "auth_code": "B3M8T1",
            "response_code": "00"
          }
        }
      ]
    }'
    // klient: viz /v2/docs/js
    // token zaměstnance přidá knihovna sama (po přihlášení zaměstnance)
    const receiptPayment = await api.post('/restaurants/123/receipts/01a318f0-a0c0-750d-8c36-65b69d55462d/payment-change', {
      id: '01a318f0-a0c0-7b2e-b422-5663a54604b9',
      reason: 'Omylem hotově, platil kartou',
      payments: [
        {
          method: 'card',
          amount: { amount: 33700, currency: 'CZK' },
          terminal: {
            provider: 'csob',
            transaction_id: '0011245611',
            card_number_masked: '**** **** **** 1187',
            auth_code: 'B3M8T1',
            response_code: '00',
          },
        },
      ],
    }); // 200
    // the client: see /v2/docs/js
    // the library adds the employee's token itself (after the employee signs in)
    const receiptPayment = await api.post('/restaurants/123/receipts/01a318f0-a0c0-750d-8c36-65b69d55462d/payment-change', {
      id: '01a318f0-a0c0-7b2e-b422-5663a54604b9',
      reason: 'Omylem hotově, platil kartou',
      payments: [
        {
          method: 'card',
          amount: { amount: 33700, currency: 'CZK' },
          terminal: {
            provider: 'csob',
            transaction_id: '0011245611',
            card_number_masked: '**** **** **** 1187',
            auth_code: 'B3M8T1',
            response_code: '00',
          },
        },
      ],
    }); // 200
    // klient: viz /v2/docs/typescript
    // token zaměstnance přidá knihovna sama (po přihlášení zaměstnance)
    const receiptPayment = await api.post('/restaurants/123/receipts/01a318f0-a0c0-750d-8c36-65b69d55462d/payment-change', {
      id: '01a318f0-a0c0-7b2e-b422-5663a54604b9',
      reason: 'Omylem hotově, platil kartou',
      payments: [
        {
          method: 'card',
          amount: { amount: 33700, currency: 'CZK' },
          terminal: {
            provider: 'csob',
            transaction_id: '0011245611',
            card_number_masked: '**** **** **** 1187',
            auth_code: 'B3M8T1',
            response_code: '00',
          },
        },
      ],
    }); // 200 Receipt
    // the client: see /v2/docs/typescript
    // the library adds the employee's token itself (after the employee signs in)
    const receiptPayment = await api.post('/restaurants/123/receipts/01a318f0-a0c0-750d-8c36-65b69d55462d/payment-change', {
      id: '01a318f0-a0c0-7b2e-b422-5663a54604b9',
      reason: 'Omylem hotově, platil kartou',
      payments: [
        {
          method: 'card',
          amount: { amount: 33700, currency: 'CZK' },
          terminal: {
            provider: 'csob',
            transaction_id: '0011245611',
            card_number_masked: '**** **** **** 1187',
            auth_code: 'B3M8T1',
            response_code: '00',
          },
        },
      ],
    }); // 200 Receipt
    // klient: viz /v2/docs/php
    // token zaměstnance přidá knihovna sama (po přihlášení zaměstnance)
    $receiptPayment = $api->post('/restaurants/123/receipts/01a318f0-a0c0-750d-8c36-65b69d55462d/payment-change', [
        'id' => '01a318f0-a0c0-7b2e-b422-5663a54604b9',
        'reason' => 'Omylem hotově, platil kartou',
        'payments' => [
            [
                'method' => 'card',
                'amount' => ['amount' => 33700, 'currency' => 'CZK'],
                'terminal' => [
                    'provider' => 'csob',
                    'transaction_id' => '0011245611',
                    'card_number_masked' => '**** **** **** 1187',
                    'auth_code' => 'B3M8T1',
                    'response_code' => '00',
                ],
            ],
        ],
    ]); // 200
    // the client: see /v2/docs/php
    // the library adds the employee's token itself (after the employee signs in)
    $receiptPayment = $api->post('/restaurants/123/receipts/01a318f0-a0c0-750d-8c36-65b69d55462d/payment-change', [
        'id' => '01a318f0-a0c0-7b2e-b422-5663a54604b9',
        'reason' => 'Omylem hotově, platil kartou',
        'payments' => [
            [
                'method' => 'card',
                'amount' => ['amount' => 33700, 'currency' => 'CZK'],
                'terminal' => [
                    'provider' => 'csob',
                    'transaction_id' => '0011245611',
                    'card_number_masked' => '**** **** **** 1187',
                    'auth_code' => 'B3M8T1',
                    'response_code' => '00',
                ],
            ],
        ],
    ]); // 200
    // klient: viz /v2/docs/java
    // volání blokuje – na Androidu z pracovního vlákna (Dispatchers.IO)
    // token zaměstnance přidá knihovna sama (po přihlášení zaměstnance)
    Receipt receiptPayment = api.post("/restaurants/123/receipts/01a318f0-a0c0-750d-8c36-65b69d55462d/payment-change", Json.parse("""
        {
          "id": "01a318f0-a0c0-7b2e-b422-5663a54604b9",
          "reason": "Omylem hotově, platil kartou",
          "payments": [
            {
              "method": "card",
              "amount": {"amount": 33700, "currency": "CZK"},
              "terminal": {
                "provider": "csob",
                "transaction_id": "0011245611",
                "card_number_masked": "**** **** **** 1187",
                "auth_code": "B3M8T1",
                "response_code": "00"
              }
            }
          ]
        }
        """), Receipt::fromJson); // 200
    // the client: see /v2/docs/java
    // the call blocks – on Android from a worker thread (Dispatchers.IO)
    // the library adds the employee's token itself (after the employee signs in)
    Receipt receiptPayment = api.post("/restaurants/123/receipts/01a318f0-a0c0-750d-8c36-65b69d55462d/payment-change", Json.parse("""
        {
          "id": "01a318f0-a0c0-7b2e-b422-5663a54604b9",
          "reason": "Omylem hotově, platil kartou",
          "payments": [
            {
              "method": "card",
              "amount": {"amount": 33700, "currency": "CZK"},
              "terminal": {
                "provider": "csob",
                "transaction_id": "0011245611",
                "card_number_masked": "**** **** **** 1187",
                "auth_code": "B3M8T1",
                "response_code": "00"
              }
            }
          ]
        }
        """), Receipt::fromJson); // 200
    // klient: viz /v2/docs/java
    // volání blokuje – na Androidu z pracovního vlákna (Dispatchers.IO)
    // token zaměstnance přidá knihovna sama (po přihlášení zaměstnance)
    val receiptPayment = api.post("/restaurants/123/receipts/01a318f0-a0c0-750d-8c36-65b69d55462d/payment-change", mapOf(
        "id" to "01a318f0-a0c0-7b2e-b422-5663a54604b9",
        "reason" to "Omylem hotově, platil kartou",
        "payments" to listOf(
            mapOf(
                "method" to "card",
                "amount" to mapOf("amount" to 33700, "currency" to "CZK"),
                "terminal" to mapOf(
                    "provider" to "csob",
                    "transaction_id" to "0011245611",
                    "card_number_masked" to "**** **** **** 1187",
                    "auth_code" to "B3M8T1",
                    "response_code" to "00",
                ),
            ),
        ),
    ), Receipt::fromJson) // 200
    // the client: see /v2/docs/java
    // the call blocks – on Android from a worker thread (Dispatchers.IO)
    // the library adds the employee's token itself (after the employee signs in)
    val receiptPayment = api.post("/restaurants/123/receipts/01a318f0-a0c0-750d-8c36-65b69d55462d/payment-change", mapOf(
        "id" to "01a318f0-a0c0-7b2e-b422-5663a54604b9",
        "reason" to "Omylem hotově, platil kartou",
        "payments" to listOf(
            mapOf(
                "method" to "card",
                "amount" to mapOf("amount" to 33700, "currency" to "CZK"),
                "terminal" to mapOf(
                    "provider" to "csob",
                    "transaction_id" to "0011245611",
                    "card_number_masked" to "**** **** **** 1187",
                    "auth_code" to "B3M8T1",
                    "response_code" to "00",
                ),
            ),
        ),
    ), Receipt::fromJson) // 200
    // klient: viz /v2/docs/csharp
    // token zaměstnance přidá knihovna sama (po přihlášení zaměstnance)
    var receiptPayment = await api.PostAsync<Receipt>("/restaurants/123/receipts/01a318f0-a0c0-750d-8c36-65b69d55462d/payment-change", new {
        id = "01a318f0-a0c0-7b2e-b422-5663a54604b9",
        reason = "Omylem hotově, platil kartou",
        payments = new object[] {
            new {
                method = "card",
                amount = new { amount = 33700, currency = "CZK" },
                terminal = new {
                    provider = "csob",
                    transaction_id = "0011245611",
                    card_number_masked = "**** **** **** 1187",
                    auth_code = "B3M8T1",
                    response_code = "00",
                },
            },
        },
    }); // 200
    // the client: see /v2/docs/csharp
    // the library adds the employee's token itself (after the employee signs in)
    var receiptPayment = await api.PostAsync<Receipt>("/restaurants/123/receipts/01a318f0-a0c0-750d-8c36-65b69d55462d/payment-change", new {
        id = "01a318f0-a0c0-7b2e-b422-5663a54604b9",
        reason = "Omylem hotově, platil kartou",
        payments = new object[] {
            new {
                method = "card",
                amount = new { amount = 33700, currency = "CZK" },
                terminal = new {
                    provider = "csob",
                    transaction_id = "0011245611",
                    card_number_masked = "**** **** **** 1187",
                    auth_code = "B3M8T1",
                    response_code = "00",
                },
            },
        },
    }); // 200
    # klient: viz /v2/docs/python
    # token zaměstnance přidá knihovna sama (po přihlášení zaměstnance)
    receipt_payment = api.post('/restaurants/123/receipts/01a318f0-a0c0-750d-8c36-65b69d55462d/payment-change', {
        'id': '01a318f0-a0c0-7b2e-b422-5663a54604b9',
        'reason': 'Omylem hotově, platil kartou',
        'payments': [
            {
                'method': 'card',
                'amount': {'amount': 33700, 'currency': 'CZK'},
                'terminal': {
                    'provider': 'csob',
                    'transaction_id': '0011245611',
                    'card_number_masked': '**** **** **** 1187',
                    'auth_code': 'B3M8T1',
                    'response_code': '00',
                },
            },
        ],
    })  # 200
    # the client: see /v2/docs/python
    # the library adds the employee's token itself (after the employee signs in)
    receipt_payment = api.post('/restaurants/123/receipts/01a318f0-a0c0-750d-8c36-65b69d55462d/payment-change', {
        'id': '01a318f0-a0c0-7b2e-b422-5663a54604b9',
        'reason': 'Omylem hotově, platil kartou',
        'payments': [
            {
                'method': 'card',
                'amount': {'amount': 33700, 'currency': 'CZK'},
                'terminal': {
                    'provider': 'csob',
                    'transaction_id': '0011245611',
                    'card_number_masked': '**** **** **** 1187',
                    'auth_code': 'B3M8T1',
                    'response_code': '00',
                },
            },
        ],
    })  # 200
    // klient: viz /v2/docs/swift
    // token zaměstnance přidá knihovna sama (po přihlášení zaměstnance)
    let receiptPayment: Receipt = try await api.post("/restaurants/123/receipts/01a318f0-a0c0-750d-8c36-65b69d55462d/payment-change", body: [
        "id": "01a318f0-a0c0-7b2e-b422-5663a54604b9",
        "reason": "Omylem hotově, platil kartou",
        "payments": [
            [
                "method": "card",
                "amount": ["amount": 33700, "currency": "CZK"],
                "terminal": [
                    "provider": "csob",
                    "transaction_id": "0011245611",
                    "card_number_masked": "**** **** **** 1187",
                    "auth_code": "B3M8T1",
                    "response_code": "00",
                ],
            ],
        ],
    ]) // 200
    // the client: see /v2/docs/swift
    // the library adds the employee's token itself (after the employee signs in)
    let receiptPayment: Receipt = try await api.post("/restaurants/123/receipts/01a318f0-a0c0-750d-8c36-65b69d55462d/payment-change", body: [
        "id": "01a318f0-a0c0-7b2e-b422-5663a54604b9",
        "reason": "Omylem hotově, platil kartou",
        "payments": [
            [
                "method": "card",
                "amount": ["amount": 33700, "currency": "CZK"],
                "terminal": [
                    "provider": "csob",
                    "transaction_id": "0011245611",
                    "card_number_masked": "**** **** **** 1187",
                    "auth_code": "B3M8T1",
                    "response_code": "00",
                ],
            ],
        ],
    ]) // 200
    // klient: viz /v2/docs/dart
    // token zaměstnance přidá knihovna sama (po přihlášení zaměstnance)
    final receiptPayment = pr.Receipt.fromJson(await api.post('/restaurants/123/receipts/01a318f0-a0c0-750d-8c36-65b69d55462d/payment-change', {
      'id': '01a318f0-a0c0-7b2e-b422-5663a54604b9',
      'reason': 'Omylem hotově, platil kartou',
      'payments': [
        {
          'method': 'card',
          'amount': {'amount': 33700, 'currency': 'CZK'},
          'terminal': {
            'provider': 'csob',
            'transaction_id': '0011245611',
            'card_number_masked': '**** **** **** 1187',
            'auth_code': 'B3M8T1',
            'response_code': '00',
          },
        },
      ],
    })); // 200
    // the client: see /v2/docs/dart
    // the library adds the employee's token itself (after the employee signs in)
    final receiptPayment = pr.Receipt.fromJson(await api.post('/restaurants/123/receipts/01a318f0-a0c0-750d-8c36-65b69d55462d/payment-change', {
      'id': '01a318f0-a0c0-7b2e-b422-5663a54604b9',
      'reason': 'Omylem hotově, platil kartou',
      'payments': [
        {
          'method': 'card',
          'amount': {'amount': 33700, 'currency': 'CZK'},
          'terminal': {
            'provider': 'csob',
            'transaction_id': '0011245611',
            'card_number_masked': '**** **** **** 1187',
            'auth_code': 'B3M8T1',
            'response_code': '00',
          },
        },
      ],
    })); // 200
    // klient: viz /v2/docs/go
    // token zaměstnance přidá knihovna sama (po přihlášení zaměstnance)
    res, err := api.Post(ctx, "/restaurants/123/receipts/01a318f0-a0c0-750d-8c36-65b69d55462d/payment-change", map[string]any{
    	"id": "01a318f0-a0c0-7b2e-b422-5663a54604b9",
    	"reason": "Omylem hotově, platil kartou",
    	"payments": []any{
    		map[string]any{
    			"method": "card",
    			"amount": map[string]any{"amount": 33700, "currency": "CZK"},
    			"terminal": map[string]any{
    				"provider": "csob",
    				"transaction_id": "0011245611",
    				"card_number_masked": "**** **** **** 1187",
    				"auth_code": "B3M8T1",
    				"response_code": "00",
    			},
    		},
    	},
    }, nil)
    var receiptPayment model.Receipt // 200
    if err == nil {
    	err = res.Decode(&receiptPayment)
    }
    // the client: see /v2/docs/go
    // the library adds the employee's token itself (after the employee signs in)
    res, err := api.Post(ctx, "/restaurants/123/receipts/01a318f0-a0c0-750d-8c36-65b69d55462d/payment-change", map[string]any{
    	"id": "01a318f0-a0c0-7b2e-b422-5663a54604b9",
    	"reason": "Omylem hotově, platil kartou",
    	"payments": []any{
    		map[string]any{
    			"method": "card",
    			"amount": map[string]any{"amount": 33700, "currency": "CZK"},
    			"terminal": map[string]any{
    				"provider": "csob",
    				"transaction_id": "0011245611",
    				"card_number_masked": "**** **** **** 1187",
    				"auth_code": "B3M8T1",
    				"response_code": "00",
    			},
    		},
    	},
    }, nil)
    var receiptPayment model.Receipt // 200
    if err == nil {
    	err = res.Decode(&receiptPayment)
    }
    Příklad odpovědi 200Example answer 200
    {
      "id": "01a318f0-a0c0-750d-8c36-65b69d55462d",
      "restaurant_id": "123",
      "device_id": "512",
      "number": 1001,
      "kind": "sale",
      "status": "issued",
      "issued_at": "2027-01-15T12:03:18+01:00",
      "received_at": "2027-01-15T12:03:19+01:00",
      "offline": false,
      "issued_by": {
        "id": "58",
        "name": "Jana Dvořáková"
      },
      "approved_by": null,
      "table_name": "Stůl 4",
      "order_type": "dine_in",
      "customer_id": null,
      "note": null,
      "lines": [
        {
          "id": "1",
          "type": "product",
          "product_id": "4567",
          "name": "Svíčková na smetaně, houskový knedlík",
          "variant": "full",
          "quantity": 1,
          "unit_price": {
            "amount": 19900,
            "currency": "CZK"
          },
          "catalog_unit_price": {
            "amount": 19900,
            "currency": "CZK"
          },
          "price_source": "catalog",
          "at_employee_price": false,
          "packaging_unit_price": null,
          "vat_rate": "12",
          "add_ons": [],
          "note": null,
          "course": 1,
          "total": {
            "amount": 19900,
            "currency": "CZK"
          },
          "voucher_code": null
        },
        {
          "id": "2",
          "type": "product",
          "product_id": "4590",
          "name": "Pivo 12° 0,5 l",
          "variant": "full",
          "quantity": 2,
          "unit_price": {
            "amount": 6900,
            "currency": "CZK"
          },
          "catalog_unit_price": {
            "amount": 6900,
            "currency": "CZK"
          },
          "price_source": "catalog",
          "at_employee_price": false,
          "packaging_unit_price": null,
          "vat_rate": "21",
          "add_ons": [],
          "note": null,
          "course": 0,
          "total": {
            "amount": 13800,
            "currency": "CZK"
          },
          "voucher_code": null
        }
      ],
      "discounts": [],
      "totals": {
        "items": {
          "amount": 33700,
          "currency": "CZK"
        },
        "charges": {
          "amount": 0,
          "currency": "CZK"
        },
        "discounts": {
          "amount": 0,
          "currency": "CZK"
        },
        "rounding": {
          "amount": 0,
          "currency": "CZK"
        },
        "total": {
          "amount": 33700,
          "currency": "CZK"
        },
        "vat": [
          {
            "rate": "21",
            "base": {
              "amount": 11405,
              "currency": "CZK"
            },
            "vat": {
              "amount": 2395,
              "currency": "CZK"
            },
            "total": {
              "amount": 13800,
              "currency": "CZK"
            }
          },
          {
            "rate": "12",
            "base": {
              "amount": 17768,
              "currency": "CZK"
            },
            "vat": {
              "amount": 2132,
              "currency": "CZK"
            },
            "total": {
              "amount": 19900,
              "currency": "CZK"
            }
          }
        ]
      },
      "payments": [
        {
          "id": "1",
          "method": "card",
          "amount": {
            "amount": 33700,
            "currency": "CZK"
          },
          "tip": {
            "amount": 0,
            "currency": "CZK"
          },
          "tendered": null,
          "change": null,
          "voucher_code": null,
          "reference": null,
          "terminal": {
            "provider": "csob",
            "transaction_id": "0011245611",
            "card_number_masked": "**** **** **** 1187",
            "auth_code": "B3M8T1"
          }
        }
      ],
      "tips": {
        "amount": 0,
        "currency": "CZK"
      },
      "price_differences": [],
      "kitchen_number": null,
      "cancels": null,
      "cancelled_by": null,
      "eet": {
        "status": "accepted",
        "total": {
          "amount": 33700,
          "currency": "CZK"
        },
        "prepaid_issued": null,
        "prepaid_used": null,
        "register_id": "POS-512",
        "sequence": "1001",
        "unit_id": "273",
        "sold_at": "2027-01-15T12:03:18+01:00",
        "pok": "6a1f0c2e-58b3-4d7e-9a41-0f2c7b9d3e5a-03",
        "environment": "production",
        "error": null,
        "warnings": [],
        "deadline_at": "2027-01-17T12:03:18+01:00"
      },
      "shift_closed_at": null
    }
  11. Vklad a výběr

    Deposits and withdrawals

    POST /restaurants/{restaurant_id}/cash-movements · createCashMovement

    Drobné na směnu, odvod do banky nebo nákup z kasy jdou do pokladní knihy provozovny; výběr a výdaj schvaluje vedoucí. Uzávěrka je připočte k očekávané hotovosti.

    Change for the shift, money to the bank or a purchase from the drawer go to the restaurant's cash book; a withdrawal and an expense need a manager. The close counts them into the expected cash.

    curl "https://api.mujprofirest.cz/v2/restaurants/123/cash-movements" \
      -H "Authorization: Bearer $ACCESS_TOKEN" \
      -H "Profirest-Staff-Token: $STAFF_TOKEN" \
      -H "Content-Type: application/json" \
      -d '{
      "id": "01a318f0-a0c0-7f0d-91ef-e936a0196e90",
      "kind": "withdrawal",
      "amount": {"amount": 1500000, "currency": "CZK"},
      "note": "Odvod tržby do banky",
      "document": null,
      "occurred_at": null,
      "manager_credential": null
    }'
    curl "https://api.mujprofirest.cz/v2/restaurants/123/cash-movements" \
      -H "Authorization: Bearer $ACCESS_TOKEN" \
      -H "Profirest-Staff-Token: $STAFF_TOKEN" \
      -H "Content-Type: application/json" \
      -d '{
      "id": "01a318f0-a0c0-7f0d-91ef-e936a0196e90",
      "kind": "withdrawal",
      "amount": {"amount": 1500000, "currency": "CZK"},
      "note": "Odvod tržby do banky",
      "document": null,
      "occurred_at": null,
      "manager_credential": null
    }'
    // klient: viz /v2/docs/js
    // token zaměstnance přidá knihovna sama (po přihlášení zaměstnance)
    const cashMovement = await api.post('/restaurants/123/cash-movements', {
      id: '01a318f0-a0c0-7f0d-91ef-e936a0196e90',
      kind: 'withdrawal',
      amount: { amount: 1500000, currency: 'CZK' },
      note: 'Odvod tržby do banky',
      document: null,
      occurred_at: null,
      manager_credential: null,
    }); // 201
    // the client: see /v2/docs/js
    // the library adds the employee's token itself (after the employee signs in)
    const cashMovement = await api.post('/restaurants/123/cash-movements', {
      id: '01a318f0-a0c0-7f0d-91ef-e936a0196e90',
      kind: 'withdrawal',
      amount: { amount: 1500000, currency: 'CZK' },
      note: 'Odvod tržby do banky',
      document: null,
      occurred_at: null,
      manager_credential: null,
    }); // 201
    // klient: viz /v2/docs/typescript
    // token zaměstnance přidá knihovna sama (po přihlášení zaměstnance)
    const cashMovement = await api.post('/restaurants/123/cash-movements', {
      id: '01a318f0-a0c0-7f0d-91ef-e936a0196e90',
      kind: 'withdrawal',
      amount: { amount: 1500000, currency: 'CZK' },
      note: 'Odvod tržby do banky',
      document: null,
      occurred_at: null,
      manager_credential: null,
    }); // 201 CashMovement
    // the client: see /v2/docs/typescript
    // the library adds the employee's token itself (after the employee signs in)
    const cashMovement = await api.post('/restaurants/123/cash-movements', {
      id: '01a318f0-a0c0-7f0d-91ef-e936a0196e90',
      kind: 'withdrawal',
      amount: { amount: 1500000, currency: 'CZK' },
      note: 'Odvod tržby do banky',
      document: null,
      occurred_at: null,
      manager_credential: null,
    }); // 201 CashMovement
    // klient: viz /v2/docs/php
    // token zaměstnance přidá knihovna sama (po přihlášení zaměstnance)
    $cashMovement = $api->post('/restaurants/123/cash-movements', [
        'id' => '01a318f0-a0c0-7f0d-91ef-e936a0196e90',
        'kind' => 'withdrawal',
        'amount' => ['amount' => 1500000, 'currency' => 'CZK'],
        'note' => 'Odvod tržby do banky',
        'document' => null,
        'occurred_at' => null,
        'manager_credential' => null,
    ]); // 201
    // the client: see /v2/docs/php
    // the library adds the employee's token itself (after the employee signs in)
    $cashMovement = $api->post('/restaurants/123/cash-movements', [
        'id' => '01a318f0-a0c0-7f0d-91ef-e936a0196e90',
        'kind' => 'withdrawal',
        'amount' => ['amount' => 1500000, 'currency' => 'CZK'],
        'note' => 'Odvod tržby do banky',
        'document' => null,
        'occurred_at' => null,
        'manager_credential' => null,
    ]); // 201
    // klient: viz /v2/docs/java
    // volání blokuje – na Androidu z pracovního vlákna (Dispatchers.IO)
    // token zaměstnance přidá knihovna sama (po přihlášení zaměstnance)
    CashMovement cashMovement = api.post("/restaurants/123/cash-movements", Json.parse("""
        {
          "id": "01a318f0-a0c0-7f0d-91ef-e936a0196e90",
          "kind": "withdrawal",
          "amount": {"amount": 1500000, "currency": "CZK"},
          "note": "Odvod tržby do banky",
          "document": null,
          "occurred_at": null,
          "manager_credential": null
        }
        """), CashMovement::fromJson); // 201
    // the client: see /v2/docs/java
    // the call blocks – on Android from a worker thread (Dispatchers.IO)
    // the library adds the employee's token itself (after the employee signs in)
    CashMovement cashMovement = api.post("/restaurants/123/cash-movements", Json.parse("""
        {
          "id": "01a318f0-a0c0-7f0d-91ef-e936a0196e90",
          "kind": "withdrawal",
          "amount": {"amount": 1500000, "currency": "CZK"},
          "note": "Odvod tržby do banky",
          "document": null,
          "occurred_at": null,
          "manager_credential": null
        }
        """), CashMovement::fromJson); // 201
    // klient: viz /v2/docs/java
    // volání blokuje – na Androidu z pracovního vlákna (Dispatchers.IO)
    // token zaměstnance přidá knihovna sama (po přihlášení zaměstnance)
    val cashMovement = api.post("/restaurants/123/cash-movements", mapOf(
        "id" to "01a318f0-a0c0-7f0d-91ef-e936a0196e90",
        "kind" to "withdrawal",
        "amount" to mapOf("amount" to 1500000, "currency" to "CZK"),
        "note" to "Odvod tržby do banky",
        "document" to null,
        "occurred_at" to null,
        "manager_credential" to null,
    ), CashMovement::fromJson) // 201
    // the client: see /v2/docs/java
    // the call blocks – on Android from a worker thread (Dispatchers.IO)
    // the library adds the employee's token itself (after the employee signs in)
    val cashMovement = api.post("/restaurants/123/cash-movements", mapOf(
        "id" to "01a318f0-a0c0-7f0d-91ef-e936a0196e90",
        "kind" to "withdrawal",
        "amount" to mapOf("amount" to 1500000, "currency" to "CZK"),
        "note" to "Odvod tržby do banky",
        "document" to null,
        "occurred_at" to null,
        "manager_credential" to null,
    ), CashMovement::fromJson) // 201
    // klient: viz /v2/docs/csharp
    // token zaměstnance přidá knihovna sama (po přihlášení zaměstnance)
    var cashMovement = await api.PostAsync<CashMovement>("/restaurants/123/cash-movements", new {
        id = "01a318f0-a0c0-7f0d-91ef-e936a0196e90",
        kind = "withdrawal",
        amount = new { amount = 1500000, currency = "CZK" },
        note = "Odvod tržby do banky",
        document = (object?)null,
        occurred_at = (object?)null,
        manager_credential = (object?)null,
    }); // 201
    // the client: see /v2/docs/csharp
    // the library adds the employee's token itself (after the employee signs in)
    var cashMovement = await api.PostAsync<CashMovement>("/restaurants/123/cash-movements", new {
        id = "01a318f0-a0c0-7f0d-91ef-e936a0196e90",
        kind = "withdrawal",
        amount = new { amount = 1500000, currency = "CZK" },
        note = "Odvod tržby do banky",
        document = (object?)null,
        occurred_at = (object?)null,
        manager_credential = (object?)null,
    }); // 201
    # klient: viz /v2/docs/python
    # token zaměstnance přidá knihovna sama (po přihlášení zaměstnance)
    cash_movement = api.post('/restaurants/123/cash-movements', {
        'id': '01a318f0-a0c0-7f0d-91ef-e936a0196e90',
        'kind': 'withdrawal',
        'amount': {'amount': 1500000, 'currency': 'CZK'},
        'note': 'Odvod tržby do banky',
        'document': None,
        'occurred_at': None,
        'manager_credential': None,
    })  # 201
    # the client: see /v2/docs/python
    # the library adds the employee's token itself (after the employee signs in)
    cash_movement = api.post('/restaurants/123/cash-movements', {
        'id': '01a318f0-a0c0-7f0d-91ef-e936a0196e90',
        'kind': 'withdrawal',
        'amount': {'amount': 1500000, 'currency': 'CZK'},
        'note': 'Odvod tržby do banky',
        'document': None,
        'occurred_at': None,
        'manager_credential': None,
    })  # 201
    // klient: viz /v2/docs/swift
    // token zaměstnance přidá knihovna sama (po přihlášení zaměstnance)
    let cashMovement: CashMovement = try await api.post("/restaurants/123/cash-movements", body: [
        "id": "01a318f0-a0c0-7f0d-91ef-e936a0196e90",
        "kind": "withdrawal",
        "amount": ["amount": 1500000, "currency": "CZK"],
        "note": "Odvod tržby do banky",
        "document": nil,
        "occurred_at": nil,
        "manager_credential": nil,
    ]) // 201
    // the client: see /v2/docs/swift
    // the library adds the employee's token itself (after the employee signs in)
    let cashMovement: CashMovement = try await api.post("/restaurants/123/cash-movements", body: [
        "id": "01a318f0-a0c0-7f0d-91ef-e936a0196e90",
        "kind": "withdrawal",
        "amount": ["amount": 1500000, "currency": "CZK"],
        "note": "Odvod tržby do banky",
        "document": nil,
        "occurred_at": nil,
        "manager_credential": nil,
    ]) // 201
    // klient: viz /v2/docs/dart
    // token zaměstnance přidá knihovna sama (po přihlášení zaměstnance)
    final cashMovement = pr.CashMovement.fromJson(await api.post('/restaurants/123/cash-movements', {
      'id': '01a318f0-a0c0-7f0d-91ef-e936a0196e90',
      'kind': 'withdrawal',
      'amount': {'amount': 1500000, 'currency': 'CZK'},
      'note': 'Odvod tržby do banky',
      'document': null,
      'occurred_at': null,
      'manager_credential': null,
    })); // 201
    // the client: see /v2/docs/dart
    // the library adds the employee's token itself (after the employee signs in)
    final cashMovement = pr.CashMovement.fromJson(await api.post('/restaurants/123/cash-movements', {
      'id': '01a318f0-a0c0-7f0d-91ef-e936a0196e90',
      'kind': 'withdrawal',
      'amount': {'amount': 1500000, 'currency': 'CZK'},
      'note': 'Odvod tržby do banky',
      'document': null,
      'occurred_at': null,
      'manager_credential': null,
    })); // 201
    // klient: viz /v2/docs/go
    // token zaměstnance přidá knihovna sama (po přihlášení zaměstnance)
    res, err := api.Post(ctx, "/restaurants/123/cash-movements", map[string]any{
    	"id": "01a318f0-a0c0-7f0d-91ef-e936a0196e90",
    	"kind": "withdrawal",
    	"amount": map[string]any{"amount": 1500000, "currency": "CZK"},
    	"note": "Odvod tržby do banky",
    	"document": nil,
    	"occurred_at": nil,
    	"manager_credential": nil,
    }, nil)
    var cashMovement model.CashMovement // 201
    if err == nil {
    	err = res.Decode(&cashMovement)
    }
    // the client: see /v2/docs/go
    // the library adds the employee's token itself (after the employee signs in)
    res, err := api.Post(ctx, "/restaurants/123/cash-movements", map[string]any{
    	"id": "01a318f0-a0c0-7f0d-91ef-e936a0196e90",
    	"kind": "withdrawal",
    	"amount": map[string]any{"amount": 1500000, "currency": "CZK"},
    	"note": "Odvod tržby do banky",
    	"document": nil,
    	"occurred_at": nil,
    	"manager_credential": nil,
    }, nil)
    var cashMovement model.CashMovement // 201
    if err == nil {
    	err = res.Decode(&cashMovement)
    }
    Příklad odpovědi 200Example answer 200
    {
      "id": "01a318f0-a0c0-7f0d-91ef-e936a0196e90",
      "number": "8812",
      "kind": "withdrawal",
      "amount": {
        "amount": 1500000,
        "currency": "CZK"
      },
      "note": "Odvod tržby do banky",
      "document": null,
      "occurred_at": "2027-01-15T16:05:12+01:00",
      "recorded_at": "2027-01-15T16:05:12+01:00",
      "recorded_by": {
        "id": "61",
        "name": "Petr Novák"
      },
      "approved_by": {
        "id": "61",
        "name": "Petr Novák"
      },
      "device_id": "512"
    }
  12. Uzávěrka

    Closing the shift

    POST /restaurants/{restaurant_id}/pos-shift/close · closePosShift

    Součty spočítá server; pošlete přepočítanou hotovost a dostanete rozdíl.

    The server computes the totals; send the counted cash and get the difference.

    curl "https://api.mujprofirest.cz/v2/restaurants/123/pos-shift/close" \
      -H "Authorization: Bearer $ACCESS_TOKEN" \
      -H "Profirest-Staff-Token: $STAFF_TOKEN" \
      -H "Content-Type: application/json" \
      -d '{
      "id": "01a318f0-a0c0-7ce8-9a4a-c5d2d2497f33",
      "counted_cash": {"amount": 734300, "currency": "CZK"},
      "note": "Chybí 4 Kč."
    }'
    curl "https://api.mujprofirest.cz/v2/restaurants/123/pos-shift/close" \
      -H "Authorization: Bearer $ACCESS_TOKEN" \
      -H "Profirest-Staff-Token: $STAFF_TOKEN" \
      -H "Content-Type: application/json" \
      -d '{
      "id": "01a318f0-a0c0-7ce8-9a4a-c5d2d2497f33",
      "counted_cash": {"amount": 734300, "currency": "CZK"},
      "note": "Chybí 4 Kč."
    }'
    // klient: viz /v2/docs/js
    // token zaměstnance přidá knihovna sama (po přihlášení zaměstnance)
    const posShift = await api.post('/restaurants/123/pos-shift/close', {
      id: '01a318f0-a0c0-7ce8-9a4a-c5d2d2497f33',
      counted_cash: { amount: 734300, currency: 'CZK' },
      note: 'Chybí 4 Kč.',
    }); // 201
    // the client: see /v2/docs/js
    // the library adds the employee's token itself (after the employee signs in)
    const posShift = await api.post('/restaurants/123/pos-shift/close', {
      id: '01a318f0-a0c0-7ce8-9a4a-c5d2d2497f33',
      counted_cash: { amount: 734300, currency: 'CZK' },
      note: 'Chybí 4 Kč.',
    }); // 201
    // klient: viz /v2/docs/typescript
    // token zaměstnance přidá knihovna sama (po přihlášení zaměstnance)
    const posShift = await api.post('/restaurants/123/pos-shift/close', {
      id: '01a318f0-a0c0-7ce8-9a4a-c5d2d2497f33',
      counted_cash: { amount: 734300, currency: 'CZK' },
      note: 'Chybí 4 Kč.',
    }); // 201 PosShiftClose
    // the client: see /v2/docs/typescript
    // the library adds the employee's token itself (after the employee signs in)
    const posShift = await api.post('/restaurants/123/pos-shift/close', {
      id: '01a318f0-a0c0-7ce8-9a4a-c5d2d2497f33',
      counted_cash: { amount: 734300, currency: 'CZK' },
      note: 'Chybí 4 Kč.',
    }); // 201 PosShiftClose
    // klient: viz /v2/docs/php
    // token zaměstnance přidá knihovna sama (po přihlášení zaměstnance)
    $posShift = $api->post('/restaurants/123/pos-shift/close', [
        'id' => '01a318f0-a0c0-7ce8-9a4a-c5d2d2497f33',
        'counted_cash' => ['amount' => 734300, 'currency' => 'CZK'],
        'note' => 'Chybí 4 Kč.',
    ]); // 201
    // the client: see /v2/docs/php
    // the library adds the employee's token itself (after the employee signs in)
    $posShift = $api->post('/restaurants/123/pos-shift/close', [
        'id' => '01a318f0-a0c0-7ce8-9a4a-c5d2d2497f33',
        'counted_cash' => ['amount' => 734300, 'currency' => 'CZK'],
        'note' => 'Chybí 4 Kč.',
    ]); // 201
    // klient: viz /v2/docs/java
    // volání blokuje – na Androidu z pracovního vlákna (Dispatchers.IO)
    // token zaměstnance přidá knihovna sama (po přihlášení zaměstnance)
    PosShiftClose posShift = api.post("/restaurants/123/pos-shift/close", Json.parse("""
        {
          "id": "01a318f0-a0c0-7ce8-9a4a-c5d2d2497f33",
          "counted_cash": {"amount": 734300, "currency": "CZK"},
          "note": "Chybí 4 Kč."
        }
        """), PosShiftClose::fromJson); // 201
    // the client: see /v2/docs/java
    // the call blocks – on Android from a worker thread (Dispatchers.IO)
    // the library adds the employee's token itself (after the employee signs in)
    PosShiftClose posShift = api.post("/restaurants/123/pos-shift/close", Json.parse("""
        {
          "id": "01a318f0-a0c0-7ce8-9a4a-c5d2d2497f33",
          "counted_cash": {"amount": 734300, "currency": "CZK"},
          "note": "Chybí 4 Kč."
        }
        """), PosShiftClose::fromJson); // 201
    // klient: viz /v2/docs/java
    // volání blokuje – na Androidu z pracovního vlákna (Dispatchers.IO)
    // token zaměstnance přidá knihovna sama (po přihlášení zaměstnance)
    val posShift = api.post("/restaurants/123/pos-shift/close", mapOf(
        "id" to "01a318f0-a0c0-7ce8-9a4a-c5d2d2497f33",
        "counted_cash" to mapOf("amount" to 734300, "currency" to "CZK"),
        "note" to "Chybí 4 Kč.",
    ), PosShiftClose::fromJson) // 201
    // the client: see /v2/docs/java
    // the call blocks – on Android from a worker thread (Dispatchers.IO)
    // the library adds the employee's token itself (after the employee signs in)
    val posShift = api.post("/restaurants/123/pos-shift/close", mapOf(
        "id" to "01a318f0-a0c0-7ce8-9a4a-c5d2d2497f33",
        "counted_cash" to mapOf("amount" to 734300, "currency" to "CZK"),
        "note" to "Chybí 4 Kč.",
    ), PosShiftClose::fromJson) // 201
    // klient: viz /v2/docs/csharp
    // token zaměstnance přidá knihovna sama (po přihlášení zaměstnance)
    var posShift = await api.PostAsync<PosShiftClose>("/restaurants/123/pos-shift/close", new {
        id = "01a318f0-a0c0-7ce8-9a4a-c5d2d2497f33",
        counted_cash = new { amount = 734300, currency = "CZK" },
        note = "Chybí 4 Kč.",
    }); // 201
    // the client: see /v2/docs/csharp
    // the library adds the employee's token itself (after the employee signs in)
    var posShift = await api.PostAsync<PosShiftClose>("/restaurants/123/pos-shift/close", new {
        id = "01a318f0-a0c0-7ce8-9a4a-c5d2d2497f33",
        counted_cash = new { amount = 734300, currency = "CZK" },
        note = "Chybí 4 Kč.",
    }); // 201
    # klient: viz /v2/docs/python
    # token zaměstnance přidá knihovna sama (po přihlášení zaměstnance)
    pos_shift = api.post('/restaurants/123/pos-shift/close', {
        'id': '01a318f0-a0c0-7ce8-9a4a-c5d2d2497f33',
        'counted_cash': {'amount': 734300, 'currency': 'CZK'},
        'note': 'Chybí 4 Kč.',
    })  # 201
    # the client: see /v2/docs/python
    # the library adds the employee's token itself (after the employee signs in)
    pos_shift = api.post('/restaurants/123/pos-shift/close', {
        'id': '01a318f0-a0c0-7ce8-9a4a-c5d2d2497f33',
        'counted_cash': {'amount': 734300, 'currency': 'CZK'},
        'note': 'Chybí 4 Kč.',
    })  # 201
    // klient: viz /v2/docs/swift
    // token zaměstnance přidá knihovna sama (po přihlášení zaměstnance)
    let posShift: PosShiftClose = try await api.post("/restaurants/123/pos-shift/close", body: [
        "id": "01a318f0-a0c0-7ce8-9a4a-c5d2d2497f33",
        "counted_cash": ["amount": 734300, "currency": "CZK"],
        "note": "Chybí 4 Kč.",
    ]) // 201
    // the client: see /v2/docs/swift
    // the library adds the employee's token itself (after the employee signs in)
    let posShift: PosShiftClose = try await api.post("/restaurants/123/pos-shift/close", body: [
        "id": "01a318f0-a0c0-7ce8-9a4a-c5d2d2497f33",
        "counted_cash": ["amount": 734300, "currency": "CZK"],
        "note": "Chybí 4 Kč.",
    ]) // 201
    // klient: viz /v2/docs/dart
    // token zaměstnance přidá knihovna sama (po přihlášení zaměstnance)
    final posShift = pr.PosShiftClose.fromJson(await api.post('/restaurants/123/pos-shift/close', {
      'id': '01a318f0-a0c0-7ce8-9a4a-c5d2d2497f33',
      'counted_cash': {'amount': 734300, 'currency': 'CZK'},
      'note': 'Chybí 4 Kč.',
    })); // 201
    // the client: see /v2/docs/dart
    // the library adds the employee's token itself (after the employee signs in)
    final posShift = pr.PosShiftClose.fromJson(await api.post('/restaurants/123/pos-shift/close', {
      'id': '01a318f0-a0c0-7ce8-9a4a-c5d2d2497f33',
      'counted_cash': {'amount': 734300, 'currency': 'CZK'},
      'note': 'Chybí 4 Kč.',
    })); // 201
    // klient: viz /v2/docs/go
    // token zaměstnance přidá knihovna sama (po přihlášení zaměstnance)
    res, err := api.Post(ctx, "/restaurants/123/pos-shift/close", map[string]any{
    	"id": "01a318f0-a0c0-7ce8-9a4a-c5d2d2497f33",
    	"counted_cash": map[string]any{"amount": 734300, "currency": "CZK"},
    	"note": "Chybí 4 Kč.",
    }, nil)
    var posShift model.PosShiftClose // 201
    if err == nil {
    	err = res.Decode(&posShift)
    }
    // the client: see /v2/docs/go
    // the library adds the employee's token itself (after the employee signs in)
    res, err := api.Post(ctx, "/restaurants/123/pos-shift/close", map[string]any{
    	"id": "01a318f0-a0c0-7ce8-9a4a-c5d2d2497f33",
    	"counted_cash": map[string]any{"amount": 734300, "currency": "CZK"},
    	"note": "Chybí 4 Kč.",
    }, nil)
    var posShift model.PosShiftClose // 201
    if err == nil {
    	err = res.Decode(&posShift)
    }
    Příklad odpovědi 200Example answer 200
    {
      "id": "01a318f0-a0c0-7031-8216-27bad8f984d8",
      "device_id": "512",
      "closed_at": "2027-01-15T22:15:40+01:00",
      "closed_by": {
        "id": "61",
        "name": "Petr Novák"
      },
      "summary": {
        "device_id": "512",
        "opened_at": "2027-01-15T11:48:02+01:00",
        "receipts": {
          "sales": 1,
          "storno": 1
        },
        "totals": {
          "sales": {
            "amount": 10000,
            "currency": "CZK"
          },
          "storno": {
            "amount": 10000,
            "currency": "CZK"
          },
          "net": {
            "amount": 10000,
            "currency": "CZK"
          }
        },
        "payments": [
          {
            "method": "cash",
            "amount": {
              "amount": 10000,
              "currency": "CZK"
            },
            "tips": {
              "amount": 10000,
              "currency": "CZK"
            },
            "count": 1
          }
        ],
        "tips": {
          "amount": 10000,
          "currency": "CZK"
        },
        "vat": [
          {
            "rate": "12",
            "base": {
              "amount": 10000,
              "currency": "CZK"
            },
            "vat": {
              "amount": 10000,
              "currency": "CZK"
            },
            "total": {
              "amount": 10000,
              "currency": "CZK"
            }
          }
        ],
        "vouchers": {
          "sold": {
            "amount": 10000,
            "currency": "CZK"
          },
          "redeemed": {
            "amount": 10000,
            "currency": "CZK"
          }
        },
        "eet": {
          "pending": 1,
          "rejected": 1
        },
        "open_tabs": {
          "count": 1,
          "total": {
            "amount": 10000,
            "currency": "CZK"
          }
        },
        "cash_movements": {
          "count": 1,
          "deposits": {
            "amount": 10000,
            "currency": "CZK"
          },
          "incomes": {
            "amount": 10000,
            "currency": "CZK"
          },
          "withdrawals": {
            "amount": 10000,
            "currency": "CZK"
          },
          "expenses": {
            "amount": 10000,
            "currency": "CZK"
          },
          "net": {
            "amount": 10000,
            "currency": "CZK"
          }
        },
        "device_ids": [
          "20330"
        ],
        "by_device": [
          {
            "device_id": "512",
            "name": "Pokladna u baru",
            "receipts": {
              "sales": 1,
              "storno": 1
            },
            "net": {
              "amount": 10000,
              "currency": "CZK"
            },
            "payments": [
              {
                "method": "cash",
                "amount": {
                  "amount": 10000,
                  "currency": "CZK"
                },
                "tips": {
                  "amount": 10000,
                  "currency": "CZK"
                },
                "count": 1
              }
            ]
          }
        ],
        "by_employee": [
          {
            "employee": {
              "id": "58",
              "name": "Jana Dvořáková"
            },
            "receipts": {
              "sales": 1,
              "storno": 1
            },
            "net": {
              "amount": 10000,
              "currency": "CZK"
            },
            "payments": [
              {
                "method": "cash",
                "amount": {
                  "amount": 10000,
                  "currency": "CZK"
                },
                "tips": {
                  "amount": 10000,
                  "currency": "CZK"
                },
                "count": 1
              }
            ]
          }
        ]
      },
      "cash_expected": {
        "amount": 10000,
        "currency": "CZK"
      },
      "counted_cash": {
        "amount": 10000,
        "currency": "CZK"
      },
      "cash_difference": {
        "amount": 10000,
        "currency": "CZK"
      },
      "note": null
    }

Scénář

Scenario

Kuchyňský displej

A kitchen display

Vlastní zařízení ProfirestuProfirest's own device

Displej ukazuje bony ze všech zdrojů – pokladna, e-shop, rozvozové platformy – a hlásí, co je hotové. Výroba se dá rozdělit na stanoviště (gril, pizza) a výdej.

The display shows tickets from every source – the register, the e-shop, delivery platforms – and reports what is done. Production can be split into stations (grill, pizza) and the hand-out.

  1. Bony na displeji

    Tickets on the display

    GET /restaurants/{restaurant_id}/kitchen/tickets · listKitchenTickets

    view=active jsou bony k přípravě, preorders objednávky na později a history hotové. Ptejte se s If-None-Match. Bon nese ceny položek a účtenku k tisku pro rozvoz (receipt) – nepočítejte ji v aplikaci. Rozvoz nese i rozvozovou zónu (delivery_zone) pro souhrn podle zón; ten nabídněte, jen když listDeliveryZones nějaké zóny vrací.

    view=active are tickets to prepare, preorders orders for later and history the finished ones. Ask with If-None-Match. A ticket carries the prices of the items and the receipt to print for a delivery (receipt) – do not compute it in the application. A delivery also carries its delivery zone (delivery_zone) for a summary by zones; offer it only when listDeliveryZones returns some zones.

    curl "https://api.mujprofirest.cz/v2/restaurants/123/kitchen/tickets?view=active&area=kitchen" \
      -H "Authorization: Bearer $ACCESS_TOKEN"
    curl "https://api.mujprofirest.cz/v2/restaurants/123/kitchen/tickets?view=active&area=kitchen" \
      -H "Authorization: Bearer $ACCESS_TOKEN"
    // klient: viz /v2/docs/js
    const { data, next_cursor } = await api.get('/restaurants/123/kitchen/tickets', { query: { view: 'active', area: 'kitchen' } }); // 200
    // the client: see /v2/docs/js
    const { data, next_cursor } = await api.get('/restaurants/123/kitchen/tickets', { query: { view: 'active', area: 'kitchen' } }); // 200
    // klient: viz /v2/docs/typescript
    const { data, next_cursor } = await api.get('/restaurants/123/kitchen/tickets', { query: { view: 'active', area: 'kitchen' } }); // 200 KitchenTicketPage
    // the client: see /v2/docs/typescript
    const { data, next_cursor } = await api.get('/restaurants/123/kitchen/tickets', { query: { view: 'active', area: 'kitchen' } }); // 200 KitchenTicketPage
    // klient: viz /v2/docs/php
    $page = $api->get(
        '/restaurants/123/kitchen/tickets',
        ['query' => ['view' => 'active', 'area' => 'kitchen']],
    ); // $page['data'], $page['next_cursor']
    // the client: see /v2/docs/php
    $page = $api->get(
        '/restaurants/123/kitchen/tickets',
        ['query' => ['view' => 'active', 'area' => 'kitchen']],
    ); // $page['data'], $page['next_cursor']
    // klient: viz /v2/docs/java
    // volání blokuje – na Androidu z pracovního vlákna (Dispatchers.IO)
    KitchenTicketPage listKitchenTickets = api.get(
        "/restaurants/123/kitchen/tickets",
        RequestOptions.builder().query("view", "active").query("area", "kitchen").build(),
        KitchenTicketPage::fromJson
    ); // 200
    // the client: see /v2/docs/java
    // the call blocks – on Android from a worker thread (Dispatchers.IO)
    KitchenTicketPage listKitchenTickets = api.get(
        "/restaurants/123/kitchen/tickets",
        RequestOptions.builder().query("view", "active").query("area", "kitchen").build(),
        KitchenTicketPage::fromJson
    ); // 200
    // klient: viz /v2/docs/java
    // volání blokuje – na Androidu z pracovního vlákna (Dispatchers.IO)
    val listKitchenTickets = api.get(
        "/restaurants/123/kitchen/tickets",
        RequestOptions.builder().query("view", "active").query("area", "kitchen").build(),
        KitchenTicketPage::fromJson,
    ) // 200
    // the client: see /v2/docs/java
    // the call blocks – on Android from a worker thread (Dispatchers.IO)
    val listKitchenTickets = api.get(
        "/restaurants/123/kitchen/tickets",
        RequestOptions.builder().query("view", "active").query("area", "kitchen").build(),
        KitchenTicketPage::fromJson,
    ) // 200
    // klient: viz /v2/docs/csharp
    var listKitchenTickets = await api.GetAsync<KitchenTicketPage>(
        "/restaurants/123/kitchen/tickets",
        new RequestOptions { Query = new() { ["view"] = "active", ["area"] = "kitchen" } }
    ); // 200
    // the client: see /v2/docs/csharp
    var listKitchenTickets = await api.GetAsync<KitchenTicketPage>(
        "/restaurants/123/kitchen/tickets",
        new RequestOptions { Query = new() { ["view"] = "active", ["area"] = "kitchen" } }
    ); // 200
    # klient: viz /v2/docs/python
    page = api.get('/restaurants/123/kitchen/tickets', query={'view': 'active', 'area': 'kitchen'})  # page['data'], page['next_cursor']
    # the client: see /v2/docs/python
    page = api.get('/restaurants/123/kitchen/tickets', query={'view': 'active', 'area': 'kitchen'})  # page['data'], page['next_cursor']
    // klient: viz /v2/docs/swift
    let listKitchenTickets: KitchenTicketPage = try await api.get(
        "/restaurants/123/kitchen/tickets",
        options: .init(query: ["view": "active", "area": "kitchen"])
    ) // 200
    // the client: see /v2/docs/swift
    let listKitchenTickets: KitchenTicketPage = try await api.get(
        "/restaurants/123/kitchen/tickets",
        options: .init(query: ["view": "active", "area": "kitchen"])
    ) // 200
    // klient: viz /v2/docs/dart
    final listKitchenTickets = pr.KitchenTicketPage.fromJson(await api.get('/restaurants/123/kitchen/tickets', query: {'view': 'active', 'area': 'kitchen'})); // 200
    // the client: see /v2/docs/dart
    final listKitchenTickets = pr.KitchenTicketPage.fromJson(await api.get('/restaurants/123/kitchen/tickets', query: {'view': 'active', 'area': 'kitchen'})); // 200
    // klient: viz /v2/docs/go
    res, err := api.Get(
    	ctx,
    	"/restaurants/123/kitchen/tickets",
    	&profirest.RequestOptions{Query: map[string]any{"view": "active", "area": "kitchen"}},
    )
    var listKitchenTickets model.KitchenTicketPage // 200
    if err == nil {
    	err = res.Decode(&listKitchenTickets)
    }
    // the client: see /v2/docs/go
    res, err := api.Get(
    	ctx,
    	"/restaurants/123/kitchen/tickets",
    	&profirest.RequestOptions{Query: map[string]any{"view": "active", "area": "kitchen"}},
    )
    var listKitchenTickets model.KitchenTicketPage // 200
    if err == nil {
    	err = res.Decode(&listKitchenTickets)
    }
    Příklad odpovědi 200Example answer 200
    {
      "data": [
        {
          "id": "77812",
          "order_id": "184223",
          "number": "027",
          "status": "preparing",
          "area": "kitchen",
          "source": "web",
          "platform": null,
          "name": "Jana Nováková",
          "fulfillment": "takeaway",
          "express": false,
          "customer": {
            "name": "Jana Nováková",
            "phone": "+420777123456",
            "not_delivered_count": 0,
            "last_not_delivered_at": null
          },
          "delivery_address": null,
          "delivery_zone": null,
          "note": null,
          "payment_method": "cash",
          "total": {
            "amount": 39800,
            "currency": "CZK"
          },
          "delivery_price": {
            "amount": 0,
            "currency": "CZK"
          },
          "amount_due": {
            "amount": 39800,
            "currency": "CZK"
          },
          "paid_by": null,
          "created_at": "2027-01-15T11:42:31+01:00",
          "scheduled_for": null,
          "printed": true,
          "courier": null,
          "not_delivered": null,
          "items": [
            {
              "id": "52011",
              "product_id": "4567",
              "name": "Svíčková na smetaně, houskový knedlík",
              "kitchen_name": null,
              "note": null,
              "quantity": 2,
              "kind": "full",
              "charge": null,
              "course": 0,
              "category": {
                "id": "312",
                "name": "Hlavní jídla"
              },
              "from_daily_menu": false,
              "station_id": "2",
              "status": "pending",
              "handed_out": false,
              "part": null,
              "size": null,
              "unit_price": {
                "amount": 19900,
                "currency": "CZK"
              },
              "packaging_price": {
                "amount": 0,
                "currency": "CZK"
              },
              "discount": {
                "amount": 0,
                "currency": "CZK"
              },
              "gift": false,
              "vat_rate": "12",
              "removed_ingredients": [],
              "modifiers": []
            }
          ],
          "receipt": {
            "items": {
              "amount": 39800,
              "currency": "CZK"
            },
            "discounts": [],
            "delivery": {
              "amount": 0,
              "currency": "CZK"
            },
            "rounding": {
              "amount": 0,
              "currency": "CZK"
            },
            "adjustment": {
              "amount": 0,
              "currency": "CZK"
            },
            "total": {
              "amount": 39800,
              "currency": "CZK"
            },
            "to_pay": {
              "amount": 39800,
              "currency": "CZK"
            },
            "vat": [
              {
                "rate": "12",
                "base": {
                  "amount": 35536,
                  "currency": "CZK"
                },
                "vat": {
                  "amount": 4264,
                  "currency": "CZK"
                },
                "total": {
                  "amount": 39800,
                  "currency": "CZK"
                }
              }
            ],
            "document": {
              "title": "Účtenka",
              "number": "184223",
              "tax_document": "Zjednodušený daňový doklad"
            }
          }
        },
        {
          "id": "77814",
          "order_id": "184230",
          "number": "029",
          "status": "received",
          "area": "kitchen",
          "source": "pos",
          "platform": null,
          "name": "Stůl 4",
          "fulfillment": "dine_in",
          "express": false,
          "customer": null,
          "delivery_address": null,
          "delivery_zone": null,
          "note": null,
          "payment_method": "cash",
          "total": {
            "amount": 19900,
            "currency": "CZK"
          },
          "delivery_price": {
            "amount": 0,
            "currency": "CZK"
          },
          "amount_due": {
            "amount": 0,
            "currency": "CZK"
          },
          "paid_by": null,
          "created_at": "2027-01-15T11:51:40+01:00",
          "scheduled_for": null,
          "printed": false,
          "courier": null,
          "not_delivered": null,
          "items": [
            {
              "id": "52020",
              "product_id": "4567",
              "name": "Svíčková na smetaně, houskový knedlík",
              "kitchen_name": null,
              "note": null,
              "quantity": 1,
              "kind": "full",
              "charge": null,
              "course": 1,
              "category": {
                "id": "312",
                "name": "Hlavní jídla"
              },
              "from_daily_menu": false,
              "station_id": "2",
              "status": "pending",
              "handed_out": false,
              "part": null,
              "size": null,
              "unit_price": {
                "amount": 19900,
                "currency": "CZK"
              },
              "packaging_price": {
                "amount": 0,
                "currency": "CZK"
              },
              "discount": {
                "amount": 0,
                "currency": "CZK"
              },
              "gift": false,
              "vat_rate": "12",
              "removed_ingredients": [],
              "modifiers": []
            }
          ],
          "receipt": {
            "items": {
              "amount": 19900,
              "currency": "CZK"
            },
            "discounts": [],
            "delivery": {
              "amount": 0,
              "currency": "CZK"
            },
            "rounding": {
              "amount": 0,
              "currency": "CZK"
            },
            "adjustment": {
              "amount": 0,
              "currency": "CZK"
            },
            "total": {
              "amount": 19900,
              "currency": "CZK"
            },
            "to_pay": {
              "amount": 19900,
              "currency": "CZK"
            },
            "vat": [
              {
                "rate": "12",
                "base": {
                  "amount": 17768,
                  "currency": "CZK"
                },
                "vat": {
                  "amount": 2132,
                  "currency": "CZK"
                },
                "total": {
                  "amount": 19900,
                  "currency": "CZK"
                }
              }
            ],
            "document": {
              "title": "Účtenka",
              "number": "184230",
              "tax_document": "Zjednodušený daňový doklad"
            }
          }
        },
        {
          "id": "77815",
          "order_id": "184226",
          "number": "030",
          "status": "ready",
          "area": "kitchen",
          "source": "web",
          "platform": null,
          "name": "Jana Nováková",
          "fulfillment": "delivery",
          "express": false,
          "customer": {
            "name": "Jana Nováková",
            "phone": "+420777123456",
            "not_delivered_count": 0,
            "last_not_delivered_at": null
          },
          "delivery_address": {
            "street": "Jeseniova 1196/52",
            "city": "Praha 3",
            "location": {
              "lat": 50.0833,
              "lon": 14.4667
            }
          },
          "delivery_zone": {
            "id": "21",
            "name": "Vinohrady do 3 km"
          },
          "note": "3. patro, zvonek Nováková",
          "payment_method": "cash",
          "total": {
            "amount": 38600,
            "currency": "CZK"
          },
          "delivery_price": {
            "amount": 4900,
            "currency": "CZK"
          },
          "amount_due": {
            "amount": 38600,
            "currency": "CZK"
          },
          "paid_by": null,
          "created_at": "2027-01-15T11:50:40+01:00",
          "scheduled_for": null,
          "printed": true,
          "courier": null,
          "not_delivered": null,
          "items": [
            {
              "id": "52031",
              "product_id": "4571",
              "name": "Pizza Margherita",
              "kitchen_name": null,
              "note": "Nekrájet",
              "quantity": 1,
              "kind": "full",
              "charge": null,
              "course": 0,
              "category": {
                "id": "315",
                "name": "Pizza"
              },
              "from_daily_menu": false,
              "station_id": "3",
              "status": "done",
              "handed_out": false,
              "part": null,
              "size": {
                "name": "Ø32cm",
                "dish_name": "Pizza Margherita"
              },
              "unit_price": {
                "amount": 18900,
                "currency": "CZK"
              },
              "packaging_price": {
                "amount": 0,
                "currency": "CZK"
              },
              "discount": {
                "amount": 0,
                "currency": "CZK"
              },
              "gift": false,
              "vat_rate": "12",
              "removed_ingredients": [],
              "modifiers": [
                {
                  "id": "52032",
                  "charge": null,
                  "product_id": "4602",
                  "name": "Extra sýr",
                  "kitchen_name": null,
                  "note": null,
                  "quantity": 1,
                  "kind": "full",
                  "status": "done",
                  "handed_out": false,
                  "part": null,
                  "size": null,
                  "unit_price": {
                    "amount": 3000,
                    "currency": "CZK"
                  },
                  "packaging_price": {
                    "amount": 0,
                    "currency": "CZK"
                  },
                  "discount": {
                    "amount": 0,
                    "currency": "CZK"
                  },
                  "gift": false,
                  "vat_rate": "12",
                  "removed_ingredients": []
                }
              ]
            },
            {
              "id": "52033",
              "product_id": "4593",
              "name": "Domácí limonáda 0,4 l",
              "kitchen_name": null,
              "note": null,
              "quantity": 2,
              "kind": "full",
              "charge": null,
              "course": 0,
              "category": {
                "id": "320",
                "name": "Nápoje"
              },
              "from_daily_menu": false,
              "station_id": null,
              "status": "done",
              "handed_out": false,
              "part": null,
              "size": null,
              "unit_price": {
                "amount": 5900,
                "currency": "CZK"
              },
              "packaging_price": {
                "amount": 0,
                "currency": "CZK"
              },
              "discount": {
                "amount": 0,
                "currency": "CZK"
              },
              "gift": false,
              "vat_rate": "12",
              "removed_ingredients": [],
              "modifiers": []
            }
          ],
          "receipt": {
            "items": {
              "amount": 33700,
              "currency": "CZK"
            },
            "discounts": [],
            "delivery": {
              "amount": 4900,
              "currency": "CZK"
            },
            "rounding": {
              "amount": 0,
              "currency": "CZK"
            },
            "adjustment": {
              "amount": 0,
              "currency": "CZK"
            },
            "total": {
              "amount": 38600,
              "currency": "CZK"
            },
            "to_pay": {
              "amount": 38600,
              "currency": "CZK"
            },
            "vat": [
              {
                "rate": "12",
                "base": {
                  "amount": 34464,
                  "currency": "CZK"
                },
                "vat": {
                  "amount": 4136,
                  "currency": "CZK"
                },
                "total": {
                  "amount": 38600,
                  "currency": "CZK"
                }
              }
            ],
            "document": {
              "title": "Účtenka",
              "number": "184226",
              "tax_document": "Zjednodušený daňový doklad"
            }
          }
        }
      ],
      "next_cursor": null,
      "preorders_later": 2
    }
  2. Změňte stav

    Change the status

    POST /restaurants/{restaurant_id}/kitchen/tickets/{ticket_id}/status · setKitchenTicketStatus

    preparing, ready, delivered – zákazník e-shopu se o hotové objednávce dozví hned.

    preparing, ready, delivered – an e-shop customer learns about a ready order at once.

    curl "https://api.mujprofirest.cz/v2/restaurants/123/kitchen/tickets/77812/status" \
      -H "Authorization: Bearer $ACCESS_TOKEN" \
      -H "Profirest-Staff-Token: $STAFF_TOKEN" \
      -H "Idempotency-Key: 01a318f0-a0c0-7859-9873-bf7a7bca44e7" \
      -H "Content-Type: application/json" \
      -d '{"status": "ready"}'
    curl "https://api.mujprofirest.cz/v2/restaurants/123/kitchen/tickets/77812/status" \
      -H "Authorization: Bearer $ACCESS_TOKEN" \
      -H "Profirest-Staff-Token: $STAFF_TOKEN" \
      -H "Idempotency-Key: 01a318f0-a0c0-7859-9873-bf7a7bca44e7" \
      -H "Content-Type: application/json" \
      -d '{"status": "ready"}'
    // klient: viz /v2/docs/js
    // token zaměstnance přidá knihovna sama (po přihlášení zaměstnance)
    const kitchenTicketStatus = await api.post('/restaurants/123/kitchen/tickets/77812/status', { status: 'ready' }); // 200
    // the client: see /v2/docs/js
    // the library adds the employee's token itself (after the employee signs in)
    const kitchenTicketStatus = await api.post('/restaurants/123/kitchen/tickets/77812/status', { status: 'ready' }); // 200
    // klient: viz /v2/docs/typescript
    // token zaměstnance přidá knihovna sama (po přihlášení zaměstnance)
    const kitchenTicketStatus = await api.post('/restaurants/123/kitchen/tickets/77812/status', { status: 'ready' }); // 200 KitchenTicket
    // the client: see /v2/docs/typescript
    // the library adds the employee's token itself (after the employee signs in)
    const kitchenTicketStatus = await api.post('/restaurants/123/kitchen/tickets/77812/status', { status: 'ready' }); // 200 KitchenTicket
    // klient: viz /v2/docs/php
    // token zaměstnance přidá knihovna sama (po přihlášení zaměstnance)
    $kitchenTicketStatus = $api->post('/restaurants/123/kitchen/tickets/77812/status', ['status' => 'ready']); // 200
    // the client: see /v2/docs/php
    // the library adds the employee's token itself (after the employee signs in)
    $kitchenTicketStatus = $api->post('/restaurants/123/kitchen/tickets/77812/status', ['status' => 'ready']); // 200
    // klient: viz /v2/docs/java
    // volání blokuje – na Androidu z pracovního vlákna (Dispatchers.IO)
    // token zaměstnance přidá knihovna sama (po přihlášení zaměstnance)
    KitchenTicket kitchenTicketStatus = api.post("/restaurants/123/kitchen/tickets/77812/status", Json.parse("""
        {"status": "ready"}
        """), KitchenTicket::fromJson); // 200
    // the client: see /v2/docs/java
    // the call blocks – on Android from a worker thread (Dispatchers.IO)
    // the library adds the employee's token itself (after the employee signs in)
    KitchenTicket kitchenTicketStatus = api.post("/restaurants/123/kitchen/tickets/77812/status", Json.parse("""
        {"status": "ready"}
        """), KitchenTicket::fromJson); // 200
    // klient: viz /v2/docs/java
    // volání blokuje – na Androidu z pracovního vlákna (Dispatchers.IO)
    // token zaměstnance přidá knihovna sama (po přihlášení zaměstnance)
    val kitchenTicketStatus = api.post(
        "/restaurants/123/kitchen/tickets/77812/status",
        mapOf("status" to "ready"),
        KitchenTicket::fromJson,
    ) // 200
    // the client: see /v2/docs/java
    // the call blocks – on Android from a worker thread (Dispatchers.IO)
    // the library adds the employee's token itself (after the employee signs in)
    val kitchenTicketStatus = api.post(
        "/restaurants/123/kitchen/tickets/77812/status",
        mapOf("status" to "ready"),
        KitchenTicket::fromJson,
    ) // 200
    // klient: viz /v2/docs/csharp
    // token zaměstnance přidá knihovna sama (po přihlášení zaměstnance)
    var kitchenTicketStatus = await api.PostAsync<KitchenTicket>(
        "/restaurants/123/kitchen/tickets/77812/status",
        new { status = "ready" }
    ); // 200
    // the client: see /v2/docs/csharp
    // the library adds the employee's token itself (after the employee signs in)
    var kitchenTicketStatus = await api.PostAsync<KitchenTicket>(
        "/restaurants/123/kitchen/tickets/77812/status",
        new { status = "ready" }
    ); // 200
    # klient: viz /v2/docs/python
    # token zaměstnance přidá knihovna sama (po přihlášení zaměstnance)
    kitchen_ticket_status = api.post('/restaurants/123/kitchen/tickets/77812/status', {'status': 'ready'})  # 200
    # the client: see /v2/docs/python
    # the library adds the employee's token itself (after the employee signs in)
    kitchen_ticket_status = api.post('/restaurants/123/kitchen/tickets/77812/status', {'status': 'ready'})  # 200
    // klient: viz /v2/docs/swift
    // token zaměstnance přidá knihovna sama (po přihlášení zaměstnance)
    let kitchenTicketStatus: KitchenTicket = try await api.post("/restaurants/123/kitchen/tickets/77812/status", body: ["status": "ready"]) // 200
    // the client: see /v2/docs/swift
    // the library adds the employee's token itself (after the employee signs in)
    let kitchenTicketStatus: KitchenTicket = try await api.post("/restaurants/123/kitchen/tickets/77812/status", body: ["status": "ready"]) // 200
    // klient: viz /v2/docs/dart
    // token zaměstnance přidá knihovna sama (po přihlášení zaměstnance)
    final kitchenTicketStatus = pr.KitchenTicket.fromJson(await api.post('/restaurants/123/kitchen/tickets/77812/status', {'status': 'ready'})); // 200
    // the client: see /v2/docs/dart
    // the library adds the employee's token itself (after the employee signs in)
    final kitchenTicketStatus = pr.KitchenTicket.fromJson(await api.post('/restaurants/123/kitchen/tickets/77812/status', {'status': 'ready'})); // 200
    // klient: viz /v2/docs/go
    // token zaměstnance přidá knihovna sama (po přihlášení zaměstnance)
    res, err := api.Post(
    	ctx,
    	"/restaurants/123/kitchen/tickets/77812/status",
    	map[string]any{"status": "ready"},
    	nil,
    )
    var kitchenTicketStatus model.KitchenTicket // 200
    if err == nil {
    	err = res.Decode(&kitchenTicketStatus)
    }
    // the client: see /v2/docs/go
    // the library adds the employee's token itself (after the employee signs in)
    res, err := api.Post(
    	ctx,
    	"/restaurants/123/kitchen/tickets/77812/status",
    	map[string]any{"status": "ready"},
    	nil,
    )
    var kitchenTicketStatus model.KitchenTicket // 200
    if err == nil {
    	err = res.Decode(&kitchenTicketStatus)
    }
    Příklad odpovědi 200Example answer 200
    {
      "id": "77812",
      "order_id": "184223",
      "number": "027",
      "status": "ready",
      "area": "kitchen",
      "source": "web",
      "platform": null,
      "name": "Jana Nováková",
      "fulfillment": "takeaway",
      "express": false,
      "customer": {
        "name": "Jana Nováková",
        "phone": "+420777123456",
        "not_delivered_count": 0,
        "last_not_delivered_at": null
      },
      "delivery_address": null,
      "delivery_zone": null,
      "note": null,
      "payment_method": "cash",
      "total": {
        "amount": 39800,
        "currency": "CZK"
      },
      "delivery_price": {
        "amount": 0,
        "currency": "CZK"
      },
      "amount_due": {
        "amount": 39800,
        "currency": "CZK"
      },
      "paid_by": null,
      "created_at": "2027-01-15T11:42:31+01:00",
      "scheduled_for": null,
      "printed": true,
      "courier": null,
      "not_delivered": null,
      "items": [
        {
          "id": "52011",
          "product_id": "4567",
          "name": "Svíčková na smetaně, houskový knedlík",
          "kitchen_name": null,
          "note": null,
          "quantity": 2,
          "kind": "full",
          "charge": null,
          "course": 0,
          "category": {
            "id": "312",
            "name": "Hlavní jídla"
          },
          "from_daily_menu": false,
          "station_id": "2",
          "status": "done",
          "handed_out": false,
          "part": null,
          "size": null,
          "unit_price": {
            "amount": 19900,
            "currency": "CZK"
          },
          "packaging_price": {
            "amount": 0,
            "currency": "CZK"
          },
          "discount": {
            "amount": 0,
            "currency": "CZK"
          },
          "gift": false,
          "vat_rate": "12",
          "removed_ingredients": [],
          "modifiers": []
        }
      ],
      "receipt": {
        "items": {
          "amount": 39800,
          "currency": "CZK"
        },
        "discounts": [],
        "delivery": {
          "amount": 0,
          "currency": "CZK"
        },
        "rounding": {
          "amount": 0,
          "currency": "CZK"
        },
        "adjustment": {
          "amount": 0,
          "currency": "CZK"
        },
        "total": {
          "amount": 39800,
          "currency": "CZK"
        },
        "to_pay": {
          "amount": 39800,
          "currency": "CZK"
        },
        "vat": [
          {
            "rate": "12",
            "base": {
              "amount": 35536,
              "currency": "CZK"
            },
            "vat": {
              "amount": 4264,
              "currency": "CZK"
            },
            "total": {
              "amount": 39800,
              "currency": "CZK"
            }
          }
        ],
        "document": {
          "title": "Účtenka",
          "number": "184223",
          "tax_document": "Zjednodušený daňový doklad"
        }
      }
    }
  3. Výroba po stanovištích

    Production by station

    GET /restaurants/{restaurant_id}/kitchen/stations/{station_id}/tickets · listStationTickets

    Každé stanoviště vidí jen své položky, rozdělené po chodech a kategoriích.

    Every station sees only its items, split by courses and categories.

    curl "https://api.mujprofirest.cz/v2/restaurants/123/kitchen/stations/2/tickets" \
      -H "Authorization: Bearer $ACCESS_TOKEN"
    curl "https://api.mujprofirest.cz/v2/restaurants/123/kitchen/stations/2/tickets" \
      -H "Authorization: Bearer $ACCESS_TOKEN"
    // klient: viz /v2/docs/js
    const listStationTickets = await api.get('/restaurants/123/kitchen/stations/2/tickets'); // 200
    // the client: see /v2/docs/js
    const listStationTickets = await api.get('/restaurants/123/kitchen/stations/2/tickets'); // 200
    // klient: viz /v2/docs/typescript
    const listStationTickets = await api.get('/restaurants/123/kitchen/stations/2/tickets'); // 200 StationTicketList
    // the client: see /v2/docs/typescript
    const listStationTickets = await api.get('/restaurants/123/kitchen/stations/2/tickets'); // 200 StationTicketList
    // klient: viz /v2/docs/php
    $listStationTickets = $api->get('/restaurants/123/kitchen/stations/2/tickets'); // 200
    // the client: see /v2/docs/php
    $listStationTickets = $api->get('/restaurants/123/kitchen/stations/2/tickets'); // 200
    // klient: viz /v2/docs/java
    // volání blokuje – na Androidu z pracovního vlákna (Dispatchers.IO)
    StationTicketList listStationTickets = api.get("/restaurants/123/kitchen/stations/2/tickets", StationTicketList::fromJson); // 200
    // the client: see /v2/docs/java
    // the call blocks – on Android from a worker thread (Dispatchers.IO)
    StationTicketList listStationTickets = api.get("/restaurants/123/kitchen/stations/2/tickets", StationTicketList::fromJson); // 200
    // klient: viz /v2/docs/java
    // volání blokuje – na Androidu z pracovního vlákna (Dispatchers.IO)
    val listStationTickets = api.get("/restaurants/123/kitchen/stations/2/tickets", StationTicketList::fromJson) // 200
    // the client: see /v2/docs/java
    // the call blocks – on Android from a worker thread (Dispatchers.IO)
    val listStationTickets = api.get("/restaurants/123/kitchen/stations/2/tickets", StationTicketList::fromJson) // 200
    // klient: viz /v2/docs/csharp
    var listStationTickets = await api.GetAsync<StationTicketList>("/restaurants/123/kitchen/stations/2/tickets"); // 200
    // the client: see /v2/docs/csharp
    var listStationTickets = await api.GetAsync<StationTicketList>("/restaurants/123/kitchen/stations/2/tickets"); // 200
    # klient: viz /v2/docs/python
    list_station_tickets = api.get('/restaurants/123/kitchen/stations/2/tickets')  # 200
    # the client: see /v2/docs/python
    list_station_tickets = api.get('/restaurants/123/kitchen/stations/2/tickets')  # 200
    // klient: viz /v2/docs/swift
    let listStationTickets: StationTicketList = try await api.get("/restaurants/123/kitchen/stations/2/tickets") // 200
    // the client: see /v2/docs/swift
    let listStationTickets: StationTicketList = try await api.get("/restaurants/123/kitchen/stations/2/tickets") // 200
    // klient: viz /v2/docs/dart
    final listStationTickets = pr.StationTicketList.fromJson(await api.get('/restaurants/123/kitchen/stations/2/tickets')); // 200
    // the client: see /v2/docs/dart
    final listStationTickets = pr.StationTicketList.fromJson(await api.get('/restaurants/123/kitchen/stations/2/tickets')); // 200
    // klient: viz /v2/docs/go
    res, err := api.Get(ctx, "/restaurants/123/kitchen/stations/2/tickets", nil)
    var listStationTickets model.StationTicketList // 200
    if err == nil {
    	err = res.Decode(&listStationTickets)
    }
    // the client: see /v2/docs/go
    res, err := api.Get(ctx, "/restaurants/123/kitchen/stations/2/tickets", nil)
    var listStationTickets model.StationTicketList // 200
    if err == nil {
    	err = res.Decode(&listStationTickets)
    }
    Příklad odpovědi 200Example answer 200
    {
      "data": [
        {
          "ticket": {
            "id": "77812",
            "order_id": "184223",
            "number": "027",
            "status": "preparing",
            "area": "kitchen",
            "source": "web",
            "platform": null,
            "name": "Jana Nováková",
            "fulfillment": "takeaway",
            "express": false,
            "customer": {
              "name": "Jana Nováková",
              "phone": "+420777123456",
              "not_delivered_count": 0,
              "last_not_delivered_at": null
            },
            "delivery_address": null,
            "delivery_zone": null,
            "note": null,
            "payment_method": "cash",
            "total": {
              "amount": 39800,
              "currency": "CZK"
            },
            "delivery_price": {
              "amount": 0,
              "currency": "CZK"
            },
            "amount_due": {
              "amount": 39800,
              "currency": "CZK"
            },
            "paid_by": null,
            "created_at": "2027-01-15T11:42:31+01:00",
            "scheduled_for": null,
            "printed": true,
            "courier": null,
            "not_delivered": null,
            "items": [
              {
                "id": "52011",
                "product_id": "4567",
                "name": "Svíčková na smetaně, houskový knedlík",
                "kitchen_name": null,
                "note": null,
                "quantity": 2,
                "kind": "full",
                "charge": null,
                "course": 0,
                "category": {
                  "id": "312",
                  "name": "Hlavní jídla"
                },
                "from_daily_menu": false,
                "station_id": "2",
                "status": "pending",
                "handed_out": false,
                "part": null,
                "size": null,
                "unit_price": {
                  "amount": 19900,
                  "currency": "CZK"
                },
                "packaging_price": {
                  "amount": 0,
                  "currency": "CZK"
                },
                "discount": {
                  "amount": 0,
                  "currency": "CZK"
                },
                "gift": false,
                "vat_rate": "12",
                "removed_ingredients": [],
                "modifiers": []
              }
            ],
            "receipt": {
              "items": {
                "amount": 39800,
                "currency": "CZK"
              },
              "discounts": [],
              "delivery": {
                "amount": 0,
                "currency": "CZK"
              },
              "rounding": {
                "amount": 0,
                "currency": "CZK"
              },
              "adjustment": {
                "amount": 0,
                "currency": "CZK"
              },
              "total": {
                "amount": 39800,
                "currency": "CZK"
              },
              "to_pay": {
                "amount": 39800,
                "currency": "CZK"
              },
              "vat": [
                {
                  "rate": "12",
                  "base": {
                    "amount": 35536,
                    "currency": "CZK"
                  },
                  "vat": {
                    "amount": 4264,
                    "currency": "CZK"
                  },
                  "total": {
                    "amount": 39800,
                    "currency": "CZK"
                  }
                }
              ],
              "document": {
                "title": "Účtenka",
                "number": "184223",
                "tax_document": "Zjednodušený daňový doklad"
              }
            }
          },
          "working": true,
          "other_stations": [],
          "courses": [
            {
              "course": 0,
              "done": false,
              "categories": [
                {
                  "id": "312",
                  "name": "Hlavní jídla",
                  "done": false,
                  "item_ids": [
                    "52011"
                  ]
                }
              ]
            }
          ]
        },
        {
          "ticket": {
            "id": "77814",
            "order_id": "184230",
            "number": "029",
            "status": "received",
            "area": "kitchen",
            "source": "pos",
            "platform": null,
            "name": "Stůl 4",
            "fulfillment": "dine_in",
            "express": false,
            "customer": null,
            "delivery_address": null,
            "delivery_zone": null,
            "note": null,
            "payment_method": "cash",
            "total": {
              "amount": 19900,
              "currency": "CZK"
            },
            "delivery_price": {
              "amount": 0,
              "currency": "CZK"
            },
            "amount_due": {
              "amount": 0,
              "currency": "CZK"
            },
            "paid_by": null,
            "created_at": "2027-01-15T11:51:40+01:00",
            "scheduled_for": null,
            "printed": false,
            "courier": null,
            "not_delivered": null,
            "items": [
              {
                "id": "52020",
                "product_id": "4567",
                "name": "Svíčková na smetaně, houskový knedlík",
                "kitchen_name": null,
                "note": null,
                "quantity": 1,
                "kind": "full",
                "charge": null,
                "course": 1,
                "category": {
                  "id": "312",
                  "name": "Hlavní jídla"
                },
                "from_daily_menu": false,
                "station_id": "2",
                "status": "pending",
                "handed_out": false,
                "part": null,
                "size": null,
                "unit_price": {
                  "amount": 19900,
                  "currency": "CZK"
                },
                "packaging_price": {
                  "amount": 0,
                  "currency": "CZK"
                },
                "discount": {
                  "amount": 0,
                  "currency": "CZK"
                },
                "gift": false,
                "vat_rate": "12",
                "removed_ingredients": [],
                "modifiers": []
              }
            ],
            "receipt": {
              "items": {
                "amount": 19900,
                "currency": "CZK"
              },
              "discounts": [],
              "delivery": {
                "amount": 0,
                "currency": "CZK"
              },
              "rounding": {
                "amount": 0,
                "currency": "CZK"
              },
              "adjustment": {
                "amount": 0,
                "currency": "CZK"
              },
              "total": {
                "amount": 19900,
                "currency": "CZK"
              },
              "to_pay": {
                "amount": 19900,
                "currency": "CZK"
              },
              "vat": [
                {
                  "rate": "12",
                  "base": {
                    "amount": 17768,
                    "currency": "CZK"
                  },
                  "vat": {
                    "amount": 2132,
                    "currency": "CZK"
                  },
                  "total": {
                    "amount": 19900,
                    "currency": "CZK"
                  }
                }
              ],
              "document": {
                "title": "Účtenka",
                "number": "184230",
                "tax_document": "Zjednodušený daňový doklad"
              }
            }
          },
          "working": false,
          "other_stations": [
            {
              "id": "3",
              "name": "Pizza"
            }
          ],
          "courses": [
            {
              "course": 1,
              "done": false,
              "categories": [
                {
                  "id": "312",
                  "name": "Hlavní jídla",
                  "done": false,
                  "item_ids": [
                    "52020"
                  ]
                }
              ]
            }
          ]
        }
      ]
    }
  4. Odbavte chod

    Complete a course

    POST /restaurants/{restaurant_id}/kitchen/stations/{station_id}/tickets/{ticket_id}/complete · completeStationSegment

    Celou objednávku, chod nebo kategorii. Omyl jde vrátit v historii stanoviště (undo).

    The whole order, a course or a category. A mistake can be undone in the station's history.

    curl "https://api.mujprofirest.cz/v2/restaurants/123/kitchen/stations/2/tickets/77812/complete" \
      -H "Authorization: Bearer $ACCESS_TOKEN" \
      -H "Profirest-Staff-Token: $STAFF_TOKEN" \
      -H "Idempotency-Key: 01a318f0-a0c0-7286-8f53-6133d6a059b4" \
      -H "Content-Type: application/json" \
      -d '{"scope": "order"}'
    curl "https://api.mujprofirest.cz/v2/restaurants/123/kitchen/stations/2/tickets/77812/complete" \
      -H "Authorization: Bearer $ACCESS_TOKEN" \
      -H "Profirest-Staff-Token: $STAFF_TOKEN" \
      -H "Idempotency-Key: 01a318f0-a0c0-7286-8f53-6133d6a059b4" \
      -H "Content-Type: application/json" \
      -d '{"scope": "order"}'
    // klient: viz /v2/docs/js
    // token zaměstnance přidá knihovna sama (po přihlášení zaměstnance)
    const stationSegment = await api.post('/restaurants/123/kitchen/stations/2/tickets/77812/complete', { scope: 'order' }); // 201
    // the client: see /v2/docs/js
    // the library adds the employee's token itself (after the employee signs in)
    const stationSegment = await api.post('/restaurants/123/kitchen/stations/2/tickets/77812/complete', { scope: 'order' }); // 201
    // klient: viz /v2/docs/typescript
    // token zaměstnance přidá knihovna sama (po přihlášení zaměstnance)
    const stationSegment = await api.post('/restaurants/123/kitchen/stations/2/tickets/77812/complete', { scope: 'order' }); // 201 ProductionAction
    // the client: see /v2/docs/typescript
    // the library adds the employee's token itself (after the employee signs in)
    const stationSegment = await api.post('/restaurants/123/kitchen/stations/2/tickets/77812/complete', { scope: 'order' }); // 201 ProductionAction
    // klient: viz /v2/docs/php
    // token zaměstnance přidá knihovna sama (po přihlášení zaměstnance)
    $stationSegment = $api->post('/restaurants/123/kitchen/stations/2/tickets/77812/complete', ['scope' => 'order']); // 201
    // the client: see /v2/docs/php
    // the library adds the employee's token itself (after the employee signs in)
    $stationSegment = $api->post('/restaurants/123/kitchen/stations/2/tickets/77812/complete', ['scope' => 'order']); // 201
    // klient: viz /v2/docs/java
    // volání blokuje – na Androidu z pracovního vlákna (Dispatchers.IO)
    // token zaměstnance přidá knihovna sama (po přihlášení zaměstnance)
    ProductionAction stationSegment = api.post("/restaurants/123/kitchen/stations/2/tickets/77812/complete", Json.parse("""
        {"scope": "order"}
        """), ProductionAction::fromJson); // 201
    // the client: see /v2/docs/java
    // the call blocks – on Android from a worker thread (Dispatchers.IO)
    // the library adds the employee's token itself (after the employee signs in)
    ProductionAction stationSegment = api.post("/restaurants/123/kitchen/stations/2/tickets/77812/complete", Json.parse("""
        {"scope": "order"}
        """), ProductionAction::fromJson); // 201
    // klient: viz /v2/docs/java
    // volání blokuje – na Androidu z pracovního vlákna (Dispatchers.IO)
    // token zaměstnance přidá knihovna sama (po přihlášení zaměstnance)
    val stationSegment = api.post(
        "/restaurants/123/kitchen/stations/2/tickets/77812/complete",
        mapOf("scope" to "order"),
        ProductionAction::fromJson,
    ) // 201
    // the client: see /v2/docs/java
    // the call blocks – on Android from a worker thread (Dispatchers.IO)
    // the library adds the employee's token itself (after the employee signs in)
    val stationSegment = api.post(
        "/restaurants/123/kitchen/stations/2/tickets/77812/complete",
        mapOf("scope" to "order"),
        ProductionAction::fromJson,
    ) // 201
    // klient: viz /v2/docs/csharp
    // token zaměstnance přidá knihovna sama (po přihlášení zaměstnance)
    var stationSegment = await api.PostAsync<ProductionAction>(
        "/restaurants/123/kitchen/stations/2/tickets/77812/complete",
        new { scope = "order" }
    ); // 201
    // the client: see /v2/docs/csharp
    // the library adds the employee's token itself (after the employee signs in)
    var stationSegment = await api.PostAsync<ProductionAction>(
        "/restaurants/123/kitchen/stations/2/tickets/77812/complete",
        new { scope = "order" }
    ); // 201
    # klient: viz /v2/docs/python
    # token zaměstnance přidá knihovna sama (po přihlášení zaměstnance)
    station_segment = api.post('/restaurants/123/kitchen/stations/2/tickets/77812/complete', {'scope': 'order'})  # 201
    # the client: see /v2/docs/python
    # the library adds the employee's token itself (after the employee signs in)
    station_segment = api.post('/restaurants/123/kitchen/stations/2/tickets/77812/complete', {'scope': 'order'})  # 201
    // klient: viz /v2/docs/swift
    // token zaměstnance přidá knihovna sama (po přihlášení zaměstnance)
    let stationSegment: ProductionAction = try await api.post("/restaurants/123/kitchen/stations/2/tickets/77812/complete", body: ["scope": "order"]) // 201
    // the client: see /v2/docs/swift
    // the library adds the employee's token itself (after the employee signs in)
    let stationSegment: ProductionAction = try await api.post("/restaurants/123/kitchen/stations/2/tickets/77812/complete", body: ["scope": "order"]) // 201
    // klient: viz /v2/docs/dart
    // token zaměstnance přidá knihovna sama (po přihlášení zaměstnance)
    final stationSegment = pr.ProductionAction.fromJson(await api.post('/restaurants/123/kitchen/stations/2/tickets/77812/complete', {'scope': 'order'})); // 201
    // the client: see /v2/docs/dart
    // the library adds the employee's token itself (after the employee signs in)
    final stationSegment = pr.ProductionAction.fromJson(await api.post('/restaurants/123/kitchen/stations/2/tickets/77812/complete', {'scope': 'order'})); // 201
    // klient: viz /v2/docs/go
    // token zaměstnance přidá knihovna sama (po přihlášení zaměstnance)
    res, err := api.Post(
    	ctx,
    	"/restaurants/123/kitchen/stations/2/tickets/77812/complete",
    	map[string]any{"scope": "order"},
    	nil,
    )
    var stationSegment model.ProductionAction // 201
    if err == nil {
    	err = res.Decode(&stationSegment)
    }
    // the client: see /v2/docs/go
    // the library adds the employee's token itself (after the employee signs in)
    res, err := api.Post(
    	ctx,
    	"/restaurants/123/kitchen/stations/2/tickets/77812/complete",
    	map[string]any{"scope": "order"},
    	nil,
    )
    var stationSegment model.ProductionAction // 201
    if err == nil {
    	err = res.Decode(&stationSegment)
    }
    Příklad odpovědi 201Example answer 201
    {
      "id": "9921",
      "ticket_id": "77812",
      "kind": "production",
      "scope": "order",
      "name": "Celá objednávka",
      "item_count": 2,
      "undone": false,
      "created_at": "2027-01-15T11:57:02+01:00",
      "employee": {
        "id": "66",
        "name": "Lucie Svobodová"
      }
    }
  5. Výdej

    Hand-out

    POST /restaurants/{restaurant_id}/kitchen/tickets/{ticket_id}/handover · handOverTicketSegment

    Výdejní okno potvrdí, co odešlo ke stolu nebo zákazníkovi.

    The hand-out window confirms what went to the table or the customer.

    curl "https://api.mujprofirest.cz/v2/restaurants/123/kitchen/tickets/77812/handover" \
      -H "Authorization: Bearer $ACCESS_TOKEN" \
      -H "Profirest-Staff-Token: $STAFF_TOKEN" \
      -H "Idempotency-Key: 01a318f0-a0c0-76ca-9937-77abc3d63953" \
      -H "Content-Type: application/json" \
      -d '{"scope": "order"}'
    curl "https://api.mujprofirest.cz/v2/restaurants/123/kitchen/tickets/77812/handover" \
      -H "Authorization: Bearer $ACCESS_TOKEN" \
      -H "Profirest-Staff-Token: $STAFF_TOKEN" \
      -H "Idempotency-Key: 01a318f0-a0c0-76ca-9937-77abc3d63953" \
      -H "Content-Type: application/json" \
      -d '{"scope": "order"}'
    // klient: viz /v2/docs/js
    // token zaměstnance přidá knihovna sama (po přihlášení zaměstnance)
    const overTicketSegment = await api.post('/restaurants/123/kitchen/tickets/77812/handover', { scope: 'order' }); // 201
    // the client: see /v2/docs/js
    // the library adds the employee's token itself (after the employee signs in)
    const overTicketSegment = await api.post('/restaurants/123/kitchen/tickets/77812/handover', { scope: 'order' }); // 201
    // klient: viz /v2/docs/typescript
    // token zaměstnance přidá knihovna sama (po přihlášení zaměstnance)
    const overTicketSegment = await api.post('/restaurants/123/kitchen/tickets/77812/handover', { scope: 'order' }); // 201 ProductionAction
    // the client: see /v2/docs/typescript
    // the library adds the employee's token itself (after the employee signs in)
    const overTicketSegment = await api.post('/restaurants/123/kitchen/tickets/77812/handover', { scope: 'order' }); // 201 ProductionAction
    // klient: viz /v2/docs/php
    // token zaměstnance přidá knihovna sama (po přihlášení zaměstnance)
    $overTicketSegment = $api->post('/restaurants/123/kitchen/tickets/77812/handover', ['scope' => 'order']); // 201
    // the client: see /v2/docs/php
    // the library adds the employee's token itself (after the employee signs in)
    $overTicketSegment = $api->post('/restaurants/123/kitchen/tickets/77812/handover', ['scope' => 'order']); // 201
    // klient: viz /v2/docs/java
    // volání blokuje – na Androidu z pracovního vlákna (Dispatchers.IO)
    // token zaměstnance přidá knihovna sama (po přihlášení zaměstnance)
    ProductionAction overTicketSegment = api.post("/restaurants/123/kitchen/tickets/77812/handover", Json.parse("""
        {"scope": "order"}
        """), ProductionAction::fromJson); // 201
    // the client: see /v2/docs/java
    // the call blocks – on Android from a worker thread (Dispatchers.IO)
    // the library adds the employee's token itself (after the employee signs in)
    ProductionAction overTicketSegment = api.post("/restaurants/123/kitchen/tickets/77812/handover", Json.parse("""
        {"scope": "order"}
        """), ProductionAction::fromJson); // 201
    // klient: viz /v2/docs/java
    // volání blokuje – na Androidu z pracovního vlákna (Dispatchers.IO)
    // token zaměstnance přidá knihovna sama (po přihlášení zaměstnance)
    val overTicketSegment = api.post(
        "/restaurants/123/kitchen/tickets/77812/handover",
        mapOf("scope" to "order"),
        ProductionAction::fromJson,
    ) // 201
    // the client: see /v2/docs/java
    // the call blocks – on Android from a worker thread (Dispatchers.IO)
    // the library adds the employee's token itself (after the employee signs in)
    val overTicketSegment = api.post(
        "/restaurants/123/kitchen/tickets/77812/handover",
        mapOf("scope" to "order"),
        ProductionAction::fromJson,
    ) // 201
    // klient: viz /v2/docs/csharp
    // token zaměstnance přidá knihovna sama (po přihlášení zaměstnance)
    var overTicketSegment = await api.PostAsync<ProductionAction>(
        "/restaurants/123/kitchen/tickets/77812/handover",
        new { scope = "order" }
    ); // 201
    // the client: see /v2/docs/csharp
    // the library adds the employee's token itself (after the employee signs in)
    var overTicketSegment = await api.PostAsync<ProductionAction>(
        "/restaurants/123/kitchen/tickets/77812/handover",
        new { scope = "order" }
    ); // 201
    # klient: viz /v2/docs/python
    # token zaměstnance přidá knihovna sama (po přihlášení zaměstnance)
    over_ticket_segment = api.post('/restaurants/123/kitchen/tickets/77812/handover', {'scope': 'order'})  # 201
    # the client: see /v2/docs/python
    # the library adds the employee's token itself (after the employee signs in)
    over_ticket_segment = api.post('/restaurants/123/kitchen/tickets/77812/handover', {'scope': 'order'})  # 201
    // klient: viz /v2/docs/swift
    // token zaměstnance přidá knihovna sama (po přihlášení zaměstnance)
    let overTicketSegment: ProductionAction = try await api.post("/restaurants/123/kitchen/tickets/77812/handover", body: ["scope": "order"]) // 201
    // the client: see /v2/docs/swift
    // the library adds the employee's token itself (after the employee signs in)
    let overTicketSegment: ProductionAction = try await api.post("/restaurants/123/kitchen/tickets/77812/handover", body: ["scope": "order"]) // 201
    // klient: viz /v2/docs/dart
    // token zaměstnance přidá knihovna sama (po přihlášení zaměstnance)
    final overTicketSegment = pr.ProductionAction.fromJson(await api.post('/restaurants/123/kitchen/tickets/77812/handover', {'scope': 'order'})); // 201
    // the client: see /v2/docs/dart
    // the library adds the employee's token itself (after the employee signs in)
    final overTicketSegment = pr.ProductionAction.fromJson(await api.post('/restaurants/123/kitchen/tickets/77812/handover', {'scope': 'order'})); // 201
    // klient: viz /v2/docs/go
    // token zaměstnance přidá knihovna sama (po přihlášení zaměstnance)
    res, err := api.Post(
    	ctx,
    	"/restaurants/123/kitchen/tickets/77812/handover",
    	map[string]any{"scope": "order"},
    	nil,
    )
    var overTicketSegment model.ProductionAction // 201
    if err == nil {
    	err = res.Decode(&overTicketSegment)
    }
    // the client: see /v2/docs/go
    // the library adds the employee's token itself (after the employee signs in)
    res, err := api.Post(
    	ctx,
    	"/restaurants/123/kitchen/tickets/77812/handover",
    	map[string]any{"scope": "order"},
    	nil,
    )
    var overTicketSegment model.ProductionAction // 201
    if err == nil {
    	err = res.Decode(&overTicketSegment)
    }
    Příklad odpovědi 201Example answer 201
    {
      "id": "9930",
      "ticket_id": "77812",
      "kind": "handover",
      "scope": "order",
      "name": "Celá objednávka",
      "item_count": 2,
      "undone": false,
      "created_at": "2027-01-15T12:04:11+01:00",
      "employee": {
        "id": "58",
        "name": "Jana Dvořáková"
      }
    }
  6. Pořadník pro zákazníky

    The queue for customers

    GET /restaurants/{restaurant_id}/kitchen/queue · getKitchenQueue

    Čísla „připravujeme“ a „hotovo“ pro obrazovku u výdeje.

    The “preparing” and “ready” numbers for the screen at the counter.

    curl "https://api.mujprofirest.cz/v2/restaurants/123/kitchen/queue" \
      -H "Authorization: Bearer $ACCESS_TOKEN"
    curl "https://api.mujprofirest.cz/v2/restaurants/123/kitchen/queue" \
      -H "Authorization: Bearer $ACCESS_TOKEN"
    // klient: viz /v2/docs/js
    const kitchenQueue = await api.get('/restaurants/123/kitchen/queue'); // 200
    // the client: see /v2/docs/js
    const kitchenQueue = await api.get('/restaurants/123/kitchen/queue'); // 200
    // klient: viz /v2/docs/typescript
    const kitchenQueue = await api.get('/restaurants/123/kitchen/queue'); // 200 KitchenQueue
    // the client: see /v2/docs/typescript
    const kitchenQueue = await api.get('/restaurants/123/kitchen/queue'); // 200 KitchenQueue
    // klient: viz /v2/docs/php
    $kitchenQueue = $api->get('/restaurants/123/kitchen/queue'); // 200
    // the client: see /v2/docs/php
    $kitchenQueue = $api->get('/restaurants/123/kitchen/queue'); // 200
    // klient: viz /v2/docs/java
    // volání blokuje – na Androidu z pracovního vlákna (Dispatchers.IO)
    KitchenQueue kitchenQueue = api.get("/restaurants/123/kitchen/queue", KitchenQueue::fromJson); // 200
    // the client: see /v2/docs/java
    // the call blocks – on Android from a worker thread (Dispatchers.IO)
    KitchenQueue kitchenQueue = api.get("/restaurants/123/kitchen/queue", KitchenQueue::fromJson); // 200
    // klient: viz /v2/docs/java
    // volání blokuje – na Androidu z pracovního vlákna (Dispatchers.IO)
    val kitchenQueue = api.get("/restaurants/123/kitchen/queue", KitchenQueue::fromJson) // 200
    // the client: see /v2/docs/java
    // the call blocks – on Android from a worker thread (Dispatchers.IO)
    val kitchenQueue = api.get("/restaurants/123/kitchen/queue", KitchenQueue::fromJson) // 200
    // klient: viz /v2/docs/csharp
    var kitchenQueue = await api.GetAsync<KitchenQueue>("/restaurants/123/kitchen/queue"); // 200
    // the client: see /v2/docs/csharp
    var kitchenQueue = await api.GetAsync<KitchenQueue>("/restaurants/123/kitchen/queue"); // 200
    # klient: viz /v2/docs/python
    kitchen_queue = api.get('/restaurants/123/kitchen/queue')  # 200
    # the client: see /v2/docs/python
    kitchen_queue = api.get('/restaurants/123/kitchen/queue')  # 200
    // klient: viz /v2/docs/swift
    let kitchenQueue: KitchenQueue = try await api.get("/restaurants/123/kitchen/queue") // 200
    // the client: see /v2/docs/swift
    let kitchenQueue: KitchenQueue = try await api.get("/restaurants/123/kitchen/queue") // 200
    // klient: viz /v2/docs/dart
    final kitchenQueue = pr.KitchenQueue.fromJson(await api.get('/restaurants/123/kitchen/queue')); // 200
    // the client: see /v2/docs/dart
    final kitchenQueue = pr.KitchenQueue.fromJson(await api.get('/restaurants/123/kitchen/queue')); // 200
    // klient: viz /v2/docs/go
    res, err := api.Get(ctx, "/restaurants/123/kitchen/queue", nil)
    var kitchenQueue model.KitchenQueue // 200
    if err == nil {
    	err = res.Decode(&kitchenQueue)
    }
    // the client: see /v2/docs/go
    res, err := api.Get(ctx, "/restaurants/123/kitchen/queue", nil)
    var kitchenQueue model.KitchenQueue // 200
    if err == nil {
    	err = res.Decode(&kitchenQueue)
    }
    Příklad odpovědi 200Example answer 200
    {
      "preparing": [
        {
          "ticket_id": "77812",
          "number": "027",
          "since": "2027-01-15T11:44:02+01:00"
        },
        {
          "ticket_id": "77814",
          "number": "029",
          "since": "2027-01-15T11:52:00+01:00"
        }
      ],
      "ready": [
        {
          "ticket_id": "77815",
          "number": "030",
          "since": "2027-01-15T11:58:20+01:00"
        }
      ]
    }
  7. Uzávěrka kuchyně

    Closing the kitchen

    POST /restaurants/{restaurant_id}/kitchen/shift/close · closeKitchenShift

    Tržby podle plateb a kurýrů; číslování bonů začne znovu.

    Takings by payment and courier; ticket numbering starts again.

    curl "https://api.mujprofirest.cz/v2/restaurants/123/kitchen/shift/close" \
      -H "Authorization: Bearer $ACCESS_TOKEN" \
      -H "Profirest-Staff-Token: $STAFF_TOKEN" \
      -H "Idempotency-Key: 01a318f0-a0c0-7066-9b00-4e4d06fa5038" \
      -H "Content-Type: application/json" \
      -d '{"courier_id": null}'
    curl "https://api.mujprofirest.cz/v2/restaurants/123/kitchen/shift/close" \
      -H "Authorization: Bearer $ACCESS_TOKEN" \
      -H "Profirest-Staff-Token: $STAFF_TOKEN" \
      -H "Idempotency-Key: 01a318f0-a0c0-7066-9b00-4e4d06fa5038" \
      -H "Content-Type: application/json" \
      -d '{"courier_id": null}'
    // klient: viz /v2/docs/js
    // token zaměstnance přidá knihovna sama (po přihlášení zaměstnance)
    const kitchenShift = await api.post('/restaurants/123/kitchen/shift/close', { courier_id: null }); // 201
    // the client: see /v2/docs/js
    // the library adds the employee's token itself (after the employee signs in)
    const kitchenShift = await api.post('/restaurants/123/kitchen/shift/close', { courier_id: null }); // 201
    // klient: viz /v2/docs/typescript
    // token zaměstnance přidá knihovna sama (po přihlášení zaměstnance)
    const kitchenShift = await api.post('/restaurants/123/kitchen/shift/close', { courier_id: null }); // 201 KitchenShiftClose
    // the client: see /v2/docs/typescript
    // the library adds the employee's token itself (after the employee signs in)
    const kitchenShift = await api.post('/restaurants/123/kitchen/shift/close', { courier_id: null }); // 201 KitchenShiftClose
    // klient: viz /v2/docs/php
    // token zaměstnance přidá knihovna sama (po přihlášení zaměstnance)
    $kitchenShift = $api->post('/restaurants/123/kitchen/shift/close', ['courier_id' => null]); // 201
    // the client: see /v2/docs/php
    // the library adds the employee's token itself (after the employee signs in)
    $kitchenShift = $api->post('/restaurants/123/kitchen/shift/close', ['courier_id' => null]); // 201
    // klient: viz /v2/docs/java
    // volání blokuje – na Androidu z pracovního vlákna (Dispatchers.IO)
    // token zaměstnance přidá knihovna sama (po přihlášení zaměstnance)
    KitchenShiftClose kitchenShift = api.post("/restaurants/123/kitchen/shift/close", Json.parse("""
        {"courier_id": null}
        """), KitchenShiftClose::fromJson); // 201
    // the client: see /v2/docs/java
    // the call blocks – on Android from a worker thread (Dispatchers.IO)
    // the library adds the employee's token itself (after the employee signs in)
    KitchenShiftClose kitchenShift = api.post("/restaurants/123/kitchen/shift/close", Json.parse("""
        {"courier_id": null}
        """), KitchenShiftClose::fromJson); // 201
    // klient: viz /v2/docs/java
    // volání blokuje – na Androidu z pracovního vlákna (Dispatchers.IO)
    // token zaměstnance přidá knihovna sama (po přihlášení zaměstnance)
    val kitchenShift = api.post(
        "/restaurants/123/kitchen/shift/close",
        mapOf("courier_id" to null),
        KitchenShiftClose::fromJson,
    ) // 201
    // the client: see /v2/docs/java
    // the call blocks – on Android from a worker thread (Dispatchers.IO)
    // the library adds the employee's token itself (after the employee signs in)
    val kitchenShift = api.post(
        "/restaurants/123/kitchen/shift/close",
        mapOf("courier_id" to null),
        KitchenShiftClose::fromJson,
    ) // 201
    // klient: viz /v2/docs/csharp
    // token zaměstnance přidá knihovna sama (po přihlášení zaměstnance)
    var kitchenShift = await api.PostAsync<KitchenShiftClose>(
        "/restaurants/123/kitchen/shift/close",
        new { courier_id = (object?)null }
    ); // 201
    // the client: see /v2/docs/csharp
    // the library adds the employee's token itself (after the employee signs in)
    var kitchenShift = await api.PostAsync<KitchenShiftClose>(
        "/restaurants/123/kitchen/shift/close",
        new { courier_id = (object?)null }
    ); // 201
    # klient: viz /v2/docs/python
    # token zaměstnance přidá knihovna sama (po přihlášení zaměstnance)
    kitchen_shift = api.post('/restaurants/123/kitchen/shift/close', {'courier_id': None})  # 201
    # the client: see /v2/docs/python
    # the library adds the employee's token itself (after the employee signs in)
    kitchen_shift = api.post('/restaurants/123/kitchen/shift/close', {'courier_id': None})  # 201
    // klient: viz /v2/docs/swift
    // token zaměstnance přidá knihovna sama (po přihlášení zaměstnance)
    let kitchenShift: KitchenShiftClose = try await api.post("/restaurants/123/kitchen/shift/close", body: ["courier_id": nil]) // 201
    // the client: see /v2/docs/swift
    // the library adds the employee's token itself (after the employee signs in)
    let kitchenShift: KitchenShiftClose = try await api.post("/restaurants/123/kitchen/shift/close", body: ["courier_id": nil]) // 201
    // klient: viz /v2/docs/dart
    // token zaměstnance přidá knihovna sama (po přihlášení zaměstnance)
    final kitchenShift = pr.KitchenShiftClose.fromJson(await api.post('/restaurants/123/kitchen/shift/close', {'courier_id': null})); // 201
    // the client: see /v2/docs/dart
    // the library adds the employee's token itself (after the employee signs in)
    final kitchenShift = pr.KitchenShiftClose.fromJson(await api.post('/restaurants/123/kitchen/shift/close', {'courier_id': null})); // 201
    // klient: viz /v2/docs/go
    // token zaměstnance přidá knihovna sama (po přihlášení zaměstnance)
    res, err := api.Post(ctx, "/restaurants/123/kitchen/shift/close", map[string]any{"courier_id": nil}, nil)
    var kitchenShift model.KitchenShiftClose // 201
    if err == nil {
    	err = res.Decode(&kitchenShift)
    }
    // the client: see /v2/docs/go
    // the library adds the employee's token itself (after the employee signs in)
    res, err := api.Post(ctx, "/restaurants/123/kitchen/shift/close", map[string]any{"courier_id": nil}, nil)
    var kitchenShift model.KitchenShiftClose // 201
    if err == nil {
    	err = res.Decode(&kitchenShift)
    }
    Příklad odpovědi 201Example answer 201
    {
      "id": "1187",
      "closed_at": "2027-01-15T22:15:40+01:00",
      "closed_by": {
        "id": "61",
        "name": "Petr Novák"
      },
      "closed_orders": 64,
      "numbering_reset": true,
      "summary": {
        "orders": 64,
        "completed": {
          "amount": 1954300,
          "currency": "CZK"
        },
        "by_payment": {
          "cash": {
            "amount": 802100,
            "currency": "CZK"
          },
          "card": {
            "amount": 1029500,
            "currency": "CZK"
          },
          "meal_voucher": {
            "amount": 0,
            "currency": "CZK"
          },
          "company_account": {
            "amount": 0,
            "currency": "CZK"
          },
          "invoice": {
            "amount": 122700,
            "currency": "CZK"
          }
        },
        "not_completed": {
          "amount": 0,
          "currency": "CZK"
        },
        "not_delivered": {
          "orders": 1,
          "total": {
            "amount": 38600,
            "currency": "CZK"
          }
        },
        "cancelled": {
          "amount": 18900,
          "currency": "CZK"
        },
        "courier_id": null,
        "couriers": [
          {
            "orders": 9,
            "completed": {
              "amount": 352800,
              "currency": "CZK"
            },
            "by_payment": {
              "cash": {
                "amount": 214300,
                "currency": "CZK"
              },
              "card": {
                "amount": 138500,
                "currency": "CZK"
              },
              "meal_voucher": {
                "amount": 0,
                "currency": "CZK"
              },
              "company_account": {
                "amount": 0,
                "currency": "CZK"
              },
              "invoice": {
                "amount": 0,
                "currency": "CZK"
              }
            },
            "not_completed": {
              "amount": 0,
              "currency": "CZK"
            },
            "not_delivered": {
              "orders": 1,
              "total": {
                "amount": 38600,
                "currency": "CZK"
              }
            },
            "cancelled": {
              "amount": 0,
              "currency": "CZK"
            },
            "courier": {
              "id": "64",
              "name": "Tomáš Král"
            }
          }
        ]
      }
    }

Scénář

Scenario

Docházkový terminál

An attendance terminal

Vlastní zařízení ProfirestuProfirest's own device

Terminál u vchodu: zaměstnanec se prokáže PINem nebo čipem a píchne příchod, přestávku nebo odchod. Bez sítě si záznamy podrží a pošle je dávkou.

A terminal at the entrance: an employee proves who they are with a PIN or a card and records an arrival, a break or a departure. Without a network it keeps the records and sends them in a batch.

  1. Vzhled terminálu

    The terminal's look

    GET /restaurants/{restaurant_id}/attendance/terminal · getAttendanceTerminal

    Logo, barvu, světlou nebo tmavou obrazovku a uvítání si provozovna nastaví v administraci; null znamená vzhled Profirestu. Odpověď si terminál uloží, ať nastartuje správně i bez sítě.

    The restaurant sets the logo, colour, light or dark screen and welcome line in the administration; null means Profirest's own look. The terminal keeps the answer so it starts right even without a network.

    curl "https://api.mujprofirest.cz/v2/restaurants/123/attendance/terminal" \
      -H "Authorization: Bearer $ACCESS_TOKEN"
    curl "https://api.mujprofirest.cz/v2/restaurants/123/attendance/terminal" \
      -H "Authorization: Bearer $ACCESS_TOKEN"
    // klient: viz /v2/docs/js
    const attendanceTerminal = await api.get('/restaurants/123/attendance/terminal'); // 200
    // the client: see /v2/docs/js
    const attendanceTerminal = await api.get('/restaurants/123/attendance/terminal'); // 200
    // klient: viz /v2/docs/typescript
    const attendanceTerminal = await api.get('/restaurants/123/attendance/terminal'); // 200 AttendanceTerminal
    // the client: see /v2/docs/typescript
    const attendanceTerminal = await api.get('/restaurants/123/attendance/terminal'); // 200 AttendanceTerminal
    // klient: viz /v2/docs/php
    $attendanceTerminal = $api->get('/restaurants/123/attendance/terminal'); // 200
    // the client: see /v2/docs/php
    $attendanceTerminal = $api->get('/restaurants/123/attendance/terminal'); // 200
    // klient: viz /v2/docs/java
    // volání blokuje – na Androidu z pracovního vlákna (Dispatchers.IO)
    AttendanceTerminal attendanceTerminal = api.get("/restaurants/123/attendance/terminal", AttendanceTerminal::fromJson); // 200
    // the client: see /v2/docs/java
    // the call blocks – on Android from a worker thread (Dispatchers.IO)
    AttendanceTerminal attendanceTerminal = api.get("/restaurants/123/attendance/terminal", AttendanceTerminal::fromJson); // 200
    // klient: viz /v2/docs/java
    // volání blokuje – na Androidu z pracovního vlákna (Dispatchers.IO)
    val attendanceTerminal = api.get("/restaurants/123/attendance/terminal", AttendanceTerminal::fromJson) // 200
    // the client: see /v2/docs/java
    // the call blocks – on Android from a worker thread (Dispatchers.IO)
    val attendanceTerminal = api.get("/restaurants/123/attendance/terminal", AttendanceTerminal::fromJson) // 200
    // klient: viz /v2/docs/csharp
    var attendanceTerminal = await api.GetAsync<AttendanceTerminal>("/restaurants/123/attendance/terminal"); // 200
    // the client: see /v2/docs/csharp
    var attendanceTerminal = await api.GetAsync<AttendanceTerminal>("/restaurants/123/attendance/terminal"); // 200
    # klient: viz /v2/docs/python
    attendance_terminal = api.get('/restaurants/123/attendance/terminal')  # 200
    # the client: see /v2/docs/python
    attendance_terminal = api.get('/restaurants/123/attendance/terminal')  # 200
    // klient: viz /v2/docs/swift
    let attendanceTerminal: AttendanceTerminal = try await api.get("/restaurants/123/attendance/terminal") // 200
    // the client: see /v2/docs/swift
    let attendanceTerminal: AttendanceTerminal = try await api.get("/restaurants/123/attendance/terminal") // 200
    // klient: viz /v2/docs/dart
    final attendanceTerminal = pr.AttendanceTerminal.fromJson(await api.get('/restaurants/123/attendance/terminal')); // 200
    // the client: see /v2/docs/dart
    final attendanceTerminal = pr.AttendanceTerminal.fromJson(await api.get('/restaurants/123/attendance/terminal')); // 200
    // klient: viz /v2/docs/go
    res, err := api.Get(ctx, "/restaurants/123/attendance/terminal", nil)
    var attendanceTerminal model.AttendanceTerminal // 200
    if err == nil {
    	err = res.Decode(&attendanceTerminal)
    }
    // the client: see /v2/docs/go
    res, err := api.Get(ctx, "/restaurants/123/attendance/terminal", nil)
    var attendanceTerminal model.AttendanceTerminal // 200
    if err == nil {
    	err = res.Decode(&attendanceTerminal)
    }
    Příklad odpovědi 200Example answer 200
    {
      "restaurant_name": "Bistro U Lípy",
      "branding": {
        "logo_url": "https://www.mujprofirest.cz/uploads/terminal/123-logo.png",
        "accent_color": "#0e7c66",
        "theme": "light",
        "welcome_text": "Dobré ráno, ať se dnes daří!"
      },
      "offline": {
        "allowed": true,
        "max_age_hours": 24
      },
      "absence_requests": {
        "enabled": true,
        "types": [
          "holiday",
          "unpaid",
          "sick"
        ],
        "notice_days": 14,
        "max_days": 14,
        "horizon_days": 180
      }
    }
  2. Kdo se smí píchat

    Who may punch

    GET /restaurants/{restaurant_id}/staff · listStaff

    Seznam bez PINů – PIN ověřuje jen server.

    A list without PINs – only the server checks a PIN.

    curl "https://api.mujprofirest.cz/v2/restaurants/123/staff" \
      -H "Authorization: Bearer $ACCESS_TOKEN"
    curl "https://api.mujprofirest.cz/v2/restaurants/123/staff" \
      -H "Authorization: Bearer $ACCESS_TOKEN"
    // klient: viz /v2/docs/js
    const { data, next_cursor } = await api.get('/restaurants/123/staff'); // 200
    // the client: see /v2/docs/js
    const { data, next_cursor } = await api.get('/restaurants/123/staff'); // 200
    // klient: viz /v2/docs/typescript
    const { data, next_cursor } = await api.get('/restaurants/123/staff'); // 200 StaffMemberPage
    // the client: see /v2/docs/typescript
    const { data, next_cursor } = await api.get('/restaurants/123/staff'); // 200 StaffMemberPage
    // klient: viz /v2/docs/php
    $page = $api->get('/restaurants/123/staff'); // $page['data'], $page['next_cursor']
    // the client: see /v2/docs/php
    $page = $api->get('/restaurants/123/staff'); // $page['data'], $page['next_cursor']
    // klient: viz /v2/docs/java
    // volání blokuje – na Androidu z pracovního vlákna (Dispatchers.IO)
    StaffMemberPage listStaff = api.get("/restaurants/123/staff", StaffMemberPage::fromJson); // 200
    // the client: see /v2/docs/java
    // the call blocks – on Android from a worker thread (Dispatchers.IO)
    StaffMemberPage listStaff = api.get("/restaurants/123/staff", StaffMemberPage::fromJson); // 200
    // klient: viz /v2/docs/java
    // volání blokuje – na Androidu z pracovního vlákna (Dispatchers.IO)
    val listStaff = api.get("/restaurants/123/staff", StaffMemberPage::fromJson) // 200
    // the client: see /v2/docs/java
    // the call blocks – on Android from a worker thread (Dispatchers.IO)
    val listStaff = api.get("/restaurants/123/staff", StaffMemberPage::fromJson) // 200
    // klient: viz /v2/docs/csharp
    var listStaff = await api.GetAsync<StaffMemberPage>("/restaurants/123/staff"); // 200
    // the client: see /v2/docs/csharp
    var listStaff = await api.GetAsync<StaffMemberPage>("/restaurants/123/staff"); // 200
    # klient: viz /v2/docs/python
    page = api.get('/restaurants/123/staff')  # page['data'], page['next_cursor']
    # the client: see /v2/docs/python
    page = api.get('/restaurants/123/staff')  # page['data'], page['next_cursor']
    // klient: viz /v2/docs/swift
    let listStaff: StaffMemberPage = try await api.get("/restaurants/123/staff") // 200
    // the client: see /v2/docs/swift
    let listStaff: StaffMemberPage = try await api.get("/restaurants/123/staff") // 200
    // klient: viz /v2/docs/dart
    final listStaff = pr.StaffMemberPage.fromJson(await api.get('/restaurants/123/staff')); // 200
    // the client: see /v2/docs/dart
    final listStaff = pr.StaffMemberPage.fromJson(await api.get('/restaurants/123/staff')); // 200
    // klient: viz /v2/docs/go
    res, err := api.Get(ctx, "/restaurants/123/staff", nil)
    var listStaff model.StaffMemberPage // 200
    if err == nil {
    	err = res.Decode(&listStaff)
    }
    // the client: see /v2/docs/go
    res, err := api.Get(ctx, "/restaurants/123/staff", nil)
    var listStaff model.StaffMemberPage // 200
    if err == nil {
    	err = res.Decode(&listStaff)
    }
    Příklad odpovědi 200Example answer 200
    {
      "data": [
        {
          "id": "58",
          "name": "Jana Dvořáková",
          "roles": [
            "pos"
          ],
          "attendance": {
            "enabled": true
          },
          "sign_in": {
            "pin": true,
            "card": true
          },
          "offline_approval": {
            "salt": "pHk3r9QnW1xY0aBcDeFgHw",
            "iterations": 100000,
            "check": 141
          },
          "offline_sign_in": {
            "salt": "pHk3r9QnW1xY0aBcDeFgHw",
            "iterations": 100000,
            "check": 141
          }
        },
        {
          "id": "61",
          "name": "Petr Novák",
          "roles": [
            "pos",
            "pos_manager",
            "kitchen_manager"
          ],
          "attendance": {
            "enabled": true
          },
          "sign_in": {
            "pin": true,
            "card": true
          },
          "offline_approval": {
            "salt": "pHk3r9QnW1xY0aBcDeFgHw",
            "iterations": 100000,
            "check": 141
          },
          "offline_sign_in": {
            "salt": "pHk3r9QnW1xY0aBcDeFgHw",
            "iterations": 100000,
            "check": 141
          }
        },
        {
          "id": "66",
          "name": "Lucie Svobodová",
          "roles": [
            "kitchen"
          ],
          "attendance": {
            "enabled": true
          },
          "sign_in": {
            "pin": true,
            "card": true
          },
          "offline_approval": {
            "salt": "pHk3r9QnW1xY0aBcDeFgHw",
            "iterations": 100000,
            "check": 141
          },
          "offline_sign_in": {
            "salt": "pHk3r9QnW1xY0aBcDeFgHw",
            "iterations": 100000,
            "check": 141
          }
        },
        {
          "id": "64",
          "name": "Tomáš Král",
          "roles": [],
          "attendance": {
            "enabled": true
          },
          "sign_in": {
            "pin": true,
            "card": false
          },
          "offline_approval": {
            "salt": "pHk3r9QnW1xY0aBcDeFgHw",
            "iterations": 100000,
            "check": 141
          },
          "offline_sign_in": {
            "salt": "pHk3r9QnW1xY0aBcDeFgHw",
            "iterations": 100000,
            "check": 141
          }
        }
      ],
      "next_cursor": null
    }
  3. Píchnutí

    A punch

    POST /restaurants/{restaurant_id}/attendance/punches · createAttendancePunch

    id je UUID z terminálu: stejné píchnutí poslané dvakrát se zapíše jednou. Stav, který nedává smysl (odchod bez příchodu), skončí 409 attendance_state_conflict.

    id is a UUID made on the terminal: the same punch sent twice is recorded once. A state that makes no sense (leaving without arriving) ends with 409 attendance_state_conflict.

    curl "https://api.mujprofirest.cz/v2/restaurants/123/attendance/punches" \
      -H "Authorization: Bearer $ACCESS_TOKEN" \
      -H "Content-Type: application/json" \
      -d '{
      "id": "01a318f0-a0c0-7ee7-995a-8607b7545591",
      "type": "clock_in",
      "credential": {"method": "pin", "secret": "4321"}
    }'
    curl "https://api.mujprofirest.cz/v2/restaurants/123/attendance/punches" \
      -H "Authorization: Bearer $ACCESS_TOKEN" \
      -H "Content-Type: application/json" \
      -d '{
      "id": "01a318f0-a0c0-7ee7-995a-8607b7545591",
      "type": "clock_in",
      "credential": {"method": "pin", "secret": "4321"}
    }'
    // klient: viz /v2/docs/js
    const attendancePunch = await api.post('/restaurants/123/attendance/punches', {
      id: '01a318f0-a0c0-7ee7-995a-8607b7545591',
      type: 'clock_in',
      credential: { method: 'pin', secret: '4321' },
    }); // 201
    // the client: see /v2/docs/js
    const attendancePunch = await api.post('/restaurants/123/attendance/punches', {
      id: '01a318f0-a0c0-7ee7-995a-8607b7545591',
      type: 'clock_in',
      credential: { method: 'pin', secret: '4321' },
    }); // 201
    // klient: viz /v2/docs/typescript
    const attendancePunch = await api.post('/restaurants/123/attendance/punches', {
      id: '01a318f0-a0c0-7ee7-995a-8607b7545591',
      type: 'clock_in',
      credential: { method: 'pin', secret: '4321' },
    }); // 201 AttendancePunch
    // the client: see /v2/docs/typescript
    const attendancePunch = await api.post('/restaurants/123/attendance/punches', {
      id: '01a318f0-a0c0-7ee7-995a-8607b7545591',
      type: 'clock_in',
      credential: { method: 'pin', secret: '4321' },
    }); // 201 AttendancePunch
    // klient: viz /v2/docs/php
    $attendancePunch = $api->post('/restaurants/123/attendance/punches', [
        'id' => '01a318f0-a0c0-7ee7-995a-8607b7545591',
        'type' => 'clock_in',
        'credential' => ['method' => 'pin', 'secret' => '4321'],
    ]); // 201
    // the client: see /v2/docs/php
    $attendancePunch = $api->post('/restaurants/123/attendance/punches', [
        'id' => '01a318f0-a0c0-7ee7-995a-8607b7545591',
        'type' => 'clock_in',
        'credential' => ['method' => 'pin', 'secret' => '4321'],
    ]); // 201
    // klient: viz /v2/docs/java
    // volání blokuje – na Androidu z pracovního vlákna (Dispatchers.IO)
    AttendancePunch attendancePunch = api.post("/restaurants/123/attendance/punches", Json.parse("""
        {
          "id": "01a318f0-a0c0-7ee7-995a-8607b7545591",
          "type": "clock_in",
          "credential": {"method": "pin", "secret": "4321"}
        }
        """), AttendancePunch::fromJson); // 201
    // the client: see /v2/docs/java
    // the call blocks – on Android from a worker thread (Dispatchers.IO)
    AttendancePunch attendancePunch = api.post("/restaurants/123/attendance/punches", Json.parse("""
        {
          "id": "01a318f0-a0c0-7ee7-995a-8607b7545591",
          "type": "clock_in",
          "credential": {"method": "pin", "secret": "4321"}
        }
        """), AttendancePunch::fromJson); // 201
    // klient: viz /v2/docs/java
    // volání blokuje – na Androidu z pracovního vlákna (Dispatchers.IO)
    val attendancePunch = api.post("/restaurants/123/attendance/punches", mapOf(
        "id" to "01a318f0-a0c0-7ee7-995a-8607b7545591",
        "type" to "clock_in",
        "credential" to mapOf("method" to "pin", "secret" to "4321"),
    ), AttendancePunch::fromJson) // 201
    // the client: see /v2/docs/java
    // the call blocks – on Android from a worker thread (Dispatchers.IO)
    val attendancePunch = api.post("/restaurants/123/attendance/punches", mapOf(
        "id" to "01a318f0-a0c0-7ee7-995a-8607b7545591",
        "type" to "clock_in",
        "credential" to mapOf("method" to "pin", "secret" to "4321"),
    ), AttendancePunch::fromJson) // 201
    // klient: viz /v2/docs/csharp
    var attendancePunch = await api.PostAsync<AttendancePunch>("/restaurants/123/attendance/punches", new {
        id = "01a318f0-a0c0-7ee7-995a-8607b7545591",
        type = "clock_in",
        credential = new { method = "pin", secret = "4321" },
    }); // 201
    // the client: see /v2/docs/csharp
    var attendancePunch = await api.PostAsync<AttendancePunch>("/restaurants/123/attendance/punches", new {
        id = "01a318f0-a0c0-7ee7-995a-8607b7545591",
        type = "clock_in",
        credential = new { method = "pin", secret = "4321" },
    }); // 201
    # klient: viz /v2/docs/python
    attendance_punch = api.post('/restaurants/123/attendance/punches', {
        'id': '01a318f0-a0c0-7ee7-995a-8607b7545591',
        'type': 'clock_in',
        'credential': {'method': 'pin', 'secret': '4321'},
    })  # 201
    # the client: see /v2/docs/python
    attendance_punch = api.post('/restaurants/123/attendance/punches', {
        'id': '01a318f0-a0c0-7ee7-995a-8607b7545591',
        'type': 'clock_in',
        'credential': {'method': 'pin', 'secret': '4321'},
    })  # 201
    // klient: viz /v2/docs/swift
    let attendancePunch: AttendancePunch = try await api.post("/restaurants/123/attendance/punches", body: [
        "id": "01a318f0-a0c0-7ee7-995a-8607b7545591",
        "type": "clock_in",
        "credential": ["method": "pin", "secret": "4321"],
    ]) // 201
    // the client: see /v2/docs/swift
    let attendancePunch: AttendancePunch = try await api.post("/restaurants/123/attendance/punches", body: [
        "id": "01a318f0-a0c0-7ee7-995a-8607b7545591",
        "type": "clock_in",
        "credential": ["method": "pin", "secret": "4321"],
    ]) // 201
    // klient: viz /v2/docs/dart
    final attendancePunch = pr.AttendancePunch.fromJson(await api.post('/restaurants/123/attendance/punches', {
      'id': '01a318f0-a0c0-7ee7-995a-8607b7545591',
      'type': 'clock_in',
      'credential': {'method': 'pin', 'secret': '4321'},
    })); // 201
    // the client: see /v2/docs/dart
    final attendancePunch = pr.AttendancePunch.fromJson(await api.post('/restaurants/123/attendance/punches', {
      'id': '01a318f0-a0c0-7ee7-995a-8607b7545591',
      'type': 'clock_in',
      'credential': {'method': 'pin', 'secret': '4321'},
    })); // 201
    // klient: viz /v2/docs/go
    res, err := api.Post(ctx, "/restaurants/123/attendance/punches", map[string]any{
    	"id": "01a318f0-a0c0-7ee7-995a-8607b7545591",
    	"type": "clock_in",
    	"credential": map[string]any{"method": "pin", "secret": "4321"},
    }, nil)
    var attendancePunch model.AttendancePunch // 201
    if err == nil {
    	err = res.Decode(&attendancePunch)
    }
    // the client: see /v2/docs/go
    res, err := api.Post(ctx, "/restaurants/123/attendance/punches", map[string]any{
    	"id": "01a318f0-a0c0-7ee7-995a-8607b7545591",
    	"type": "clock_in",
    	"credential": map[string]any{"method": "pin", "secret": "4321"},
    }, nil)
    var attendancePunch model.AttendancePunch // 201
    if err == nil {
    	err = res.Decode(&attendancePunch)
    }
    Příklad odpovědi 200Example answer 200
    {
      "id": "01a318f0-a0c0-7ee7-995a-8607b7545591",
      "employee": {
        "id": "58",
        "name": "Jana Dvořáková"
      },
      "type": "clock_in",
      "occurred_at": "2027-01-15T09:58:12+01:00",
      "received_at": "2027-01-15T09:58:13+01:00",
      "offline": false,
      "state": "working",
      "shift": {
        "started_at": "2027-01-15T09:58:12+01:00",
        "ended_at": null,
        "break_minutes": null,
        "worked_minutes": null
      }
    }
  4. Kdo je v práci

    Who is at work

    GET /restaurants/{restaurant_id}/attendance/presence · listAttendancePresence

    Pro obrazovku terminálu nebo vedoucího.

    For the terminal's screen or the manager.

    curl "https://api.mujprofirest.cz/v2/restaurants/123/attendance/presence" \
      -H "Authorization: Bearer $ACCESS_TOKEN"
    curl "https://api.mujprofirest.cz/v2/restaurants/123/attendance/presence" \
      -H "Authorization: Bearer $ACCESS_TOKEN"
    // klient: viz /v2/docs/js
    const { data, next_cursor } = await api.get('/restaurants/123/attendance/presence'); // 200
    // the client: see /v2/docs/js
    const { data, next_cursor } = await api.get('/restaurants/123/attendance/presence'); // 200
    // klient: viz /v2/docs/typescript
    const { data, next_cursor } = await api.get('/restaurants/123/attendance/presence'); // 200 AttendancePresencePage
    // the client: see /v2/docs/typescript
    const { data, next_cursor } = await api.get('/restaurants/123/attendance/presence'); // 200 AttendancePresencePage
    // klient: viz /v2/docs/php
    $page = $api->get('/restaurants/123/attendance/presence'); // $page['data'], $page['next_cursor']
    // the client: see /v2/docs/php
    $page = $api->get('/restaurants/123/attendance/presence'); // $page['data'], $page['next_cursor']
    // klient: viz /v2/docs/java
    // volání blokuje – na Androidu z pracovního vlákna (Dispatchers.IO)
    AttendancePresencePage listAttendancePresence = api.get("/restaurants/123/attendance/presence", AttendancePresencePage::fromJson); // 200
    // the client: see /v2/docs/java
    // the call blocks – on Android from a worker thread (Dispatchers.IO)
    AttendancePresencePage listAttendancePresence = api.get("/restaurants/123/attendance/presence", AttendancePresencePage::fromJson); // 200
    // klient: viz /v2/docs/java
    // volání blokuje – na Androidu z pracovního vlákna (Dispatchers.IO)
    val listAttendancePresence = api.get("/restaurants/123/attendance/presence", AttendancePresencePage::fromJson) // 200
    // the client: see /v2/docs/java
    // the call blocks – on Android from a worker thread (Dispatchers.IO)
    val listAttendancePresence = api.get("/restaurants/123/attendance/presence", AttendancePresencePage::fromJson) // 200
    // klient: viz /v2/docs/csharp
    var listAttendancePresence = await api.GetAsync<AttendancePresencePage>("/restaurants/123/attendance/presence"); // 200
    // the client: see /v2/docs/csharp
    var listAttendancePresence = await api.GetAsync<AttendancePresencePage>("/restaurants/123/attendance/presence"); // 200
    # klient: viz /v2/docs/python
    page = api.get('/restaurants/123/attendance/presence')  # page['data'], page['next_cursor']
    # the client: see /v2/docs/python
    page = api.get('/restaurants/123/attendance/presence')  # page['data'], page['next_cursor']
    // klient: viz /v2/docs/swift
    let listAttendancePresence: AttendancePresencePage = try await api.get("/restaurants/123/attendance/presence") // 200
    // the client: see /v2/docs/swift
    let listAttendancePresence: AttendancePresencePage = try await api.get("/restaurants/123/attendance/presence") // 200
    // klient: viz /v2/docs/dart
    final listAttendancePresence = pr.AttendancePresencePage.fromJson(await api.get('/restaurants/123/attendance/presence')); // 200
    // the client: see /v2/docs/dart
    final listAttendancePresence = pr.AttendancePresencePage.fromJson(await api.get('/restaurants/123/attendance/presence')); // 200
    // klient: viz /v2/docs/go
    res, err := api.Get(ctx, "/restaurants/123/attendance/presence", nil)
    var listAttendancePresence model.AttendancePresencePage // 200
    if err == nil {
    	err = res.Decode(&listAttendancePresence)
    }
    // the client: see /v2/docs/go
    res, err := api.Get(ctx, "/restaurants/123/attendance/presence", nil)
    var listAttendancePresence model.AttendancePresencePage // 200
    if err == nil {
    	err = res.Decode(&listAttendancePresence)
    }
    Příklad odpovědi 200Example answer 200
    {
      "data": [
        {
          "employee": {
            "id": "58",
            "name": "Jana Dvořáková"
          },
          "state": "working",
          "since": "2027-01-15T09:58:12+01:00",
          "shift_started_at": "2027-01-15T09:58:12+01:00"
        },
        {
          "employee": {
            "id": "66",
            "name": "Lucie Svobodová"
          },
          "state": "on_break",
          "since": "2027-01-15T11:30:05+01:00",
          "shift_started_at": "2027-01-15T08:00:40+01:00"
        },
        {
          "employee": {
            "id": "61",
            "name": "Petr Novák"
          },
          "state": "off",
          "since": null,
          "shift_started_at": null
        }
      ],
      "next_cursor": null
    }
  5. Záznamy z výpadku

    Records from an outage

    POST /restaurants/{restaurant_id}/attendance/punches/batch · createAttendancePunchBatch

    Každý záznam má vlastní výsledek: created, duplicate nebo rejected s chybou. Odeslané záznamy (s PINy) na zařízení hned smažte.

    Every record has its own result: created, duplicate or rejected with a problem. Delete the sent records (with PINs) from the device at once.

    curl "https://api.mujprofirest.cz/v2/restaurants/123/attendance/punches/batch" \
      -H "Authorization: Bearer $ACCESS_TOKEN" \
      -H "Content-Type: application/json" \
      -d '{
      "items": [
        {
          "id": "01a318f0-a0c0-7659-af30-64e055b22d85",
          "type": "break_start",
          "occurred_at": "2027-01-15T11:30:05+01:00",
          "credential": {"method": "card", "secret": "04B7C2D9E1"}
        },
        {
          "id": "01a318f0-a0c0-7804-a3a6-4d8707f841b2",
          "type": "break_end",
          "occurred_at": "2027-01-15T11:45:10+01:00",
          "credential": {"method": "card", "secret": "04B7C2D9E1"}
        },
        {
          "id": "01a318f0-a0c0-791a-b9db-5935f9c3e239",
          "type": "clock_in",
          "occurred_at": "2027-01-15T11:47:00+01:00",
          "credential": {"method": "pin", "secret": "9999"}
        }
      ]
    }'
    curl "https://api.mujprofirest.cz/v2/restaurants/123/attendance/punches/batch" \
      -H "Authorization: Bearer $ACCESS_TOKEN" \
      -H "Content-Type: application/json" \
      -d '{
      "items": [
        {
          "id": "01a318f0-a0c0-7659-af30-64e055b22d85",
          "type": "break_start",
          "occurred_at": "2027-01-15T11:30:05+01:00",
          "credential": {"method": "card", "secret": "04B7C2D9E1"}
        },
        {
          "id": "01a318f0-a0c0-7804-a3a6-4d8707f841b2",
          "type": "break_end",
          "occurred_at": "2027-01-15T11:45:10+01:00",
          "credential": {"method": "card", "secret": "04B7C2D9E1"}
        },
        {
          "id": "01a318f0-a0c0-791a-b9db-5935f9c3e239",
          "type": "clock_in",
          "occurred_at": "2027-01-15T11:47:00+01:00",
          "credential": {"method": "pin", "secret": "9999"}
        }
      ]
    }'
    // klient: viz /v2/docs/js
    const attendancePunchBatch = await api.post('/restaurants/123/attendance/punches/batch', {
      items: [
        {
          id: '01a318f0-a0c0-7659-af30-64e055b22d85',
          type: 'break_start',
          occurred_at: '2027-01-15T11:30:05+01:00',
          credential: { method: 'card', secret: '04B7C2D9E1' },
        },
        {
          id: '01a318f0-a0c0-7804-a3a6-4d8707f841b2',
          type: 'break_end',
          occurred_at: '2027-01-15T11:45:10+01:00',
          credential: { method: 'card', secret: '04B7C2D9E1' },
        },
        {
          id: '01a318f0-a0c0-791a-b9db-5935f9c3e239',
          type: 'clock_in',
          occurred_at: '2027-01-15T11:47:00+01:00',
          credential: { method: 'pin', secret: '9999' },
        },
      ],
    }); // 200
    // the client: see /v2/docs/js
    const attendancePunchBatch = await api.post('/restaurants/123/attendance/punches/batch', {
      items: [
        {
          id: '01a318f0-a0c0-7659-af30-64e055b22d85',
          type: 'break_start',
          occurred_at: '2027-01-15T11:30:05+01:00',
          credential: { method: 'card', secret: '04B7C2D9E1' },
        },
        {
          id: '01a318f0-a0c0-7804-a3a6-4d8707f841b2',
          type: 'break_end',
          occurred_at: '2027-01-15T11:45:10+01:00',
          credential: { method: 'card', secret: '04B7C2D9E1' },
        },
        {
          id: '01a318f0-a0c0-791a-b9db-5935f9c3e239',
          type: 'clock_in',
          occurred_at: '2027-01-15T11:47:00+01:00',
          credential: { method: 'pin', secret: '9999' },
        },
      ],
    }); // 200
    // klient: viz /v2/docs/typescript
    const attendancePunchBatch = await api.post('/restaurants/123/attendance/punches/batch', {
      items: [
        {
          id: '01a318f0-a0c0-7659-af30-64e055b22d85',
          type: 'break_start',
          occurred_at: '2027-01-15T11:30:05+01:00',
          credential: { method: 'card', secret: '04B7C2D9E1' },
        },
        {
          id: '01a318f0-a0c0-7804-a3a6-4d8707f841b2',
          type: 'break_end',
          occurred_at: '2027-01-15T11:45:10+01:00',
          credential: { method: 'card', secret: '04B7C2D9E1' },
        },
        {
          id: '01a318f0-a0c0-791a-b9db-5935f9c3e239',
          type: 'clock_in',
          occurred_at: '2027-01-15T11:47:00+01:00',
          credential: { method: 'pin', secret: '9999' },
        },
      ],
    }); // 200 AttendancePunchBatchResult
    // the client: see /v2/docs/typescript
    const attendancePunchBatch = await api.post('/restaurants/123/attendance/punches/batch', {
      items: [
        {
          id: '01a318f0-a0c0-7659-af30-64e055b22d85',
          type: 'break_start',
          occurred_at: '2027-01-15T11:30:05+01:00',
          credential: { method: 'card', secret: '04B7C2D9E1' },
        },
        {
          id: '01a318f0-a0c0-7804-a3a6-4d8707f841b2',
          type: 'break_end',
          occurred_at: '2027-01-15T11:45:10+01:00',
          credential: { method: 'card', secret: '04B7C2D9E1' },
        },
        {
          id: '01a318f0-a0c0-791a-b9db-5935f9c3e239',
          type: 'clock_in',
          occurred_at: '2027-01-15T11:47:00+01:00',
          credential: { method: 'pin', secret: '9999' },
        },
      ],
    }); // 200 AttendancePunchBatchResult
    // klient: viz /v2/docs/php
    $attendancePunchBatch = $api->post('/restaurants/123/attendance/punches/batch', [
        'items' => [
            [
                'id' => '01a318f0-a0c0-7659-af30-64e055b22d85',
                'type' => 'break_start',
                'occurred_at' => '2027-01-15T11:30:05+01:00',
                'credential' => ['method' => 'card', 'secret' => '04B7C2D9E1'],
            ],
            [
                'id' => '01a318f0-a0c0-7804-a3a6-4d8707f841b2',
                'type' => 'break_end',
                'occurred_at' => '2027-01-15T11:45:10+01:00',
                'credential' => ['method' => 'card', 'secret' => '04B7C2D9E1'],
            ],
            [
                'id' => '01a318f0-a0c0-791a-b9db-5935f9c3e239',
                'type' => 'clock_in',
                'occurred_at' => '2027-01-15T11:47:00+01:00',
                'credential' => ['method' => 'pin', 'secret' => '9999'],
            ],
        ],
    ]); // 200
    // the client: see /v2/docs/php
    $attendancePunchBatch = $api->post('/restaurants/123/attendance/punches/batch', [
        'items' => [
            [
                'id' => '01a318f0-a0c0-7659-af30-64e055b22d85',
                'type' => 'break_start',
                'occurred_at' => '2027-01-15T11:30:05+01:00',
                'credential' => ['method' => 'card', 'secret' => '04B7C2D9E1'],
            ],
            [
                'id' => '01a318f0-a0c0-7804-a3a6-4d8707f841b2',
                'type' => 'break_end',
                'occurred_at' => '2027-01-15T11:45:10+01:00',
                'credential' => ['method' => 'card', 'secret' => '04B7C2D9E1'],
            ],
            [
                'id' => '01a318f0-a0c0-791a-b9db-5935f9c3e239',
                'type' => 'clock_in',
                'occurred_at' => '2027-01-15T11:47:00+01:00',
                'credential' => ['method' => 'pin', 'secret' => '9999'],
            ],
        ],
    ]); // 200
    // klient: viz /v2/docs/java
    // volání blokuje – na Androidu z pracovního vlákna (Dispatchers.IO)
    AttendancePunchBatchResult attendancePunchBatch = api.post("/restaurants/123/attendance/punches/batch", Json.parse("""
        {
          "items": [
            {
              "id": "01a318f0-a0c0-7659-af30-64e055b22d85",
              "type": "break_start",
              "occurred_at": "2027-01-15T11:30:05+01:00",
              "credential": {"method": "card", "secret": "04B7C2D9E1"}
            },
            {
              "id": "01a318f0-a0c0-7804-a3a6-4d8707f841b2",
              "type": "break_end",
              "occurred_at": "2027-01-15T11:45:10+01:00",
              "credential": {"method": "card", "secret": "04B7C2D9E1"}
            },
            {
              "id": "01a318f0-a0c0-791a-b9db-5935f9c3e239",
              "type": "clock_in",
              "occurred_at": "2027-01-15T11:47:00+01:00",
              "credential": {"method": "pin", "secret": "9999"}
            }
          ]
        }
        """), AttendancePunchBatchResult::fromJson); // 200
    // the client: see /v2/docs/java
    // the call blocks – on Android from a worker thread (Dispatchers.IO)
    AttendancePunchBatchResult attendancePunchBatch = api.post("/restaurants/123/attendance/punches/batch", Json.parse("""
        {
          "items": [
            {
              "id": "01a318f0-a0c0-7659-af30-64e055b22d85",
              "type": "break_start",
              "occurred_at": "2027-01-15T11:30:05+01:00",
              "credential": {"method": "card", "secret": "04B7C2D9E1"}
            },
            {
              "id": "01a318f0-a0c0-7804-a3a6-4d8707f841b2",
              "type": "break_end",
              "occurred_at": "2027-01-15T11:45:10+01:00",
              "credential": {"method": "card", "secret": "04B7C2D9E1"}
            },
            {
              "id": "01a318f0-a0c0-791a-b9db-5935f9c3e239",
              "type": "clock_in",
              "occurred_at": "2027-01-15T11:47:00+01:00",
              "credential": {"method": "pin", "secret": "9999"}
            }
          ]
        }
        """), AttendancePunchBatchResult::fromJson); // 200
    // klient: viz /v2/docs/java
    // volání blokuje – na Androidu z pracovního vlákna (Dispatchers.IO)
    val attendancePunchBatch = api.post("/restaurants/123/attendance/punches/batch", mapOf(
        "items" to listOf(
            mapOf(
                "id" to "01a318f0-a0c0-7659-af30-64e055b22d85",
                "type" to "break_start",
                "occurred_at" to "2027-01-15T11:30:05+01:00",
                "credential" to mapOf("method" to "card", "secret" to "04B7C2D9E1"),
            ),
            mapOf(
                "id" to "01a318f0-a0c0-7804-a3a6-4d8707f841b2",
                "type" to "break_end",
                "occurred_at" to "2027-01-15T11:45:10+01:00",
                "credential" to mapOf("method" to "card", "secret" to "04B7C2D9E1"),
            ),
            mapOf(
                "id" to "01a318f0-a0c0-791a-b9db-5935f9c3e239",
                "type" to "clock_in",
                "occurred_at" to "2027-01-15T11:47:00+01:00",
                "credential" to mapOf("method" to "pin", "secret" to "9999"),
            ),
        ),
    ), AttendancePunchBatchResult::fromJson) // 200
    // the client: see /v2/docs/java
    // the call blocks – on Android from a worker thread (Dispatchers.IO)
    val attendancePunchBatch = api.post("/restaurants/123/attendance/punches/batch", mapOf(
        "items" to listOf(
            mapOf(
                "id" to "01a318f0-a0c0-7659-af30-64e055b22d85",
                "type" to "break_start",
                "occurred_at" to "2027-01-15T11:30:05+01:00",
                "credential" to mapOf("method" to "card", "secret" to "04B7C2D9E1"),
            ),
            mapOf(
                "id" to "01a318f0-a0c0-7804-a3a6-4d8707f841b2",
                "type" to "break_end",
                "occurred_at" to "2027-01-15T11:45:10+01:00",
                "credential" to mapOf("method" to "card", "secret" to "04B7C2D9E1"),
            ),
            mapOf(
                "id" to "01a318f0-a0c0-791a-b9db-5935f9c3e239",
                "type" to "clock_in",
                "occurred_at" to "2027-01-15T11:47:00+01:00",
                "credential" to mapOf("method" to "pin", "secret" to "9999"),
            ),
        ),
    ), AttendancePunchBatchResult::fromJson) // 200
    // klient: viz /v2/docs/csharp
    var attendancePunchBatch = await api.PostAsync<AttendancePunchBatchResult>("/restaurants/123/attendance/punches/batch", new {
        items = new object[] {
            new {
                id = "01a318f0-a0c0-7659-af30-64e055b22d85",
                type = "break_start",
                occurred_at = "2027-01-15T11:30:05+01:00",
                credential = new { method = "card", secret = "04B7C2D9E1" },
            },
            new {
                id = "01a318f0-a0c0-7804-a3a6-4d8707f841b2",
                type = "break_end",
                occurred_at = "2027-01-15T11:45:10+01:00",
                credential = new { method = "card", secret = "04B7C2D9E1" },
            },
            new {
                id = "01a318f0-a0c0-791a-b9db-5935f9c3e239",
                type = "clock_in",
                occurred_at = "2027-01-15T11:47:00+01:00",
                credential = new { method = "pin", secret = "9999" },
            },
        },
    }); // 200
    // the client: see /v2/docs/csharp
    var attendancePunchBatch = await api.PostAsync<AttendancePunchBatchResult>("/restaurants/123/attendance/punches/batch", new {
        items = new object[] {
            new {
                id = "01a318f0-a0c0-7659-af30-64e055b22d85",
                type = "break_start",
                occurred_at = "2027-01-15T11:30:05+01:00",
                credential = new { method = "card", secret = "04B7C2D9E1" },
            },
            new {
                id = "01a318f0-a0c0-7804-a3a6-4d8707f841b2",
                type = "break_end",
                occurred_at = "2027-01-15T11:45:10+01:00",
                credential = new { method = "card", secret = "04B7C2D9E1" },
            },
            new {
                id = "01a318f0-a0c0-791a-b9db-5935f9c3e239",
                type = "clock_in",
                occurred_at = "2027-01-15T11:47:00+01:00",
                credential = new { method = "pin", secret = "9999" },
            },
        },
    }); // 200
    # klient: viz /v2/docs/python
    attendance_punch_batch = api.post('/restaurants/123/attendance/punches/batch', {
        'items': [
            {
                'id': '01a318f0-a0c0-7659-af30-64e055b22d85',
                'type': 'break_start',
                'occurred_at': '2027-01-15T11:30:05+01:00',
                'credential': {'method': 'card', 'secret': '04B7C2D9E1'},
            },
            {
                'id': '01a318f0-a0c0-7804-a3a6-4d8707f841b2',
                'type': 'break_end',
                'occurred_at': '2027-01-15T11:45:10+01:00',
                'credential': {'method': 'card', 'secret': '04B7C2D9E1'},
            },
            {
                'id': '01a318f0-a0c0-791a-b9db-5935f9c3e239',
                'type': 'clock_in',
                'occurred_at': '2027-01-15T11:47:00+01:00',
                'credential': {'method': 'pin', 'secret': '9999'},
            },
        ],
    })  # 200
    # the client: see /v2/docs/python
    attendance_punch_batch = api.post('/restaurants/123/attendance/punches/batch', {
        'items': [
            {
                'id': '01a318f0-a0c0-7659-af30-64e055b22d85',
                'type': 'break_start',
                'occurred_at': '2027-01-15T11:30:05+01:00',
                'credential': {'method': 'card', 'secret': '04B7C2D9E1'},
            },
            {
                'id': '01a318f0-a0c0-7804-a3a6-4d8707f841b2',
                'type': 'break_end',
                'occurred_at': '2027-01-15T11:45:10+01:00',
                'credential': {'method': 'card', 'secret': '04B7C2D9E1'},
            },
            {
                'id': '01a318f0-a0c0-791a-b9db-5935f9c3e239',
                'type': 'clock_in',
                'occurred_at': '2027-01-15T11:47:00+01:00',
                'credential': {'method': 'pin', 'secret': '9999'},
            },
        ],
    })  # 200
    // klient: viz /v2/docs/swift
    let attendancePunchBatch: AttendancePunchBatchResult = try await api.post("/restaurants/123/attendance/punches/batch", body: [
        "items": [
            [
                "id": "01a318f0-a0c0-7659-af30-64e055b22d85",
                "type": "break_start",
                "occurred_at": "2027-01-15T11:30:05+01:00",
                "credential": ["method": "card", "secret": "04B7C2D9E1"],
            ],
            [
                "id": "01a318f0-a0c0-7804-a3a6-4d8707f841b2",
                "type": "break_end",
                "occurred_at": "2027-01-15T11:45:10+01:00",
                "credential": ["method": "card", "secret": "04B7C2D9E1"],
            ],
            [
                "id": "01a318f0-a0c0-791a-b9db-5935f9c3e239",
                "type": "clock_in",
                "occurred_at": "2027-01-15T11:47:00+01:00",
                "credential": ["method": "pin", "secret": "9999"],
            ],
        ],
    ]) // 200
    // the client: see /v2/docs/swift
    let attendancePunchBatch: AttendancePunchBatchResult = try await api.post("/restaurants/123/attendance/punches/batch", body: [
        "items": [
            [
                "id": "01a318f0-a0c0-7659-af30-64e055b22d85",
                "type": "break_start",
                "occurred_at": "2027-01-15T11:30:05+01:00",
                "credential": ["method": "card", "secret": "04B7C2D9E1"],
            ],
            [
                "id": "01a318f0-a0c0-7804-a3a6-4d8707f841b2",
                "type": "break_end",
                "occurred_at": "2027-01-15T11:45:10+01:00",
                "credential": ["method": "card", "secret": "04B7C2D9E1"],
            ],
            [
                "id": "01a318f0-a0c0-791a-b9db-5935f9c3e239",
                "type": "clock_in",
                "occurred_at": "2027-01-15T11:47:00+01:00",
                "credential": ["method": "pin", "secret": "9999"],
            ],
        ],
    ]) // 200
    // klient: viz /v2/docs/dart
    final attendancePunchBatch = pr.AttendancePunchBatchResult.fromJson(await api.post('/restaurants/123/attendance/punches/batch', {
      'items': [
        {
          'id': '01a318f0-a0c0-7659-af30-64e055b22d85',
          'type': 'break_start',
          'occurred_at': '2027-01-15T11:30:05+01:00',
          'credential': {'method': 'card', 'secret': '04B7C2D9E1'},
        },
        {
          'id': '01a318f0-a0c0-7804-a3a6-4d8707f841b2',
          'type': 'break_end',
          'occurred_at': '2027-01-15T11:45:10+01:00',
          'credential': {'method': 'card', 'secret': '04B7C2D9E1'},
        },
        {
          'id': '01a318f0-a0c0-791a-b9db-5935f9c3e239',
          'type': 'clock_in',
          'occurred_at': '2027-01-15T11:47:00+01:00',
          'credential': {'method': 'pin', 'secret': '9999'},
        },
      ],
    })); // 200
    // the client: see /v2/docs/dart
    final attendancePunchBatch = pr.AttendancePunchBatchResult.fromJson(await api.post('/restaurants/123/attendance/punches/batch', {
      'items': [
        {
          'id': '01a318f0-a0c0-7659-af30-64e055b22d85',
          'type': 'break_start',
          'occurred_at': '2027-01-15T11:30:05+01:00',
          'credential': {'method': 'card', 'secret': '04B7C2D9E1'},
        },
        {
          'id': '01a318f0-a0c0-7804-a3a6-4d8707f841b2',
          'type': 'break_end',
          'occurred_at': '2027-01-15T11:45:10+01:00',
          'credential': {'method': 'card', 'secret': '04B7C2D9E1'},
        },
        {
          'id': '01a318f0-a0c0-791a-b9db-5935f9c3e239',
          'type': 'clock_in',
          'occurred_at': '2027-01-15T11:47:00+01:00',
          'credential': {'method': 'pin', 'secret': '9999'},
        },
      ],
    })); // 200
    // klient: viz /v2/docs/go
    res, err := api.Post(ctx, "/restaurants/123/attendance/punches/batch", map[string]any{
    	"items": []any{
    		map[string]any{
    			"id": "01a318f0-a0c0-7659-af30-64e055b22d85",
    			"type": "break_start",
    			"occurred_at": "2027-01-15T11:30:05+01:00",
    			"credential": map[string]any{"method": "card", "secret": "04B7C2D9E1"},
    		},
    		map[string]any{
    			"id": "01a318f0-a0c0-7804-a3a6-4d8707f841b2",
    			"type": "break_end",
    			"occurred_at": "2027-01-15T11:45:10+01:00",
    			"credential": map[string]any{"method": "card", "secret": "04B7C2D9E1"},
    		},
    		map[string]any{
    			"id": "01a318f0-a0c0-791a-b9db-5935f9c3e239",
    			"type": "clock_in",
    			"occurred_at": "2027-01-15T11:47:00+01:00",
    			"credential": map[string]any{"method": "pin", "secret": "9999"},
    		},
    	},
    }, nil)
    var attendancePunchBatch model.AttendancePunchBatchResult // 200
    if err == nil {
    	err = res.Decode(&attendancePunchBatch)
    }
    // the client: see /v2/docs/go
    res, err := api.Post(ctx, "/restaurants/123/attendance/punches/batch", map[string]any{
    	"items": []any{
    		map[string]any{
    			"id": "01a318f0-a0c0-7659-af30-64e055b22d85",
    			"type": "break_start",
    			"occurred_at": "2027-01-15T11:30:05+01:00",
    			"credential": map[string]any{"method": "card", "secret": "04B7C2D9E1"},
    		},
    		map[string]any{
    			"id": "01a318f0-a0c0-7804-a3a6-4d8707f841b2",
    			"type": "break_end",
    			"occurred_at": "2027-01-15T11:45:10+01:00",
    			"credential": map[string]any{"method": "card", "secret": "04B7C2D9E1"},
    		},
    		map[string]any{
    			"id": "01a318f0-a0c0-791a-b9db-5935f9c3e239",
    			"type": "clock_in",
    			"occurred_at": "2027-01-15T11:47:00+01:00",
    			"credential": map[string]any{"method": "pin", "secret": "9999"},
    		},
    	},
    }, nil)
    var attendancePunchBatch model.AttendancePunchBatchResult // 200
    if err == nil {
    	err = res.Decode(&attendancePunchBatch)
    }
    Příklad odpovědi 200Example answer 200
    {
      "results": [
        {
          "id": "01a318f0-a0c0-7659-af30-64e055b22d85",
          "status": "created",
          "retryable": false,
          "punch": {
            "id": "01a318f0-a0c0-7659-af30-64e055b22d85",
            "employee": {
              "id": "66",
              "name": "Lucie Svobodová"
            },
            "type": "break_start",
            "occurred_at": "2027-01-15T11:30:05+01:00",
            "received_at": "2027-01-15T11:52:30+01:00",
            "offline": true,
            "state": "on_break",
            "shift": {
              "started_at": "2027-01-15T08:00:40+01:00",
              "ended_at": null,
              "break_minutes": null,
              "worked_minutes": null
            }
          },
          "problem": null,
          "employee": null
        },
        {
          "id": "01a318f0-a0c0-7804-a3a6-4d8707f841b2",
          "status": "duplicate",
          "retryable": false,
          "punch": {
            "id": "01a318f0-a0c0-7804-a3a6-4d8707f841b2",
            "employee": {
              "id": "66",
              "name": "Lucie Svobodová"
            },
            "type": "break_end",
            "occurred_at": "2027-01-15T11:45:10+01:00",
            "received_at": "2027-01-15T11:52:30+01:00",
            "offline": true,
            "state": "working",
            "shift": {
              "started_at": "2027-01-15T08:00:40+01:00",
              "ended_at": null,
              "break_minutes": 15,
              "worked_minutes": null
            }
          },
          "problem": null,
          "employee": null
        },
        {
          "id": "01a318f0-a0c0-791a-b9db-5935f9c3e239",
          "status": "rejected",
          "retryable": false,
          "punch": null,
          "problem": {
            "type": "https://api.mujprofirest.cz/v2/docs/errors#staff_credentials_invalid",
            "title": "Špatný PIN nebo neznámý čip",
            "status": 422,
            "code": "staff_credentials_invalid",
            "detail": null,
            "instance": null,
            "request_id": "7c9e6679a1f04d3b8e2b5f0a4c1d2e3f",
            "errors": [],
            "existing_id": null,
            "candidates": [],
            "paid_by": null
          },
          "employee": null
        }
      ]
    }

Scénář

Scenario

Rozvoz

Deliveries

Vlastní zařízení ProfirestuProfirest's own device

Kurýr začne směnu, dispečink mu sestaví trasu z hotových objednávek a kurýr hlásí doručení.

A courier starts the shift, the dispatcher builds a route from ready orders and the courier reports the deliveries.

  1. Kurýři

    Couriers

    GET /restaurants/{restaurant_id}/couriers · listCouriers

    Kdo je na směně a kolik má otevřených tras.

    Who is on shift and how many open routes they have.

    curl "https://api.mujprofirest.cz/v2/restaurants/123/couriers" \
      -H "Authorization: Bearer $ACCESS_TOKEN"
    curl "https://api.mujprofirest.cz/v2/restaurants/123/couriers" \
      -H "Authorization: Bearer $ACCESS_TOKEN"
    // klient: viz /v2/docs/js
    const { data, next_cursor } = await api.get('/restaurants/123/couriers'); // 200
    // the client: see /v2/docs/js
    const { data, next_cursor } = await api.get('/restaurants/123/couriers'); // 200
    // klient: viz /v2/docs/typescript
    const { data, next_cursor } = await api.get('/restaurants/123/couriers'); // 200 CourierPage
    // the client: see /v2/docs/typescript
    const { data, next_cursor } = await api.get('/restaurants/123/couriers'); // 200 CourierPage
    // klient: viz /v2/docs/php
    $page = $api->get('/restaurants/123/couriers'); // $page['data'], $page['next_cursor']
    // the client: see /v2/docs/php
    $page = $api->get('/restaurants/123/couriers'); // $page['data'], $page['next_cursor']
    // klient: viz /v2/docs/java
    // volání blokuje – na Androidu z pracovního vlákna (Dispatchers.IO)
    CourierPage listCouriers = api.get("/restaurants/123/couriers", CourierPage::fromJson); // 200
    // the client: see /v2/docs/java
    // the call blocks – on Android from a worker thread (Dispatchers.IO)
    CourierPage listCouriers = api.get("/restaurants/123/couriers", CourierPage::fromJson); // 200
    // klient: viz /v2/docs/java
    // volání blokuje – na Androidu z pracovního vlákna (Dispatchers.IO)
    val listCouriers = api.get("/restaurants/123/couriers", CourierPage::fromJson) // 200
    // the client: see /v2/docs/java
    // the call blocks – on Android from a worker thread (Dispatchers.IO)
    val listCouriers = api.get("/restaurants/123/couriers", CourierPage::fromJson) // 200
    // klient: viz /v2/docs/csharp
    var listCouriers = await api.GetAsync<CourierPage>("/restaurants/123/couriers"); // 200
    // the client: see /v2/docs/csharp
    var listCouriers = await api.GetAsync<CourierPage>("/restaurants/123/couriers"); // 200
    # klient: viz /v2/docs/python
    page = api.get('/restaurants/123/couriers')  # page['data'], page['next_cursor']
    # the client: see /v2/docs/python
    page = api.get('/restaurants/123/couriers')  # page['data'], page['next_cursor']
    // klient: viz /v2/docs/swift
    let listCouriers: CourierPage = try await api.get("/restaurants/123/couriers") // 200
    // the client: see /v2/docs/swift
    let listCouriers: CourierPage = try await api.get("/restaurants/123/couriers") // 200
    // klient: viz /v2/docs/dart
    final listCouriers = pr.CourierPage.fromJson(await api.get('/restaurants/123/couriers')); // 200
    // the client: see /v2/docs/dart
    final listCouriers = pr.CourierPage.fromJson(await api.get('/restaurants/123/couriers')); // 200
    // klient: viz /v2/docs/go
    res, err := api.Get(ctx, "/restaurants/123/couriers", nil)
    var listCouriers model.CourierPage // 200
    if err == nil {
    	err = res.Decode(&listCouriers)
    }
    // the client: see /v2/docs/go
    res, err := api.Get(ctx, "/restaurants/123/couriers", nil)
    var listCouriers model.CourierPage // 200
    if err == nil {
    	err = res.Decode(&listCouriers)
    }
    Příklad odpovědi 200Example answer 200
    {
      "data": [
        {
          "employee": {
            "id": "64",
            "name": "Tomáš Král"
          },
          "on_shift": true,
          "on_shift_since": "2027-01-15T10:30:00+01:00",
          "open_routes": 1
        },
        {
          "employee": {
            "id": "68",
            "name": "Martin Beneš"
          },
          "on_shift": false,
          "on_shift_since": null,
          "open_routes": 0
        }
      ],
      "next_cursor": null
    }
  2. Začátek směny

    Starting the shift

    PUT /restaurants/{restaurant_id}/couriers/{employee_id}/shift · startCourierShift

    Kurýr se přihlásí na zařízení a začne směnu.

    The courier signs in on the device and starts the shift.

    curl -X PUT "https://api.mujprofirest.cz/v2/restaurants/123/couriers/64/shift" \
      -H "Authorization: Bearer $ACCESS_TOKEN" \
      -H "Profirest-Staff-Token: $STAFF_TOKEN"
    curl -X PUT "https://api.mujprofirest.cz/v2/restaurants/123/couriers/64/shift" \
      -H "Authorization: Bearer $ACCESS_TOKEN" \
      -H "Profirest-Staff-Token: $STAFF_TOKEN"
    // klient: viz /v2/docs/js
    // token zaměstnance přidá knihovna sama (po přihlášení zaměstnance)
    const courierShift = await api.put('/restaurants/123/couriers/64/shift', null); // 200
    // the client: see /v2/docs/js
    // the library adds the employee's token itself (after the employee signs in)
    const courierShift = await api.put('/restaurants/123/couriers/64/shift', null); // 200
    // klient: viz /v2/docs/typescript
    // token zaměstnance přidá knihovna sama (po přihlášení zaměstnance)
    const courierShift = await api.put('/restaurants/123/couriers/64/shift', null); // 200 Courier
    // the client: see /v2/docs/typescript
    // the library adds the employee's token itself (after the employee signs in)
    const courierShift = await api.put('/restaurants/123/couriers/64/shift', null); // 200 Courier
    // klient: viz /v2/docs/php
    // token zaměstnance přidá knihovna sama (po přihlášení zaměstnance)
    $courierShift = $api->put('/restaurants/123/couriers/64/shift', null); // 200
    // the client: see /v2/docs/php
    // the library adds the employee's token itself (after the employee signs in)
    $courierShift = $api->put('/restaurants/123/couriers/64/shift', null); // 200
    // klient: viz /v2/docs/java
    // volání blokuje – na Androidu z pracovního vlákna (Dispatchers.IO)
    // token zaměstnance přidá knihovna sama (po přihlášení zaměstnance)
    Courier courierShift = api.put("/restaurants/123/couriers/64/shift", null, Courier::fromJson); // 200
    // the client: see /v2/docs/java
    // the call blocks – on Android from a worker thread (Dispatchers.IO)
    // the library adds the employee's token itself (after the employee signs in)
    Courier courierShift = api.put("/restaurants/123/couriers/64/shift", null, Courier::fromJson); // 200
    // klient: viz /v2/docs/java
    // volání blokuje – na Androidu z pracovního vlákna (Dispatchers.IO)
    // token zaměstnance přidá knihovna sama (po přihlášení zaměstnance)
    val courierShift = api.put("/restaurants/123/couriers/64/shift", null, Courier::fromJson) // 200
    // the client: see /v2/docs/java
    // the call blocks – on Android from a worker thread (Dispatchers.IO)
    // the library adds the employee's token itself (after the employee signs in)
    val courierShift = api.put("/restaurants/123/couriers/64/shift", null, Courier::fromJson) // 200
    // klient: viz /v2/docs/csharp
    // token zaměstnance přidá knihovna sama (po přihlášení zaměstnance)
    var courierShift = await api.PutAsync<Courier>("/restaurants/123/couriers/64/shift", (object?)null); // 200
    // the client: see /v2/docs/csharp
    // the library adds the employee's token itself (after the employee signs in)
    var courierShift = await api.PutAsync<Courier>("/restaurants/123/couriers/64/shift", (object?)null); // 200
    # klient: viz /v2/docs/python
    # token zaměstnance přidá knihovna sama (po přihlášení zaměstnance)
    courier_shift = api.put('/restaurants/123/couriers/64/shift', None)  # 200
    # the client: see /v2/docs/python
    # the library adds the employee's token itself (after the employee signs in)
    courier_shift = api.put('/restaurants/123/couriers/64/shift', None)  # 200
    // klient: viz /v2/docs/swift
    // token zaměstnance přidá knihovna sama (po přihlášení zaměstnance)
    let courierShift: Courier = try await api.put("/restaurants/123/couriers/64/shift", body: nil) // 200
    // the client: see /v2/docs/swift
    // the library adds the employee's token itself (after the employee signs in)
    let courierShift: Courier = try await api.put("/restaurants/123/couriers/64/shift", body: nil) // 200
    // klient: viz /v2/docs/dart
    // token zaměstnance přidá knihovna sama (po přihlášení zaměstnance)
    final courierShift = pr.Courier.fromJson(await api.put('/restaurants/123/couriers/64/shift', null)); // 200
    // the client: see /v2/docs/dart
    // the library adds the employee's token itself (after the employee signs in)
    final courierShift = pr.Courier.fromJson(await api.put('/restaurants/123/couriers/64/shift', null)); // 200
    // klient: viz /v2/docs/go
    // token zaměstnance přidá knihovna sama (po přihlášení zaměstnance)
    res, err := api.Put(ctx, "/restaurants/123/couriers/64/shift", nil, nil)
    var courierShift model.Courier // 200
    if err == nil {
    	err = res.Decode(&courierShift)
    }
    // the client: see /v2/docs/go
    // the library adds the employee's token itself (after the employee signs in)
    res, err := api.Put(ctx, "/restaurants/123/couriers/64/shift", nil, nil)
    var courierShift model.Courier // 200
    if err == nil {
    	err = res.Decode(&courierShift)
    }
    Příklad odpovědi 200Example answer 200
    {
      "employee": {
        "id": "64",
        "name": "Tomáš Král"
      },
      "on_shift": true,
      "on_shift_since": "2027-01-15T10:30:00+01:00",
      "open_routes": 0
    }
  3. Trasa

    A route

    POST /restaurants/{restaurant_id}/delivery-routes · createDeliveryRoute

    Hotové bony k rozvozu pro jednoho kurýra.

    Ready delivery tickets for one courier.

    curl "https://api.mujprofirest.cz/v2/restaurants/123/delivery-routes" \
      -H "Authorization: Bearer $ACCESS_TOKEN" \
      -H "Profirest-Staff-Token: $STAFF_TOKEN" \
      -H "Idempotency-Key: 01a318f0-a0c0-7cc6-882f-c95de1e2352a" \
      -H "Content-Type: application/json" \
      -d '{"courier_id": "64", "ticket_ids": ["77815"]}'
    curl "https://api.mujprofirest.cz/v2/restaurants/123/delivery-routes" \
      -H "Authorization: Bearer $ACCESS_TOKEN" \
      -H "Profirest-Staff-Token: $STAFF_TOKEN" \
      -H "Idempotency-Key: 01a318f0-a0c0-7cc6-882f-c95de1e2352a" \
      -H "Content-Type: application/json" \
      -d '{"courier_id": "64", "ticket_ids": ["77815"]}'
    // klient: viz /v2/docs/js
    // token zaměstnance přidá knihovna sama (po přihlášení zaměstnance)
    const deliveryRoute = await api.post('/restaurants/123/delivery-routes', { courier_id: '64', ticket_ids: ['77815'] }); // 201
    // the client: see /v2/docs/js
    // the library adds the employee's token itself (after the employee signs in)
    const deliveryRoute = await api.post('/restaurants/123/delivery-routes', { courier_id: '64', ticket_ids: ['77815'] }); // 201
    // klient: viz /v2/docs/typescript
    // token zaměstnance přidá knihovna sama (po přihlášení zaměstnance)
    const deliveryRoute = await api.post('/restaurants/123/delivery-routes', { courier_id: '64', ticket_ids: ['77815'] }); // 201 DeliveryRoute
    // the client: see /v2/docs/typescript
    // the library adds the employee's token itself (after the employee signs in)
    const deliveryRoute = await api.post('/restaurants/123/delivery-routes', { courier_id: '64', ticket_ids: ['77815'] }); // 201 DeliveryRoute
    // klient: viz /v2/docs/php
    // token zaměstnance přidá knihovna sama (po přihlášení zaměstnance)
    $deliveryRoute = $api->post('/restaurants/123/delivery-routes', ['courier_id' => '64', 'ticket_ids' => ['77815']]); // 201
    // the client: see /v2/docs/php
    // the library adds the employee's token itself (after the employee signs in)
    $deliveryRoute = $api->post('/restaurants/123/delivery-routes', ['courier_id' => '64', 'ticket_ids' => ['77815']]); // 201
    // klient: viz /v2/docs/java
    // volání blokuje – na Androidu z pracovního vlákna (Dispatchers.IO)
    // token zaměstnance přidá knihovna sama (po přihlášení zaměstnance)
    DeliveryRoute deliveryRoute = api.post("/restaurants/123/delivery-routes", Json.parse("""
        {"courier_id": "64", "ticket_ids": ["77815"]}
        """), DeliveryRoute::fromJson); // 201
    // the client: see /v2/docs/java
    // the call blocks – on Android from a worker thread (Dispatchers.IO)
    // the library adds the employee's token itself (after the employee signs in)
    DeliveryRoute deliveryRoute = api.post("/restaurants/123/delivery-routes", Json.parse("""
        {"courier_id": "64", "ticket_ids": ["77815"]}
        """), DeliveryRoute::fromJson); // 201
    // klient: viz /v2/docs/java
    // volání blokuje – na Androidu z pracovního vlákna (Dispatchers.IO)
    // token zaměstnance přidá knihovna sama (po přihlášení zaměstnance)
    val deliveryRoute = api.post(
        "/restaurants/123/delivery-routes",
        mapOf("courier_id" to "64", "ticket_ids" to listOf("77815")),
        DeliveryRoute::fromJson,
    ) // 201
    // the client: see /v2/docs/java
    // the call blocks – on Android from a worker thread (Dispatchers.IO)
    // the library adds the employee's token itself (after the employee signs in)
    val deliveryRoute = api.post(
        "/restaurants/123/delivery-routes",
        mapOf("courier_id" to "64", "ticket_ids" to listOf("77815")),
        DeliveryRoute::fromJson,
    ) // 201
    // klient: viz /v2/docs/csharp
    // token zaměstnance přidá knihovna sama (po přihlášení zaměstnance)
    var deliveryRoute = await api.PostAsync<DeliveryRoute>(
        "/restaurants/123/delivery-routes",
        new { courier_id = "64", ticket_ids = new[] { "77815" } }
    ); // 201
    // the client: see /v2/docs/csharp
    // the library adds the employee's token itself (after the employee signs in)
    var deliveryRoute = await api.PostAsync<DeliveryRoute>(
        "/restaurants/123/delivery-routes",
        new { courier_id = "64", ticket_ids = new[] { "77815" } }
    ); // 201
    # klient: viz /v2/docs/python
    # token zaměstnance přidá knihovna sama (po přihlášení zaměstnance)
    delivery_route = api.post('/restaurants/123/delivery-routes', {'courier_id': '64', 'ticket_ids': ['77815']})  # 201
    # the client: see /v2/docs/python
    # the library adds the employee's token itself (after the employee signs in)
    delivery_route = api.post('/restaurants/123/delivery-routes', {'courier_id': '64', 'ticket_ids': ['77815']})  # 201
    // klient: viz /v2/docs/swift
    // token zaměstnance přidá knihovna sama (po přihlášení zaměstnance)
    let deliveryRoute: DeliveryRoute = try await api.post("/restaurants/123/delivery-routes", body: ["courier_id": "64", "ticket_ids": ["77815"]]) // 201
    // the client: see /v2/docs/swift
    // the library adds the employee's token itself (after the employee signs in)
    let deliveryRoute: DeliveryRoute = try await api.post("/restaurants/123/delivery-routes", body: ["courier_id": "64", "ticket_ids": ["77815"]]) // 201
    // klient: viz /v2/docs/dart
    // token zaměstnance přidá knihovna sama (po přihlášení zaměstnance)
    final deliveryRoute = pr.DeliveryRoute.fromJson(await api.post('/restaurants/123/delivery-routes', {'courier_id': '64', 'ticket_ids': ['77815']})); // 201
    // the client: see /v2/docs/dart
    // the library adds the employee's token itself (after the employee signs in)
    final deliveryRoute = pr.DeliveryRoute.fromJson(await api.post('/restaurants/123/delivery-routes', {'courier_id': '64', 'ticket_ids': ['77815']})); // 201
    // klient: viz /v2/docs/go
    // token zaměstnance přidá knihovna sama (po přihlášení zaměstnance)
    res, err := api.Post(
    	ctx,
    	"/restaurants/123/delivery-routes",
    	map[string]any{"courier_id": "64", "ticket_ids": []any{"77815"}},
    	nil,
    )
    var deliveryRoute model.DeliveryRoute // 201
    if err == nil {
    	err = res.Decode(&deliveryRoute)
    }
    // the client: see /v2/docs/go
    // the library adds the employee's token itself (after the employee signs in)
    res, err := api.Post(
    	ctx,
    	"/restaurants/123/delivery-routes",
    	map[string]any{"courier_id": "64", "ticket_ids": []any{"77815"}},
    	nil,
    )
    var deliveryRoute model.DeliveryRoute // 201
    if err == nil {
    	err = res.Decode(&deliveryRoute)
    }
    Příklad odpovědi 201Example answer 201
    {
      "id": "3307",
      "courier": {
        "id": "64",
        "name": "Tomáš Král"
      },
      "status": "open",
      "created_at": "2027-01-15T12:06:40+01:00",
      "completed_at": null,
      "tickets": [
        {
          "id": "77815",
          "order_id": "184226",
          "number": "030",
          "status": "out_for_delivery",
          "area": "kitchen",
          "source": "web",
          "platform": null,
          "name": "Jana Nováková",
          "fulfillment": "delivery",
          "express": false,
          "customer": {
            "name": "Jana Nováková",
            "phone": "+420777123456",
            "not_delivered_count": 0,
            "last_not_delivered_at": null
          },
          "delivery_address": {
            "street": "Jeseniova 1196/52",
            "city": "Praha 3",
            "location": {
              "lat": 50.0833,
              "lon": 14.4667
            }
          },
          "delivery_zone": {
            "id": "21",
            "name": "Vinohrady do 3 km"
          },
          "note": "3. patro, zvonek Nováková",
          "payment_method": "cash",
          "total": {
            "amount": 38600,
            "currency": "CZK"
          },
          "delivery_price": {
            "amount": 4900,
            "currency": "CZK"
          },
          "amount_due": {
            "amount": 38600,
            "currency": "CZK"
          },
          "paid_by": null,
          "created_at": "2027-01-15T11:50:40+01:00",
          "scheduled_for": null,
          "printed": true,
          "courier": {
            "id": "64",
            "name": "Tomáš Král"
          },
          "not_delivered": null,
          "items": [
            {
              "id": "52031",
              "product_id": "4571",
              "name": "Pizza Margherita",
              "kitchen_name": null,
              "note": "Nekrájet",
              "quantity": 1,
              "kind": "full",
              "charge": null,
              "course": 0,
              "category": {
                "id": "315",
                "name": "Pizza"
              },
              "from_daily_menu": false,
              "station_id": "3",
              "status": "done",
              "handed_out": false,
              "part": null,
              "size": {
                "name": "Ø32cm",
                "dish_name": "Pizza Margherita"
              },
              "unit_price": {
                "amount": 18900,
                "currency": "CZK"
              },
              "packaging_price": {
                "amount": 0,
                "currency": "CZK"
              },
              "discount": {
                "amount": 0,
                "currency": "CZK"
              },
              "gift": false,
              "vat_rate": "12",
              "removed_ingredients": [],
              "modifiers": [
                {
                  "id": "52032",
                  "charge": null,
                  "product_id": "4602",
                  "name": "Extra sýr",
                  "kitchen_name": null,
                  "note": null,
                  "quantity": 1,
                  "kind": "full",
                  "status": "done",
                  "handed_out": false,
                  "part": null,
                  "size": null,
                  "unit_price": {
                    "amount": 3000,
                    "currency": "CZK"
                  },
                  "packaging_price": {
                    "amount": 0,
                    "currency": "CZK"
                  },
                  "discount": {
                    "amount": 0,
                    "currency": "CZK"
                  },
                  "gift": false,
                  "vat_rate": "12",
                  "removed_ingredients": []
                }
              ]
            },
            {
              "id": "52033",
              "product_id": "4593",
              "name": "Domácí limonáda 0,4 l",
              "kitchen_name": null,
              "note": null,
              "quantity": 2,
              "kind": "full",
              "charge": null,
              "course": 0,
              "category": {
                "id": "320",
                "name": "Nápoje"
              },
              "from_daily_menu": false,
              "station_id": null,
              "status": "done",
              "handed_out": false,
              "part": null,
              "size": null,
              "unit_price": {
                "amount": 5900,
                "currency": "CZK"
              },
              "packaging_price": {
                "amount": 0,
                "currency": "CZK"
              },
              "discount": {
                "amount": 0,
                "currency": "CZK"
              },
              "gift": false,
              "vat_rate": "12",
              "removed_ingredients": [],
              "modifiers": []
            }
          ],
          "receipt": {
            "items": {
              "amount": 33700,
              "currency": "CZK"
            },
            "discounts": [],
            "delivery": {
              "amount": 4900,
              "currency": "CZK"
            },
            "rounding": {
              "amount": 0,
              "currency": "CZK"
            },
            "adjustment": {
              "amount": 0,
              "currency": "CZK"
            },
            "total": {
              "amount": 38600,
              "currency": "CZK"
            },
            "to_pay": {
              "amount": 38600,
              "currency": "CZK"
            },
            "vat": [
              {
                "rate": "12",
                "base": {
                  "amount": 34464,
                  "currency": "CZK"
                },
                "vat": {
                  "amount": 4136,
                  "currency": "CZK"
                },
                "total": {
                  "amount": 38600,
                  "currency": "CZK"
                }
              }
            ],
            "document": {
              "title": "Účtenka",
              "number": "184226",
              "tax_document": "Zjednodušený daňový doklad"
            }
          }
        }
      ]
    }
  4. Doručeno

    Delivered

    POST /restaurants/{restaurant_id}/delivery-routes/{route_id}/tickets/{ticket_id}/delivered · markTicketDelivered

    Po posledním doručení se trasa uzavře sama.

    After the last delivery the route closes itself.

    curl -X POST "https://api.mujprofirest.cz/v2/restaurants/123/delivery-routes/3307/tickets/77815/delivered" \
      -H "Authorization: Bearer $ACCESS_TOKEN" \
      -H "Profirest-Staff-Token: $STAFF_TOKEN" \
      -H "Idempotency-Key: 01a318f0-a0c0-7086-a0c0-a5560bd45149"
    curl -X POST "https://api.mujprofirest.cz/v2/restaurants/123/delivery-routes/3307/tickets/77815/delivered" \
      -H "Authorization: Bearer $ACCESS_TOKEN" \
      -H "Profirest-Staff-Token: $STAFF_TOKEN" \
      -H "Idempotency-Key: 01a318f0-a0c0-7086-a0c0-a5560bd45149"
    // klient: viz /v2/docs/js
    // token zaměstnance přidá knihovna sama (po přihlášení zaměstnance)
    const ticketDelivered = await api.post('/restaurants/123/delivery-routes/3307/tickets/77815/delivered', null); // 200
    // the client: see /v2/docs/js
    // the library adds the employee's token itself (after the employee signs in)
    const ticketDelivered = await api.post('/restaurants/123/delivery-routes/3307/tickets/77815/delivered', null); // 200
    // klient: viz /v2/docs/typescript
    // token zaměstnance přidá knihovna sama (po přihlášení zaměstnance)
    const ticketDelivered = await api.post('/restaurants/123/delivery-routes/3307/tickets/77815/delivered', null); // 200 DeliveryRoute
    // the client: see /v2/docs/typescript
    // the library adds the employee's token itself (after the employee signs in)
    const ticketDelivered = await api.post('/restaurants/123/delivery-routes/3307/tickets/77815/delivered', null); // 200 DeliveryRoute
    // klient: viz /v2/docs/php
    // token zaměstnance přidá knihovna sama (po přihlášení zaměstnance)
    $ticketDelivered = $api->post('/restaurants/123/delivery-routes/3307/tickets/77815/delivered', null); // 200
    // the client: see /v2/docs/php
    // the library adds the employee's token itself (after the employee signs in)
    $ticketDelivered = $api->post('/restaurants/123/delivery-routes/3307/tickets/77815/delivered', null); // 200
    // klient: viz /v2/docs/java
    // volání blokuje – na Androidu z pracovního vlákna (Dispatchers.IO)
    // token zaměstnance přidá knihovna sama (po přihlášení zaměstnance)
    DeliveryRoute ticketDelivered = api.post(
        "/restaurants/123/delivery-routes/3307/tickets/77815/delivered",
        null,
        DeliveryRoute::fromJson
    ); // 200
    // the client: see /v2/docs/java
    // the call blocks – on Android from a worker thread (Dispatchers.IO)
    // the library adds the employee's token itself (after the employee signs in)
    DeliveryRoute ticketDelivered = api.post(
        "/restaurants/123/delivery-routes/3307/tickets/77815/delivered",
        null,
        DeliveryRoute::fromJson
    ); // 200
    // klient: viz /v2/docs/java
    // volání blokuje – na Androidu z pracovního vlákna (Dispatchers.IO)
    // token zaměstnance přidá knihovna sama (po přihlášení zaměstnance)
    val ticketDelivered = api.post(
        "/restaurants/123/delivery-routes/3307/tickets/77815/delivered",
        null,
        DeliveryRoute::fromJson,
    ) // 200
    // the client: see /v2/docs/java
    // the call blocks – on Android from a worker thread (Dispatchers.IO)
    // the library adds the employee's token itself (after the employee signs in)
    val ticketDelivered = api.post(
        "/restaurants/123/delivery-routes/3307/tickets/77815/delivered",
        null,
        DeliveryRoute::fromJson,
    ) // 200
    // klient: viz /v2/docs/csharp
    // token zaměstnance přidá knihovna sama (po přihlášení zaměstnance)
    var ticketDelivered = await api.PostAsync<DeliveryRoute>(
        "/restaurants/123/delivery-routes/3307/tickets/77815/delivered",
        (object?)null
    ); // 200
    // the client: see /v2/docs/csharp
    // the library adds the employee's token itself (after the employee signs in)
    var ticketDelivered = await api.PostAsync<DeliveryRoute>(
        "/restaurants/123/delivery-routes/3307/tickets/77815/delivered",
        (object?)null
    ); // 200
    # klient: viz /v2/docs/python
    # token zaměstnance přidá knihovna sama (po přihlášení zaměstnance)
    ticket_delivered = api.post('/restaurants/123/delivery-routes/3307/tickets/77815/delivered', None)  # 200
    # the client: see /v2/docs/python
    # the library adds the employee's token itself (after the employee signs in)
    ticket_delivered = api.post('/restaurants/123/delivery-routes/3307/tickets/77815/delivered', None)  # 200
    // klient: viz /v2/docs/swift
    // token zaměstnance přidá knihovna sama (po přihlášení zaměstnance)
    let ticketDelivered: DeliveryRoute = try await api.post("/restaurants/123/delivery-routes/3307/tickets/77815/delivered", body: nil) // 200
    // the client: see /v2/docs/swift
    // the library adds the employee's token itself (after the employee signs in)
    let ticketDelivered: DeliveryRoute = try await api.post("/restaurants/123/delivery-routes/3307/tickets/77815/delivered", body: nil) // 200
    // klient: viz /v2/docs/dart
    // token zaměstnance přidá knihovna sama (po přihlášení zaměstnance)
    final ticketDelivered = pr.DeliveryRoute.fromJson(await api.post('/restaurants/123/delivery-routes/3307/tickets/77815/delivered', null)); // 200
    // the client: see /v2/docs/dart
    // the library adds the employee's token itself (after the employee signs in)
    final ticketDelivered = pr.DeliveryRoute.fromJson(await api.post('/restaurants/123/delivery-routes/3307/tickets/77815/delivered', null)); // 200
    // klient: viz /v2/docs/go
    // token zaměstnance přidá knihovna sama (po přihlášení zaměstnance)
    res, err := api.Post(ctx, "/restaurants/123/delivery-routes/3307/tickets/77815/delivered", nil, nil)
    var ticketDelivered model.DeliveryRoute // 200
    if err == nil {
    	err = res.Decode(&ticketDelivered)
    }
    // the client: see /v2/docs/go
    // the library adds the employee's token itself (after the employee signs in)
    res, err := api.Post(ctx, "/restaurants/123/delivery-routes/3307/tickets/77815/delivered", nil, nil)
    var ticketDelivered model.DeliveryRoute // 200
    if err == nil {
    	err = res.Decode(&ticketDelivered)
    }
    Příklad odpovědi 200Example answer 200
    {
      "id": "3307",
      "courier": {
        "id": "64",
        "name": "Tomáš Král"
      },
      "status": "completed",
      "created_at": "2027-01-15T12:06:40+01:00",
      "completed_at": "2027-01-15T12:31:10+01:00",
      "tickets": [
        {
          "id": "77815",
          "order_id": "184226",
          "number": "030",
          "status": "delivered",
          "area": "kitchen",
          "source": "web",
          "platform": null,
          "name": "Jana Nováková",
          "fulfillment": "delivery",
          "express": false,
          "customer": {
            "name": "Jana Nováková",
            "phone": "+420777123456",
            "not_delivered_count": 0,
            "last_not_delivered_at": null
          },
          "delivery_address": {
            "street": "Jeseniova 1196/52",
            "city": "Praha 3",
            "location": {
              "lat": 50.0833,
              "lon": 14.4667
            }
          },
          "delivery_zone": {
            "id": "21",
            "name": "Vinohrady do 3 km"
          },
          "note": "3. patro, zvonek Nováková",
          "payment_method": "cash",
          "total": {
            "amount": 38600,
            "currency": "CZK"
          },
          "delivery_price": {
            "amount": 4900,
            "currency": "CZK"
          },
          "amount_due": {
            "amount": 38600,
            "currency": "CZK"
          },
          "paid_by": null,
          "created_at": "2027-01-15T11:50:40+01:00",
          "scheduled_for": null,
          "printed": true,
          "courier": {
            "id": "64",
            "name": "Tomáš Král"
          },
          "not_delivered": null,
          "items": [
            {
              "id": "52031",
              "product_id": "4571",
              "name": "Pizza Margherita",
              "kitchen_name": null,
              "note": "Nekrájet",
              "quantity": 1,
              "kind": "full",
              "charge": null,
              "course": 0,
              "category": {
                "id": "315",
                "name": "Pizza"
              },
              "from_daily_menu": false,
              "station_id": "3",
              "status": "done",
              "handed_out": false,
              "part": null,
              "size": {
                "name": "Ø32cm",
                "dish_name": "Pizza Margherita"
              },
              "unit_price": {
                "amount": 18900,
                "currency": "CZK"
              },
              "packaging_price": {
                "amount": 0,
                "currency": "CZK"
              },
              "discount": {
                "amount": 0,
                "currency": "CZK"
              },
              "gift": false,
              "vat_rate": "12",
              "removed_ingredients": [],
              "modifiers": [
                {
                  "id": "52032",
                  "charge": null,
                  "product_id": "4602",
                  "name": "Extra sýr",
                  "kitchen_name": null,
                  "note": null,
                  "quantity": 1,
                  "kind": "full",
                  "status": "done",
                  "handed_out": false,
                  "part": null,
                  "size": null,
                  "unit_price": {
                    "amount": 3000,
                    "currency": "CZK"
                  },
                  "packaging_price": {
                    "amount": 0,
                    "currency": "CZK"
                  },
                  "discount": {
                    "amount": 0,
                    "currency": "CZK"
                  },
                  "gift": false,
                  "vat_rate": "12",
                  "removed_ingredients": []
                }
              ]
            },
            {
              "id": "52033",
              "product_id": "4593",
              "name": "Domácí limonáda 0,4 l",
              "kitchen_name": null,
              "note": null,
              "quantity": 2,
              "kind": "full",
              "charge": null,
              "course": 0,
              "category": {
                "id": "320",
                "name": "Nápoje"
              },
              "from_daily_menu": false,
              "station_id": null,
              "status": "done",
              "handed_out": false,
              "part": null,
              "size": null,
              "unit_price": {
                "amount": 5900,
                "currency": "CZK"
              },
              "packaging_price": {
                "amount": 0,
                "currency": "CZK"
              },
              "discount": {
                "amount": 0,
                "currency": "CZK"
              },
              "gift": false,
              "vat_rate": "12",
              "removed_ingredients": [],
              "modifiers": []
            }
          ],
          "receipt": {
            "items": {
              "amount": 33700,
              "currency": "CZK"
            },
            "discounts": [],
            "delivery": {
              "amount": 4900,
              "currency": "CZK"
            },
            "rounding": {
              "amount": 0,
              "currency": "CZK"
            },
            "adjustment": {
              "amount": 0,
              "currency": "CZK"
            },
            "total": {
              "amount": 38600,
              "currency": "CZK"
            },
            "to_pay": {
              "amount": 38600,
              "currency": "CZK"
            },
            "vat": [
              {
                "rate": "12",
                "base": {
                  "amount": 34464,
                  "currency": "CZK"
                },
                "vat": {
                  "amount": 4136,
                  "currency": "CZK"
                },
                "total": {
                  "amount": 38600,
                  "currency": "CZK"
                }
              }
            ],
            "document": {
              "title": "Účtenka",
              "number": "184226",
              "tax_document": "Zjednodušený daňový doklad"
            }
          }
        }
      ]
    }
  5. Konec směny

    Ending the shift

    DELETE /restaurants/{restaurant_id}/couriers/{employee_id}/shift · endCourierShift

    Tržby kurýra ukáže uzávěrka kuchyně.

    The kitchen closing shows the courier's takings.

    curl -X DELETE "https://api.mujprofirest.cz/v2/restaurants/123/couriers/64/shift" \
      -H "Authorization: Bearer $ACCESS_TOKEN" \
      -H "Profirest-Staff-Token: $STAFF_TOKEN"
    curl -X DELETE "https://api.mujprofirest.cz/v2/restaurants/123/couriers/64/shift" \
      -H "Authorization: Bearer $ACCESS_TOKEN" \
      -H "Profirest-Staff-Token: $STAFF_TOKEN"
    // klient: viz /v2/docs/js
    // token zaměstnance přidá knihovna sama (po přihlášení zaměstnance)
    await api.delete('/restaurants/123/couriers/64/shift');
    // the client: see /v2/docs/js
    // the library adds the employee's token itself (after the employee signs in)
    await api.delete('/restaurants/123/couriers/64/shift');
    // klient: viz /v2/docs/typescript
    // token zaměstnance přidá knihovna sama (po přihlášení zaměstnance)
    await api.delete('/restaurants/123/couriers/64/shift');
    // the client: see /v2/docs/typescript
    // the library adds the employee's token itself (after the employee signs in)
    await api.delete('/restaurants/123/couriers/64/shift');
    // klient: viz /v2/docs/php
    // token zaměstnance přidá knihovna sama (po přihlášení zaměstnance)
    $api->delete('/restaurants/123/couriers/64/shift');
    // the client: see /v2/docs/php
    // the library adds the employee's token itself (after the employee signs in)
    $api->delete('/restaurants/123/couriers/64/shift');
    // klient: viz /v2/docs/java
    // volání blokuje – na Androidu z pracovního vlákna (Dispatchers.IO)
    // token zaměstnance přidá knihovna sama (po přihlášení zaměstnance)
    api.delete("/restaurants/123/couriers/64/shift");
    // the client: see /v2/docs/java
    // the call blocks – on Android from a worker thread (Dispatchers.IO)
    // the library adds the employee's token itself (after the employee signs in)
    api.delete("/restaurants/123/couriers/64/shift");
    // klient: viz /v2/docs/java
    // volání blokuje – na Androidu z pracovního vlákna (Dispatchers.IO)
    // token zaměstnance přidá knihovna sama (po přihlášení zaměstnance)
    api.delete("/restaurants/123/couriers/64/shift")
    // the client: see /v2/docs/java
    // the call blocks – on Android from a worker thread (Dispatchers.IO)
    // the library adds the employee's token itself (after the employee signs in)
    api.delete("/restaurants/123/couriers/64/shift")
    // klient: viz /v2/docs/csharp
    // token zaměstnance přidá knihovna sama (po přihlášení zaměstnance)
    await api.DeleteAsync("/restaurants/123/couriers/64/shift");
    // the client: see /v2/docs/csharp
    // the library adds the employee's token itself (after the employee signs in)
    await api.DeleteAsync("/restaurants/123/couriers/64/shift");
    # klient: viz /v2/docs/python
    # token zaměstnance přidá knihovna sama (po přihlášení zaměstnance)
    api.delete('/restaurants/123/couriers/64/shift')
    # the client: see /v2/docs/python
    # the library adds the employee's token itself (after the employee signs in)
    api.delete('/restaurants/123/couriers/64/shift')
    // klient: viz /v2/docs/swift
    // token zaměstnance přidá knihovna sama (po přihlášení zaměstnance)
    try await api.delete("/restaurants/123/couriers/64/shift")
    // the client: see /v2/docs/swift
    // the library adds the employee's token itself (after the employee signs in)
    try await api.delete("/restaurants/123/couriers/64/shift")
    // klient: viz /v2/docs/dart
    // token zaměstnance přidá knihovna sama (po přihlášení zaměstnance)
    await api.delete('/restaurants/123/couriers/64/shift');
    // the client: see /v2/docs/dart
    // the library adds the employee's token itself (after the employee signs in)
    await api.delete('/restaurants/123/couriers/64/shift');
    // klient: viz /v2/docs/go
    // token zaměstnance přidá knihovna sama (po přihlášení zaměstnance)
    _, err := api.Delete(ctx, "/restaurants/123/couriers/64/shift", nil)
    // the client: see /v2/docs/go
    // the library adds the employee's token itself (after the employee signs in)
    _, err := api.Delete(ctx, "/restaurants/123/couriers/64/shift", nil)

Scénář

Scenario

Stav, chyby a logy zařízení

State, errors and logs of a device

Vlastní zařízení ProfirestuProfirest's own device

Zařízení si log drží u sebe (černá skříňka, 14 dní). Serveru každou minutu přihlásí stav, chyby pošle hned, a celý log nahraje jen na vyžádání – podpora nebo provozovna o něj požádá v administraci a soubory dorazí do pár minut.

The device keeps its log on itself (a black box, 14 days). It checks its state in with the server every minute, reports errors at once and uploads the whole log only when asked – support or the restaurant asks in the administration and the files arrive within minutes.

  1. Každou minutu přihlaste stav

    Check the state in every minute

    POST /restaurants/{restaurant_id}/device-checkin · checkInDevice

    Verze, síť, fronty čekající na odeslání, poslední záloha, připojené telefony číšníků (peers) a volná počítadla. Odpověď nese commands; výsledky příkazů hlaste v dalším check-inu. Když příkaz čeká, nese každá odpověď API hlavičku Profirest-Commands: pending – přihlaste stav hned.

    Versions, network, the queues waiting to be sent, the last backup, the waiters' phones connected to the register (peers) and free counters. The answer carries commands; report their results in the next check-in. While a command waits, every answer of the API carries the header Profirest-Commands: pending – check in at once.

    curl "https://api.mujprofirest.cz/v2/restaurants/123/device-checkin" \
      -H "Authorization: Bearer $ACCESS_TOKEN" \
      -H "Content-Type: application/json" \
      -d '{
      "role": "register",
      "app_version": "26.10.3",
      "os_version": "Android 13",
      "device_model": "Sunmi T2s",
      "sent_at": "2027-01-15T12:01:00+01:00",
      "uptime_seconds": 41820,
      "battery": {"percent": 100, "charging": true},
      "network": {"type": "wifi", "ip": "192.168.1.57", "signal_dbm": -58},
      "queues": {
        "receipts": {"count": 0, "oldest_at": null},
        "payments": {"count": 1, "oldest_at": "2027-01-15T11:58:40+01:00"},
        "print_jobs": {"count": 0, "oldest_at": null}
      },
      "last_backup_at": "2027-01-15T03:00:12+01:00",
      "last_sync_at": "2027-01-15T12:00:48+01:00",
      "log_store": {
        "segments": 2016,
        "bytes": 22806528,
        "oldest_at": "2027-01-01T12:00:00+01:00",
        "errors_today": 1
      },
      "counters": {"polls": 3312, "broadcasts": 148, "errors": 1, "socket_reconnects": 2},
      "peers": [
        {
          "key": "9bb5f040",
          "name": "Jana",
          "role": "waiter",
          "app_version": "26.10.3",
          "connected": true,
          "last_seen_at": "2027-01-15T12:00:58+01:00",
          "log_store": true
        },
        {
          "key": "c17d02aa",
          "name": "Petr",
          "role": "waiter",
          "app_version": "26.10.3",
          "connected": false,
          "last_seen_at": "2027-01-15T11:20:03+01:00",
          "log_store": true
        }
      ],
      "command_results": [{"command_id": "c-5d10b9", "status": "done", "message": null}]
    }'
    curl "https://api.mujprofirest.cz/v2/restaurants/123/device-checkin" \
      -H "Authorization: Bearer $ACCESS_TOKEN" \
      -H "Content-Type: application/json" \
      -d '{
      "role": "register",
      "app_version": "26.10.3",
      "os_version": "Android 13",
      "device_model": "Sunmi T2s",
      "sent_at": "2027-01-15T12:01:00+01:00",
      "uptime_seconds": 41820,
      "battery": {"percent": 100, "charging": true},
      "network": {"type": "wifi", "ip": "192.168.1.57", "signal_dbm": -58},
      "queues": {
        "receipts": {"count": 0, "oldest_at": null},
        "payments": {"count": 1, "oldest_at": "2027-01-15T11:58:40+01:00"},
        "print_jobs": {"count": 0, "oldest_at": null}
      },
      "last_backup_at": "2027-01-15T03:00:12+01:00",
      "last_sync_at": "2027-01-15T12:00:48+01:00",
      "log_store": {
        "segments": 2016,
        "bytes": 22806528,
        "oldest_at": "2027-01-01T12:00:00+01:00",
        "errors_today": 1
      },
      "counters": {"polls": 3312, "broadcasts": 148, "errors": 1, "socket_reconnects": 2},
      "peers": [
        {
          "key": "9bb5f040",
          "name": "Jana",
          "role": "waiter",
          "app_version": "26.10.3",
          "connected": true,
          "last_seen_at": "2027-01-15T12:00:58+01:00",
          "log_store": true
        },
        {
          "key": "c17d02aa",
          "name": "Petr",
          "role": "waiter",
          "app_version": "26.10.3",
          "connected": false,
          "last_seen_at": "2027-01-15T11:20:03+01:00",
          "log_store": true
        }
      ],
      "command_results": [{"command_id": "c-5d10b9", "status": "done", "message": null}]
    }'
    // klient: viz /v2/docs/js
    const inDevice = await api.post('/restaurants/123/device-checkin', {
      role: 'register',
      app_version: '26.10.3',
      os_version: 'Android 13',
      device_model: 'Sunmi T2s',
      sent_at: '2027-01-15T12:01:00+01:00',
      uptime_seconds: 41820,
      battery: { percent: 100, charging: true },
      network: { type: 'wifi', ip: '192.168.1.57', signal_dbm: -58 },
      queues: {
        receipts: { count: 0, oldest_at: null },
        payments: { count: 1, oldest_at: '2027-01-15T11:58:40+01:00' },
        print_jobs: { count: 0, oldest_at: null },
      },
      last_backup_at: '2027-01-15T03:00:12+01:00',
      last_sync_at: '2027-01-15T12:00:48+01:00',
      log_store: {
        segments: 2016,
        bytes: 22806528,
        oldest_at: '2027-01-01T12:00:00+01:00',
        errors_today: 1,
      },
      counters: { polls: 3312, broadcasts: 148, errors: 1, socket_reconnects: 2 },
      peers: [
        {
          key: '9bb5f040',
          name: 'Jana',
          role: 'waiter',
          app_version: '26.10.3',
          connected: true,
          last_seen_at: '2027-01-15T12:00:58+01:00',
          log_store: true,
        },
        {
          key: 'c17d02aa',
          name: 'Petr',
          role: 'waiter',
          app_version: '26.10.3',
          connected: false,
          last_seen_at: '2027-01-15T11:20:03+01:00',
          log_store: true,
        },
      ],
      command_results: [{ command_id: 'c-5d10b9', status: 'done', message: null }],
    }); // 200
    // the client: see /v2/docs/js
    const inDevice = await api.post('/restaurants/123/device-checkin', {
      role: 'register',
      app_version: '26.10.3',
      os_version: 'Android 13',
      device_model: 'Sunmi T2s',
      sent_at: '2027-01-15T12:01:00+01:00',
      uptime_seconds: 41820,
      battery: { percent: 100, charging: true },
      network: { type: 'wifi', ip: '192.168.1.57', signal_dbm: -58 },
      queues: {
        receipts: { count: 0, oldest_at: null },
        payments: { count: 1, oldest_at: '2027-01-15T11:58:40+01:00' },
        print_jobs: { count: 0, oldest_at: null },
      },
      last_backup_at: '2027-01-15T03:00:12+01:00',
      last_sync_at: '2027-01-15T12:00:48+01:00',
      log_store: {
        segments: 2016,
        bytes: 22806528,
        oldest_at: '2027-01-01T12:00:00+01:00',
        errors_today: 1,
      },
      counters: { polls: 3312, broadcasts: 148, errors: 1, socket_reconnects: 2 },
      peers: [
        {
          key: '9bb5f040',
          name: 'Jana',
          role: 'waiter',
          app_version: '26.10.3',
          connected: true,
          last_seen_at: '2027-01-15T12:00:58+01:00',
          log_store: true,
        },
        {
          key: 'c17d02aa',
          name: 'Petr',
          role: 'waiter',
          app_version: '26.10.3',
          connected: false,
          last_seen_at: '2027-01-15T11:20:03+01:00',
          log_store: true,
        },
      ],
      command_results: [{ command_id: 'c-5d10b9', status: 'done', message: null }],
    }); // 200
    // klient: viz /v2/docs/typescript
    const inDevice = await api.post('/restaurants/123/device-checkin', {
      role: 'register',
      app_version: '26.10.3',
      os_version: 'Android 13',
      device_model: 'Sunmi T2s',
      sent_at: '2027-01-15T12:01:00+01:00',
      uptime_seconds: 41820,
      battery: { percent: 100, charging: true },
      network: { type: 'wifi', ip: '192.168.1.57', signal_dbm: -58 },
      queues: {
        receipts: { count: 0, oldest_at: null },
        payments: { count: 1, oldest_at: '2027-01-15T11:58:40+01:00' },
        print_jobs: { count: 0, oldest_at: null },
      },
      last_backup_at: '2027-01-15T03:00:12+01:00',
      last_sync_at: '2027-01-15T12:00:48+01:00',
      log_store: {
        segments: 2016,
        bytes: 22806528,
        oldest_at: '2027-01-01T12:00:00+01:00',
        errors_today: 1,
      },
      counters: { polls: 3312, broadcasts: 148, errors: 1, socket_reconnects: 2 },
      peers: [
        {
          key: '9bb5f040',
          name: 'Jana',
          role: 'waiter',
          app_version: '26.10.3',
          connected: true,
          last_seen_at: '2027-01-15T12:00:58+01:00',
          log_store: true,
        },
        {
          key: 'c17d02aa',
          name: 'Petr',
          role: 'waiter',
          app_version: '26.10.3',
          connected: false,
          last_seen_at: '2027-01-15T11:20:03+01:00',
          log_store: true,
        },
      ],
      command_results: [{ command_id: 'c-5d10b9', status: 'done', message: null }],
    }); // 200 DeviceCheckInResult
    // the client: see /v2/docs/typescript
    const inDevice = await api.post('/restaurants/123/device-checkin', {
      role: 'register',
      app_version: '26.10.3',
      os_version: 'Android 13',
      device_model: 'Sunmi T2s',
      sent_at: '2027-01-15T12:01:00+01:00',
      uptime_seconds: 41820,
      battery: { percent: 100, charging: true },
      network: { type: 'wifi', ip: '192.168.1.57', signal_dbm: -58 },
      queues: {
        receipts: { count: 0, oldest_at: null },
        payments: { count: 1, oldest_at: '2027-01-15T11:58:40+01:00' },
        print_jobs: { count: 0, oldest_at: null },
      },
      last_backup_at: '2027-01-15T03:00:12+01:00',
      last_sync_at: '2027-01-15T12:00:48+01:00',
      log_store: {
        segments: 2016,
        bytes: 22806528,
        oldest_at: '2027-01-01T12:00:00+01:00',
        errors_today: 1,
      },
      counters: { polls: 3312, broadcasts: 148, errors: 1, socket_reconnects: 2 },
      peers: [
        {
          key: '9bb5f040',
          name: 'Jana',
          role: 'waiter',
          app_version: '26.10.3',
          connected: true,
          last_seen_at: '2027-01-15T12:00:58+01:00',
          log_store: true,
        },
        {
          key: 'c17d02aa',
          name: 'Petr',
          role: 'waiter',
          app_version: '26.10.3',
          connected: false,
          last_seen_at: '2027-01-15T11:20:03+01:00',
          log_store: true,
        },
      ],
      command_results: [{ command_id: 'c-5d10b9', status: 'done', message: null }],
    }); // 200 DeviceCheckInResult
    // klient: viz /v2/docs/php
    $inDevice = $api->post('/restaurants/123/device-checkin', [
        'role' => 'register',
        'app_version' => '26.10.3',
        'os_version' => 'Android 13',
        'device_model' => 'Sunmi T2s',
        'sent_at' => '2027-01-15T12:01:00+01:00',
        'uptime_seconds' => 41820,
        'battery' => ['percent' => 100, 'charging' => true],
        'network' => ['type' => 'wifi', 'ip' => '192.168.1.57', 'signal_dbm' => -58],
        'queues' => [
            'receipts' => ['count' => 0, 'oldest_at' => null],
            'payments' => ['count' => 1, 'oldest_at' => '2027-01-15T11:58:40+01:00'],
            'print_jobs' => ['count' => 0, 'oldest_at' => null],
        ],
        'last_backup_at' => '2027-01-15T03:00:12+01:00',
        'last_sync_at' => '2027-01-15T12:00:48+01:00',
        'log_store' => [
            'segments' => 2016,
            'bytes' => 22806528,
            'oldest_at' => '2027-01-01T12:00:00+01:00',
            'errors_today' => 1,
        ],
        'counters' => ['polls' => 3312, 'broadcasts' => 148, 'errors' => 1, 'socket_reconnects' => 2],
        'peers' => [
            [
                'key' => '9bb5f040',
                'name' => 'Jana',
                'role' => 'waiter',
                'app_version' => '26.10.3',
                'connected' => true,
                'last_seen_at' => '2027-01-15T12:00:58+01:00',
                'log_store' => true,
            ],
            [
                'key' => 'c17d02aa',
                'name' => 'Petr',
                'role' => 'waiter',
                'app_version' => '26.10.3',
                'connected' => false,
                'last_seen_at' => '2027-01-15T11:20:03+01:00',
                'log_store' => true,
            ],
        ],
        'command_results' => [['command_id' => 'c-5d10b9', 'status' => 'done', 'message' => null]],
    ]); // 200
    // the client: see /v2/docs/php
    $inDevice = $api->post('/restaurants/123/device-checkin', [
        'role' => 'register',
        'app_version' => '26.10.3',
        'os_version' => 'Android 13',
        'device_model' => 'Sunmi T2s',
        'sent_at' => '2027-01-15T12:01:00+01:00',
        'uptime_seconds' => 41820,
        'battery' => ['percent' => 100, 'charging' => true],
        'network' => ['type' => 'wifi', 'ip' => '192.168.1.57', 'signal_dbm' => -58],
        'queues' => [
            'receipts' => ['count' => 0, 'oldest_at' => null],
            'payments' => ['count' => 1, 'oldest_at' => '2027-01-15T11:58:40+01:00'],
            'print_jobs' => ['count' => 0, 'oldest_at' => null],
        ],
        'last_backup_at' => '2027-01-15T03:00:12+01:00',
        'last_sync_at' => '2027-01-15T12:00:48+01:00',
        'log_store' => [
            'segments' => 2016,
            'bytes' => 22806528,
            'oldest_at' => '2027-01-01T12:00:00+01:00',
            'errors_today' => 1,
        ],
        'counters' => ['polls' => 3312, 'broadcasts' => 148, 'errors' => 1, 'socket_reconnects' => 2],
        'peers' => [
            [
                'key' => '9bb5f040',
                'name' => 'Jana',
                'role' => 'waiter',
                'app_version' => '26.10.3',
                'connected' => true,
                'last_seen_at' => '2027-01-15T12:00:58+01:00',
                'log_store' => true,
            ],
            [
                'key' => 'c17d02aa',
                'name' => 'Petr',
                'role' => 'waiter',
                'app_version' => '26.10.3',
                'connected' => false,
                'last_seen_at' => '2027-01-15T11:20:03+01:00',
                'log_store' => true,
            ],
        ],
        'command_results' => [['command_id' => 'c-5d10b9', 'status' => 'done', 'message' => null]],
    ]); // 200
    // klient: viz /v2/docs/java
    // volání blokuje – na Androidu z pracovního vlákna (Dispatchers.IO)
    DeviceCheckInResult inDevice = api.post("/restaurants/123/device-checkin", Json.parse("""
        {
          "role": "register",
          "app_version": "26.10.3",
          "os_version": "Android 13",
          "device_model": "Sunmi T2s",
          "sent_at": "2027-01-15T12:01:00+01:00",
          "uptime_seconds": 41820,
          "battery": {"percent": 100, "charging": true},
          "network": {"type": "wifi", "ip": "192.168.1.57", "signal_dbm": -58},
          "queues": {
            "receipts": {"count": 0, "oldest_at": null},
            "payments": {"count": 1, "oldest_at": "2027-01-15T11:58:40+01:00"},
            "print_jobs": {"count": 0, "oldest_at": null}
          },
          "last_backup_at": "2027-01-15T03:00:12+01:00",
          "last_sync_at": "2027-01-15T12:00:48+01:00",
          "log_store": {
            "segments": 2016,
            "bytes": 22806528,
            "oldest_at": "2027-01-01T12:00:00+01:00",
            "errors_today": 1
          },
          "counters": {"polls": 3312, "broadcasts": 148, "errors": 1, "socket_reconnects": 2},
          "peers": [
            {
              "key": "9bb5f040",
              "name": "Jana",
              "role": "waiter",
              "app_version": "26.10.3",
              "connected": true,
              "last_seen_at": "2027-01-15T12:00:58+01:00",
              "log_store": true
            },
            {
              "key": "c17d02aa",
              "name": "Petr",
              "role": "waiter",
              "app_version": "26.10.3",
              "connected": false,
              "last_seen_at": "2027-01-15T11:20:03+01:00",
              "log_store": true
            }
          ],
          "command_results": [{"command_id": "c-5d10b9", "status": "done", "message": null}]
        }
        """), DeviceCheckInResult::fromJson); // 200
    // the client: see /v2/docs/java
    // the call blocks – on Android from a worker thread (Dispatchers.IO)
    DeviceCheckInResult inDevice = api.post("/restaurants/123/device-checkin", Json.parse("""
        {
          "role": "register",
          "app_version": "26.10.3",
          "os_version": "Android 13",
          "device_model": "Sunmi T2s",
          "sent_at": "2027-01-15T12:01:00+01:00",
          "uptime_seconds": 41820,
          "battery": {"percent": 100, "charging": true},
          "network": {"type": "wifi", "ip": "192.168.1.57", "signal_dbm": -58},
          "queues": {
            "receipts": {"count": 0, "oldest_at": null},
            "payments": {"count": 1, "oldest_at": "2027-01-15T11:58:40+01:00"},
            "print_jobs": {"count": 0, "oldest_at": null}
          },
          "last_backup_at": "2027-01-15T03:00:12+01:00",
          "last_sync_at": "2027-01-15T12:00:48+01:00",
          "log_store": {
            "segments": 2016,
            "bytes": 22806528,
            "oldest_at": "2027-01-01T12:00:00+01:00",
            "errors_today": 1
          },
          "counters": {"polls": 3312, "broadcasts": 148, "errors": 1, "socket_reconnects": 2},
          "peers": [
            {
              "key": "9bb5f040",
              "name": "Jana",
              "role": "waiter",
              "app_version": "26.10.3",
              "connected": true,
              "last_seen_at": "2027-01-15T12:00:58+01:00",
              "log_store": true
            },
            {
              "key": "c17d02aa",
              "name": "Petr",
              "role": "waiter",
              "app_version": "26.10.3",
              "connected": false,
              "last_seen_at": "2027-01-15T11:20:03+01:00",
              "log_store": true
            }
          ],
          "command_results": [{"command_id": "c-5d10b9", "status": "done", "message": null}]
        }
        """), DeviceCheckInResult::fromJson); // 200
    // klient: viz /v2/docs/java
    // volání blokuje – na Androidu z pracovního vlákna (Dispatchers.IO)
    val inDevice = api.post("/restaurants/123/device-checkin", mapOf(
        "role" to "register",
        "app_version" to "26.10.3",
        "os_version" to "Android 13",
        "device_model" to "Sunmi T2s",
        "sent_at" to "2027-01-15T12:01:00+01:00",
        "uptime_seconds" to 41820,
        "battery" to mapOf("percent" to 100, "charging" to true),
        "network" to mapOf("type" to "wifi", "ip" to "192.168.1.57", "signal_dbm" to -58),
        "queues" to mapOf(
            "receipts" to mapOf("count" to 0, "oldest_at" to null),
            "payments" to mapOf("count" to 1, "oldest_at" to "2027-01-15T11:58:40+01:00"),
            "print_jobs" to mapOf("count" to 0, "oldest_at" to null),
        ),
        "last_backup_at" to "2027-01-15T03:00:12+01:00",
        "last_sync_at" to "2027-01-15T12:00:48+01:00",
        "log_store" to mapOf(
            "segments" to 2016,
            "bytes" to 22806528,
            "oldest_at" to "2027-01-01T12:00:00+01:00",
            "errors_today" to 1,
        ),
        "counters" to mapOf("polls" to 3312, "broadcasts" to 148, "errors" to 1, "socket_reconnects" to 2),
        "peers" to listOf(
            mapOf(
                "key" to "9bb5f040",
                "name" to "Jana",
                "role" to "waiter",
                "app_version" to "26.10.3",
                "connected" to true,
                "last_seen_at" to "2027-01-15T12:00:58+01:00",
                "log_store" to true,
            ),
            mapOf(
                "key" to "c17d02aa",
                "name" to "Petr",
                "role" to "waiter",
                "app_version" to "26.10.3",
                "connected" to false,
                "last_seen_at" to "2027-01-15T11:20:03+01:00",
                "log_store" to true,
            ),
        ),
        "command_results" to listOf(mapOf("command_id" to "c-5d10b9", "status" to "done", "message" to null)),
    ), DeviceCheckInResult::fromJson) // 200
    // the client: see /v2/docs/java
    // the call blocks – on Android from a worker thread (Dispatchers.IO)
    val inDevice = api.post("/restaurants/123/device-checkin", mapOf(
        "role" to "register",
        "app_version" to "26.10.3",
        "os_version" to "Android 13",
        "device_model" to "Sunmi T2s",
        "sent_at" to "2027-01-15T12:01:00+01:00",
        "uptime_seconds" to 41820,
        "battery" to mapOf("percent" to 100, "charging" to true),
        "network" to mapOf("type" to "wifi", "ip" to "192.168.1.57", "signal_dbm" to -58),
        "queues" to mapOf(
            "receipts" to mapOf("count" to 0, "oldest_at" to null),
            "payments" to mapOf("count" to 1, "oldest_at" to "2027-01-15T11:58:40+01:00"),
            "print_jobs" to mapOf("count" to 0, "oldest_at" to null),
        ),
        "last_backup_at" to "2027-01-15T03:00:12+01:00",
        "last_sync_at" to "2027-01-15T12:00:48+01:00",
        "log_store" to mapOf(
            "segments" to 2016,
            "bytes" to 22806528,
            "oldest_at" to "2027-01-01T12:00:00+01:00",
            "errors_today" to 1,
        ),
        "counters" to mapOf("polls" to 3312, "broadcasts" to 148, "errors" to 1, "socket_reconnects" to 2),
        "peers" to listOf(
            mapOf(
                "key" to "9bb5f040",
                "name" to "Jana",
                "role" to "waiter",
                "app_version" to "26.10.3",
                "connected" to true,
                "last_seen_at" to "2027-01-15T12:00:58+01:00",
                "log_store" to true,
            ),
            mapOf(
                "key" to "c17d02aa",
                "name" to "Petr",
                "role" to "waiter",
                "app_version" to "26.10.3",
                "connected" to false,
                "last_seen_at" to "2027-01-15T11:20:03+01:00",
                "log_store" to true,
            ),
        ),
        "command_results" to listOf(mapOf("command_id" to "c-5d10b9", "status" to "done", "message" to null)),
    ), DeviceCheckInResult::fromJson) // 200
    // klient: viz /v2/docs/csharp
    var inDevice = await api.PostAsync<DeviceCheckInResult>("/restaurants/123/device-checkin", new {
        role = "register",
        app_version = "26.10.3",
        os_version = "Android 13",
        device_model = "Sunmi T2s",
        sent_at = "2027-01-15T12:01:00+01:00",
        uptime_seconds = 41820,
        battery = new { percent = 100, charging = true },
        network = new { type = "wifi", ip = "192.168.1.57", signal_dbm = -58 },
        queues = new {
            receipts = new { count = 0, oldest_at = (object?)null },
            payments = new { count = 1, oldest_at = "2027-01-15T11:58:40+01:00" },
            print_jobs = new { count = 0, oldest_at = (object?)null },
        },
        last_backup_at = "2027-01-15T03:00:12+01:00",
        last_sync_at = "2027-01-15T12:00:48+01:00",
        log_store = new {
            segments = 2016,
            bytes = 22806528,
            oldest_at = "2027-01-01T12:00:00+01:00",
            errors_today = 1,
        },
        counters = new { polls = 3312, broadcasts = 148, errors = 1, socket_reconnects = 2 },
        peers = new object[] {
            new {
                key = "9bb5f040",
                name = "Jana",
                role = "waiter",
                app_version = "26.10.3",
                connected = true,
                last_seen_at = "2027-01-15T12:00:58+01:00",
                log_store = true,
            },
            new {
                key = "c17d02aa",
                name = "Petr",
                role = "waiter",
                app_version = "26.10.3",
                connected = false,
                last_seen_at = "2027-01-15T11:20:03+01:00",
                log_store = true,
            },
        },
        command_results = new object[] {
            new { command_id = "c-5d10b9", status = "done", message = (object?)null },
        },
    }); // 200
    // the client: see /v2/docs/csharp
    var inDevice = await api.PostAsync<DeviceCheckInResult>("/restaurants/123/device-checkin", new {
        role = "register",
        app_version = "26.10.3",
        os_version = "Android 13",
        device_model = "Sunmi T2s",
        sent_at = "2027-01-15T12:01:00+01:00",
        uptime_seconds = 41820,
        battery = new { percent = 100, charging = true },
        network = new { type = "wifi", ip = "192.168.1.57", signal_dbm = -58 },
        queues = new {
            receipts = new { count = 0, oldest_at = (object?)null },
            payments = new { count = 1, oldest_at = "2027-01-15T11:58:40+01:00" },
            print_jobs = new { count = 0, oldest_at = (object?)null },
        },
        last_backup_at = "2027-01-15T03:00:12+01:00",
        last_sync_at = "2027-01-15T12:00:48+01:00",
        log_store = new {
            segments = 2016,
            bytes = 22806528,
            oldest_at = "2027-01-01T12:00:00+01:00",
            errors_today = 1,
        },
        counters = new { polls = 3312, broadcasts = 148, errors = 1, socket_reconnects = 2 },
        peers = new object[] {
            new {
                key = "9bb5f040",
                name = "Jana",
                role = "waiter",
                app_version = "26.10.3",
                connected = true,
                last_seen_at = "2027-01-15T12:00:58+01:00",
                log_store = true,
            },
            new {
                key = "c17d02aa",
                name = "Petr",
                role = "waiter",
                app_version = "26.10.3",
                connected = false,
                last_seen_at = "2027-01-15T11:20:03+01:00",
                log_store = true,
            },
        },
        command_results = new object[] {
            new { command_id = "c-5d10b9", status = "done", message = (object?)null },
        },
    }); // 200
    # klient: viz /v2/docs/python
    in_device = api.post('/restaurants/123/device-checkin', {
        'role': 'register',
        'app_version': '26.10.3',
        'os_version': 'Android 13',
        'device_model': 'Sunmi T2s',
        'sent_at': '2027-01-15T12:01:00+01:00',
        'uptime_seconds': 41820,
        'battery': {'percent': 100, 'charging': True},
        'network': {'type': 'wifi', 'ip': '192.168.1.57', 'signal_dbm': -58},
        'queues': {
            'receipts': {'count': 0, 'oldest_at': None},
            'payments': {'count': 1, 'oldest_at': '2027-01-15T11:58:40+01:00'},
            'print_jobs': {'count': 0, 'oldest_at': None},
        },
        'last_backup_at': '2027-01-15T03:00:12+01:00',
        'last_sync_at': '2027-01-15T12:00:48+01:00',
        'log_store': {
            'segments': 2016,
            'bytes': 22806528,
            'oldest_at': '2027-01-01T12:00:00+01:00',
            'errors_today': 1,
        },
        'counters': {'polls': 3312, 'broadcasts': 148, 'errors': 1, 'socket_reconnects': 2},
        'peers': [
            {
                'key': '9bb5f040',
                'name': 'Jana',
                'role': 'waiter',
                'app_version': '26.10.3',
                'connected': True,
                'last_seen_at': '2027-01-15T12:00:58+01:00',
                'log_store': True,
            },
            {
                'key': 'c17d02aa',
                'name': 'Petr',
                'role': 'waiter',
                'app_version': '26.10.3',
                'connected': False,
                'last_seen_at': '2027-01-15T11:20:03+01:00',
                'log_store': True,
            },
        ],
        'command_results': [{'command_id': 'c-5d10b9', 'status': 'done', 'message': None}],
    })  # 200
    # the client: see /v2/docs/python
    in_device = api.post('/restaurants/123/device-checkin', {
        'role': 'register',
        'app_version': '26.10.3',
        'os_version': 'Android 13',
        'device_model': 'Sunmi T2s',
        'sent_at': '2027-01-15T12:01:00+01:00',
        'uptime_seconds': 41820,
        'battery': {'percent': 100, 'charging': True},
        'network': {'type': 'wifi', 'ip': '192.168.1.57', 'signal_dbm': -58},
        'queues': {
            'receipts': {'count': 0, 'oldest_at': None},
            'payments': {'count': 1, 'oldest_at': '2027-01-15T11:58:40+01:00'},
            'print_jobs': {'count': 0, 'oldest_at': None},
        },
        'last_backup_at': '2027-01-15T03:00:12+01:00',
        'last_sync_at': '2027-01-15T12:00:48+01:00',
        'log_store': {
            'segments': 2016,
            'bytes': 22806528,
            'oldest_at': '2027-01-01T12:00:00+01:00',
            'errors_today': 1,
        },
        'counters': {'polls': 3312, 'broadcasts': 148, 'errors': 1, 'socket_reconnects': 2},
        'peers': [
            {
                'key': '9bb5f040',
                'name': 'Jana',
                'role': 'waiter',
                'app_version': '26.10.3',
                'connected': True,
                'last_seen_at': '2027-01-15T12:00:58+01:00',
                'log_store': True,
            },
            {
                'key': 'c17d02aa',
                'name': 'Petr',
                'role': 'waiter',
                'app_version': '26.10.3',
                'connected': False,
                'last_seen_at': '2027-01-15T11:20:03+01:00',
                'log_store': True,
            },
        ],
        'command_results': [{'command_id': 'c-5d10b9', 'status': 'done', 'message': None}],
    })  # 200
    // klient: viz /v2/docs/swift
    let inDevice: DeviceCheckInResult = try await api.post("/restaurants/123/device-checkin", body: [
        "role": "register",
        "app_version": "26.10.3",
        "os_version": "Android 13",
        "device_model": "Sunmi T2s",
        "sent_at": "2027-01-15T12:01:00+01:00",
        "uptime_seconds": 41820,
        "battery": ["percent": 100, "charging": true],
        "network": ["type": "wifi", "ip": "192.168.1.57", "signal_dbm": -58],
        "queues": [
            "receipts": ["count": 0, "oldest_at": nil],
            "payments": ["count": 1, "oldest_at": "2027-01-15T11:58:40+01:00"],
            "print_jobs": ["count": 0, "oldest_at": nil],
        ],
        "last_backup_at": "2027-01-15T03:00:12+01:00",
        "last_sync_at": "2027-01-15T12:00:48+01:00",
        "log_store": [
            "segments": 2016,
            "bytes": 22806528,
            "oldest_at": "2027-01-01T12:00:00+01:00",
            "errors_today": 1,
        ],
        "counters": ["polls": 3312, "broadcasts": 148, "errors": 1, "socket_reconnects": 2],
        "peers": [
            [
                "key": "9bb5f040",
                "name": "Jana",
                "role": "waiter",
                "app_version": "26.10.3",
                "connected": true,
                "last_seen_at": "2027-01-15T12:00:58+01:00",
                "log_store": true,
            ],
            [
                "key": "c17d02aa",
                "name": "Petr",
                "role": "waiter",
                "app_version": "26.10.3",
                "connected": false,
                "last_seen_at": "2027-01-15T11:20:03+01:00",
                "log_store": true,
            ],
        ],
        "command_results": [["command_id": "c-5d10b9", "status": "done", "message": nil]],
    ]) // 200
    // the client: see /v2/docs/swift
    let inDevice: DeviceCheckInResult = try await api.post("/restaurants/123/device-checkin", body: [
        "role": "register",
        "app_version": "26.10.3",
        "os_version": "Android 13",
        "device_model": "Sunmi T2s",
        "sent_at": "2027-01-15T12:01:00+01:00",
        "uptime_seconds": 41820,
        "battery": ["percent": 100, "charging": true],
        "network": ["type": "wifi", "ip": "192.168.1.57", "signal_dbm": -58],
        "queues": [
            "receipts": ["count": 0, "oldest_at": nil],
            "payments": ["count": 1, "oldest_at": "2027-01-15T11:58:40+01:00"],
            "print_jobs": ["count": 0, "oldest_at": nil],
        ],
        "last_backup_at": "2027-01-15T03:00:12+01:00",
        "last_sync_at": "2027-01-15T12:00:48+01:00",
        "log_store": [
            "segments": 2016,
            "bytes": 22806528,
            "oldest_at": "2027-01-01T12:00:00+01:00",
            "errors_today": 1,
        ],
        "counters": ["polls": 3312, "broadcasts": 148, "errors": 1, "socket_reconnects": 2],
        "peers": [
            [
                "key": "9bb5f040",
                "name": "Jana",
                "role": "waiter",
                "app_version": "26.10.3",
                "connected": true,
                "last_seen_at": "2027-01-15T12:00:58+01:00",
                "log_store": true,
            ],
            [
                "key": "c17d02aa",
                "name": "Petr",
                "role": "waiter",
                "app_version": "26.10.3",
                "connected": false,
                "last_seen_at": "2027-01-15T11:20:03+01:00",
                "log_store": true,
            ],
        ],
        "command_results": [["command_id": "c-5d10b9", "status": "done", "message": nil]],
    ]) // 200
    // klient: viz /v2/docs/dart
    final inDevice = pr.DeviceCheckInResult.fromJson(await api.post('/restaurants/123/device-checkin', {
      'role': 'register',
      'app_version': '26.10.3',
      'os_version': 'Android 13',
      'device_model': 'Sunmi T2s',
      'sent_at': '2027-01-15T12:01:00+01:00',
      'uptime_seconds': 41820,
      'battery': {'percent': 100, 'charging': true},
      'network': {'type': 'wifi', 'ip': '192.168.1.57', 'signal_dbm': -58},
      'queues': {
        'receipts': {'count': 0, 'oldest_at': null},
        'payments': {'count': 1, 'oldest_at': '2027-01-15T11:58:40+01:00'},
        'print_jobs': {'count': 0, 'oldest_at': null},
      },
      'last_backup_at': '2027-01-15T03:00:12+01:00',
      'last_sync_at': '2027-01-15T12:00:48+01:00',
      'log_store': {
        'segments': 2016,
        'bytes': 22806528,
        'oldest_at': '2027-01-01T12:00:00+01:00',
        'errors_today': 1,
      },
      'counters': {'polls': 3312, 'broadcasts': 148, 'errors': 1, 'socket_reconnects': 2},
      'peers': [
        {
          'key': '9bb5f040',
          'name': 'Jana',
          'role': 'waiter',
          'app_version': '26.10.3',
          'connected': true,
          'last_seen_at': '2027-01-15T12:00:58+01:00',
          'log_store': true,
        },
        {
          'key': 'c17d02aa',
          'name': 'Petr',
          'role': 'waiter',
          'app_version': '26.10.3',
          'connected': false,
          'last_seen_at': '2027-01-15T11:20:03+01:00',
          'log_store': true,
        },
      ],
      'command_results': [{'command_id': 'c-5d10b9', 'status': 'done', 'message': null}],
    })); // 200
    // the client: see /v2/docs/dart
    final inDevice = pr.DeviceCheckInResult.fromJson(await api.post('/restaurants/123/device-checkin', {
      'role': 'register',
      'app_version': '26.10.3',
      'os_version': 'Android 13',
      'device_model': 'Sunmi T2s',
      'sent_at': '2027-01-15T12:01:00+01:00',
      'uptime_seconds': 41820,
      'battery': {'percent': 100, 'charging': true},
      'network': {'type': 'wifi', 'ip': '192.168.1.57', 'signal_dbm': -58},
      'queues': {
        'receipts': {'count': 0, 'oldest_at': null},
        'payments': {'count': 1, 'oldest_at': '2027-01-15T11:58:40+01:00'},
        'print_jobs': {'count': 0, 'oldest_at': null},
      },
      'last_backup_at': '2027-01-15T03:00:12+01:00',
      'last_sync_at': '2027-01-15T12:00:48+01:00',
      'log_store': {
        'segments': 2016,
        'bytes': 22806528,
        'oldest_at': '2027-01-01T12:00:00+01:00',
        'errors_today': 1,
      },
      'counters': {'polls': 3312, 'broadcasts': 148, 'errors': 1, 'socket_reconnects': 2},
      'peers': [
        {
          'key': '9bb5f040',
          'name': 'Jana',
          'role': 'waiter',
          'app_version': '26.10.3',
          'connected': true,
          'last_seen_at': '2027-01-15T12:00:58+01:00',
          'log_store': true,
        },
        {
          'key': 'c17d02aa',
          'name': 'Petr',
          'role': 'waiter',
          'app_version': '26.10.3',
          'connected': false,
          'last_seen_at': '2027-01-15T11:20:03+01:00',
          'log_store': true,
        },
      ],
      'command_results': [{'command_id': 'c-5d10b9', 'status': 'done', 'message': null}],
    })); // 200
    // klient: viz /v2/docs/go
    res, err := api.Post(ctx, "/restaurants/123/device-checkin", map[string]any{
    	"role": "register",
    	"app_version": "26.10.3",
    	"os_version": "Android 13",
    	"device_model": "Sunmi T2s",
    	"sent_at": "2027-01-15T12:01:00+01:00",
    	"uptime_seconds": 41820,
    	"battery": map[string]any{"percent": 100, "charging": true},
    	"network": map[string]any{"type": "wifi", "ip": "192.168.1.57", "signal_dbm": -58},
    	"queues": map[string]any{
    		"receipts": map[string]any{"count": 0, "oldest_at": nil},
    		"payments": map[string]any{"count": 1, "oldest_at": "2027-01-15T11:58:40+01:00"},
    		"print_jobs": map[string]any{"count": 0, "oldest_at": nil},
    	},
    	"last_backup_at": "2027-01-15T03:00:12+01:00",
    	"last_sync_at": "2027-01-15T12:00:48+01:00",
    	"log_store": map[string]any{
    		"segments": 2016,
    		"bytes": 22806528,
    		"oldest_at": "2027-01-01T12:00:00+01:00",
    		"errors_today": 1,
    	},
    	"counters": map[string]any{"polls": 3312, "broadcasts": 148, "errors": 1, "socket_reconnects": 2},
    	"peers": []any{
    		map[string]any{
    			"key": "9bb5f040",
    			"name": "Jana",
    			"role": "waiter",
    			"app_version": "26.10.3",
    			"connected": true,
    			"last_seen_at": "2027-01-15T12:00:58+01:00",
    			"log_store": true,
    		},
    		map[string]any{
    			"key": "c17d02aa",
    			"name": "Petr",
    			"role": "waiter",
    			"app_version": "26.10.3",
    			"connected": false,
    			"last_seen_at": "2027-01-15T11:20:03+01:00",
    			"log_store": true,
    		},
    	},
    	"command_results": []any{map[string]any{"command_id": "c-5d10b9", "status": "done", "message": nil}},
    }, nil)
    var inDevice model.DeviceCheckInResult // 200
    if err == nil {
    	err = res.Decode(&inDevice)
    }
    // the client: see /v2/docs/go
    res, err := api.Post(ctx, "/restaurants/123/device-checkin", map[string]any{
    	"role": "register",
    	"app_version": "26.10.3",
    	"os_version": "Android 13",
    	"device_model": "Sunmi T2s",
    	"sent_at": "2027-01-15T12:01:00+01:00",
    	"uptime_seconds": 41820,
    	"battery": map[string]any{"percent": 100, "charging": true},
    	"network": map[string]any{"type": "wifi", "ip": "192.168.1.57", "signal_dbm": -58},
    	"queues": map[string]any{
    		"receipts": map[string]any{"count": 0, "oldest_at": nil},
    		"payments": map[string]any{"count": 1, "oldest_at": "2027-01-15T11:58:40+01:00"},
    		"print_jobs": map[string]any{"count": 0, "oldest_at": nil},
    	},
    	"last_backup_at": "2027-01-15T03:00:12+01:00",
    	"last_sync_at": "2027-01-15T12:00:48+01:00",
    	"log_store": map[string]any{
    		"segments": 2016,
    		"bytes": 22806528,
    		"oldest_at": "2027-01-01T12:00:00+01:00",
    		"errors_today": 1,
    	},
    	"counters": map[string]any{"polls": 3312, "broadcasts": 148, "errors": 1, "socket_reconnects": 2},
    	"peers": []any{
    		map[string]any{
    			"key": "9bb5f040",
    			"name": "Jana",
    			"role": "waiter",
    			"app_version": "26.10.3",
    			"connected": true,
    			"last_seen_at": "2027-01-15T12:00:58+01:00",
    			"log_store": true,
    		},
    		map[string]any{
    			"key": "c17d02aa",
    			"name": "Petr",
    			"role": "waiter",
    			"app_version": "26.10.3",
    			"connected": false,
    			"last_seen_at": "2027-01-15T11:20:03+01:00",
    			"log_store": true,
    		},
    	},
    	"command_results": []any{map[string]any{"command_id": "c-5d10b9", "status": "done", "message": nil}},
    }, nil)
    var inDevice model.DeviceCheckInResult // 200
    if err == nil {
    	err = res.Decode(&inDevice)
    }
    Příklad odpovědi 200Example answer 200
    {
      "server_time": "2027-01-15T12:01:00+01:00",
      "api_target": {
        "target": "v2",
        "base_url": "https://api.mujprofirest.cz/v2"
      },
      "next_in_seconds": 60,
      "commands": [
        {
          "id": "c-8f2c1a",
          "type": "upload_logs",
          "created_at": "2027-01-15T12:00:35+01:00",
          "expires_at": "2027-01-16T12:00:35+01:00",
          "upload_logs": {
            "request_id": "3105",
            "reason": "karta stržena, stůl 11",
            "from": "2027-01-14T12:00:00+01:00",
            "to": "2027-01-15T12:00:00+01:00",
            "detail": "full",
            "uploads": [
              {
                "upload_id": "7742",
                "peer_key": null,
                "token": "pfl_6Y0Bl8pbgLgDKJGhWSHjW3CGQWKaO2bukl9Z2gxAUPA",
                "upload_url": "https://api.mujprofirest.cz/v2/log-uploads/7742",
                "max_part_bytes": 4194304,
                "expires_at": "2027-01-16T12:00:35+01:00"
              },
              {
                "upload_id": "7743",
                "peer_key": "9bb5f040",
                "token": "pfl_kUeD_3Y4izx2yb8cvfgBkOe-ZP05gv7dvaNvonfEzvg",
                "upload_url": "https://api.mujprofirest.cz/v2/log-uploads/7743",
                "max_part_bytes": 4194304,
                "expires_at": "2027-01-16T12:00:35+01:00"
              }
            ]
          },
          "live_logs": null
        }
      ]
    }
  2. Chybu pošlete hned

    Report an error at once

    POST /restaurants/{restaurant_id}/device-errors · reportDeviceError

    S ~30 řádky logu před ní a s ID, která v tu chvíli platila (směna, účet, platba, požadavek) – stejná ID na kase i u číšníka skládají příběh. Tajemství maskujte před odesláním. Nejvýš 60 za hodinu.

    With ~30 log lines before it and the IDs valid at the time (shift, tab, payment, request) – the same IDs on the register and the waiter's phone tell the story. Mask secrets before sending. At most 60 an hour.

    curl "https://api.mujprofirest.cz/v2/restaurants/123/device-errors" \
      -H "Authorization: Bearer $ACCESS_TOKEN" \
      -H "Content-Type: application/json" \
      -d '{
      "id": "01a318f0-a0c0-7b57-8364-1e6fc225f5ce",
      "occurred_at": "2027-01-15T11:56:17+01:00",
      "level": "error",
      "code": "SOCK.timeout",
      "area": "SOCK",
      "event": "req.timeout",
      "message": "Pay bez odpovědi 20 s (b7e1)",
      "peer_key": "9bb5f040",
      "employee_name": "Jana",
      "app_version": "26.10.3",
      "refs": {
        "session": "s-3f9a",
        "tab": "o-7c21",
        "payment": "p-8f2c",
        "request": "b7e1",
        "broadcast": null
      },
      "context": [
        "{\"t\":\"11:55:36.920\",\"seq\":48200,\"l\":\"I\",\"a\":\"UI\",\"e\":\"tap\",\"sess\":\"s-3f9a\",\"ord\":\"o-7c21\",\"intent\":\"PayCard\",\"sum\":25000}",
        "{\"t\":\"11:55:57.703\",\"seq\":48204,\"l\":\"I\",\"a\":\"PAY\",\"e\":\"terminal.ok\",\"pay\":\"p-8f2c\",\"auth\":\"1dc15286\",\"pan\":\"****4821\",\"ms\":20742}",
        "{\"t\":\"11:55:57.750\",\"seq\":48206,\"l\":\"I\",\"a\":\"SOCK\",\"e\":\"req.send\",\"ord\":\"o-7c21\",\"pay\":\"p-8f2c\",\"rid\":\"b7e1\",\"op\":\"Pay\",\"kb\":1.9}",
        "{\"t\":\"11:56:16.004\",\"seq\":48208,\"l\":\"I\",\"a\":\"ENV\",\"e\":\"net.change\",\"from\":\"wifi\",\"to\":\"lte\",\"ip\":\"10.21.4.88\"}"
      ],
      "stack": null
    }'
    curl "https://api.mujprofirest.cz/v2/restaurants/123/device-errors" \
      -H "Authorization: Bearer $ACCESS_TOKEN" \
      -H "Content-Type: application/json" \
      -d '{
      "id": "01a318f0-a0c0-7b57-8364-1e6fc225f5ce",
      "occurred_at": "2027-01-15T11:56:17+01:00",
      "level": "error",
      "code": "SOCK.timeout",
      "area": "SOCK",
      "event": "req.timeout",
      "message": "Pay bez odpovědi 20 s (b7e1)",
      "peer_key": "9bb5f040",
      "employee_name": "Jana",
      "app_version": "26.10.3",
      "refs": {
        "session": "s-3f9a",
        "tab": "o-7c21",
        "payment": "p-8f2c",
        "request": "b7e1",
        "broadcast": null
      },
      "context": [
        "{\"t\":\"11:55:36.920\",\"seq\":48200,\"l\":\"I\",\"a\":\"UI\",\"e\":\"tap\",\"sess\":\"s-3f9a\",\"ord\":\"o-7c21\",\"intent\":\"PayCard\",\"sum\":25000}",
        "{\"t\":\"11:55:57.703\",\"seq\":48204,\"l\":\"I\",\"a\":\"PAY\",\"e\":\"terminal.ok\",\"pay\":\"p-8f2c\",\"auth\":\"1dc15286\",\"pan\":\"****4821\",\"ms\":20742}",
        "{\"t\":\"11:55:57.750\",\"seq\":48206,\"l\":\"I\",\"a\":\"SOCK\",\"e\":\"req.send\",\"ord\":\"o-7c21\",\"pay\":\"p-8f2c\",\"rid\":\"b7e1\",\"op\":\"Pay\",\"kb\":1.9}",
        "{\"t\":\"11:56:16.004\",\"seq\":48208,\"l\":\"I\",\"a\":\"ENV\",\"e\":\"net.change\",\"from\":\"wifi\",\"to\":\"lte\",\"ip\":\"10.21.4.88\"}"
      ],
      "stack": null
    }'
    // klient: viz /v2/docs/js
    const deviceError = await api.post('/restaurants/123/device-errors', {
      id: '01a318f0-a0c0-7b57-8364-1e6fc225f5ce',
      occurred_at: '2027-01-15T11:56:17+01:00',
      level: 'error',
      code: 'SOCK.timeout',
      area: 'SOCK',
      event: 'req.timeout',
      message: 'Pay bez odpovědi 20 s (b7e1)',
      peer_key: '9bb5f040',
      employee_name: 'Jana',
      app_version: '26.10.3',
      refs: {
        session: 's-3f9a',
        tab: 'o-7c21',
        payment: 'p-8f2c',
        request: 'b7e1',
        broadcast: null,
      },
      context: [
        '{"t":"11:55:36.920","seq":48200,"l":"I","a":"UI","e":"tap","sess":"s-3f9a","ord":"o-7c21","intent":"PayCard","sum":25000}',
        '{"t":"11:55:57.703","seq":48204,"l":"I","a":"PAY","e":"terminal.ok","pay":"p-8f2c","auth":"1dc15286","pan":"****4821","ms":20742}',
        '{"t":"11:55:57.750","seq":48206,"l":"I","a":"SOCK","e":"req.send","ord":"o-7c21","pay":"p-8f2c","rid":"b7e1","op":"Pay","kb":1.9}',
        '{"t":"11:56:16.004","seq":48208,"l":"I","a":"ENV","e":"net.change","from":"wifi","to":"lte","ip":"10.21.4.88"}',
      ],
      stack: null,
    }); // 201
    // the client: see /v2/docs/js
    const deviceError = await api.post('/restaurants/123/device-errors', {
      id: '01a318f0-a0c0-7b57-8364-1e6fc225f5ce',
      occurred_at: '2027-01-15T11:56:17+01:00',
      level: 'error',
      code: 'SOCK.timeout',
      area: 'SOCK',
      event: 'req.timeout',
      message: 'Pay bez odpovědi 20 s (b7e1)',
      peer_key: '9bb5f040',
      employee_name: 'Jana',
      app_version: '26.10.3',
      refs: {
        session: 's-3f9a',
        tab: 'o-7c21',
        payment: 'p-8f2c',
        request: 'b7e1',
        broadcast: null,
      },
      context: [
        '{"t":"11:55:36.920","seq":48200,"l":"I","a":"UI","e":"tap","sess":"s-3f9a","ord":"o-7c21","intent":"PayCard","sum":25000}',
        '{"t":"11:55:57.703","seq":48204,"l":"I","a":"PAY","e":"terminal.ok","pay":"p-8f2c","auth":"1dc15286","pan":"****4821","ms":20742}',
        '{"t":"11:55:57.750","seq":48206,"l":"I","a":"SOCK","e":"req.send","ord":"o-7c21","pay":"p-8f2c","rid":"b7e1","op":"Pay","kb":1.9}',
        '{"t":"11:56:16.004","seq":48208,"l":"I","a":"ENV","e":"net.change","from":"wifi","to":"lte","ip":"10.21.4.88"}',
      ],
      stack: null,
    }); // 201
    // klient: viz /v2/docs/typescript
    const deviceError = await api.post('/restaurants/123/device-errors', {
      id: '01a318f0-a0c0-7b57-8364-1e6fc225f5ce',
      occurred_at: '2027-01-15T11:56:17+01:00',
      level: 'error',
      code: 'SOCK.timeout',
      area: 'SOCK',
      event: 'req.timeout',
      message: 'Pay bez odpovědi 20 s (b7e1)',
      peer_key: '9bb5f040',
      employee_name: 'Jana',
      app_version: '26.10.3',
      refs: {
        session: 's-3f9a',
        tab: 'o-7c21',
        payment: 'p-8f2c',
        request: 'b7e1',
        broadcast: null,
      },
      context: [
        '{"t":"11:55:36.920","seq":48200,"l":"I","a":"UI","e":"tap","sess":"s-3f9a","ord":"o-7c21","intent":"PayCard","sum":25000}',
        '{"t":"11:55:57.703","seq":48204,"l":"I","a":"PAY","e":"terminal.ok","pay":"p-8f2c","auth":"1dc15286","pan":"****4821","ms":20742}',
        '{"t":"11:55:57.750","seq":48206,"l":"I","a":"SOCK","e":"req.send","ord":"o-7c21","pay":"p-8f2c","rid":"b7e1","op":"Pay","kb":1.9}',
        '{"t":"11:56:16.004","seq":48208,"l":"I","a":"ENV","e":"net.change","from":"wifi","to":"lte","ip":"10.21.4.88"}',
      ],
      stack: null,
    }); // 201 DeviceErrorResult
    // the client: see /v2/docs/typescript
    const deviceError = await api.post('/restaurants/123/device-errors', {
      id: '01a318f0-a0c0-7b57-8364-1e6fc225f5ce',
      occurred_at: '2027-01-15T11:56:17+01:00',
      level: 'error',
      code: 'SOCK.timeout',
      area: 'SOCK',
      event: 'req.timeout',
      message: 'Pay bez odpovědi 20 s (b7e1)',
      peer_key: '9bb5f040',
      employee_name: 'Jana',
      app_version: '26.10.3',
      refs: {
        session: 's-3f9a',
        tab: 'o-7c21',
        payment: 'p-8f2c',
        request: 'b7e1',
        broadcast: null,
      },
      context: [
        '{"t":"11:55:36.920","seq":48200,"l":"I","a":"UI","e":"tap","sess":"s-3f9a","ord":"o-7c21","intent":"PayCard","sum":25000}',
        '{"t":"11:55:57.703","seq":48204,"l":"I","a":"PAY","e":"terminal.ok","pay":"p-8f2c","auth":"1dc15286","pan":"****4821","ms":20742}',
        '{"t":"11:55:57.750","seq":48206,"l":"I","a":"SOCK","e":"req.send","ord":"o-7c21","pay":"p-8f2c","rid":"b7e1","op":"Pay","kb":1.9}',
        '{"t":"11:56:16.004","seq":48208,"l":"I","a":"ENV","e":"net.change","from":"wifi","to":"lte","ip":"10.21.4.88"}',
      ],
      stack: null,
    }); // 201 DeviceErrorResult
    // klient: viz /v2/docs/php
    $deviceError = $api->post('/restaurants/123/device-errors', [
        'id' => '01a318f0-a0c0-7b57-8364-1e6fc225f5ce',
        'occurred_at' => '2027-01-15T11:56:17+01:00',
        'level' => 'error',
        'code' => 'SOCK.timeout',
        'area' => 'SOCK',
        'event' => 'req.timeout',
        'message' => 'Pay bez odpovědi 20 s (b7e1)',
        'peer_key' => '9bb5f040',
        'employee_name' => 'Jana',
        'app_version' => '26.10.3',
        'refs' => [
            'session' => 's-3f9a',
            'tab' => 'o-7c21',
            'payment' => 'p-8f2c',
            'request' => 'b7e1',
            'broadcast' => null,
        ],
        'context' => [
            '{"t":"11:55:36.920","seq":48200,"l":"I","a":"UI","e":"tap","sess":"s-3f9a","ord":"o-7c21","intent":"PayCard","sum":25000}',
            '{"t":"11:55:57.703","seq":48204,"l":"I","a":"PAY","e":"terminal.ok","pay":"p-8f2c","auth":"1dc15286","pan":"****4821","ms":20742}',
            '{"t":"11:55:57.750","seq":48206,"l":"I","a":"SOCK","e":"req.send","ord":"o-7c21","pay":"p-8f2c","rid":"b7e1","op":"Pay","kb":1.9}',
            '{"t":"11:56:16.004","seq":48208,"l":"I","a":"ENV","e":"net.change","from":"wifi","to":"lte","ip":"10.21.4.88"}',
        ],
        'stack' => null,
    ]); // 201
    // the client: see /v2/docs/php
    $deviceError = $api->post('/restaurants/123/device-errors', [
        'id' => '01a318f0-a0c0-7b57-8364-1e6fc225f5ce',
        'occurred_at' => '2027-01-15T11:56:17+01:00',
        'level' => 'error',
        'code' => 'SOCK.timeout',
        'area' => 'SOCK',
        'event' => 'req.timeout',
        'message' => 'Pay bez odpovědi 20 s (b7e1)',
        'peer_key' => '9bb5f040',
        'employee_name' => 'Jana',
        'app_version' => '26.10.3',
        'refs' => [
            'session' => 's-3f9a',
            'tab' => 'o-7c21',
            'payment' => 'p-8f2c',
            'request' => 'b7e1',
            'broadcast' => null,
        ],
        'context' => [
            '{"t":"11:55:36.920","seq":48200,"l":"I","a":"UI","e":"tap","sess":"s-3f9a","ord":"o-7c21","intent":"PayCard","sum":25000}',
            '{"t":"11:55:57.703","seq":48204,"l":"I","a":"PAY","e":"terminal.ok","pay":"p-8f2c","auth":"1dc15286","pan":"****4821","ms":20742}',
            '{"t":"11:55:57.750","seq":48206,"l":"I","a":"SOCK","e":"req.send","ord":"o-7c21","pay":"p-8f2c","rid":"b7e1","op":"Pay","kb":1.9}',
            '{"t":"11:56:16.004","seq":48208,"l":"I","a":"ENV","e":"net.change","from":"wifi","to":"lte","ip":"10.21.4.88"}',
        ],
        'stack' => null,
    ]); // 201
    // klient: viz /v2/docs/java
    // volání blokuje – na Androidu z pracovního vlákna (Dispatchers.IO)
    DeviceErrorResult deviceError = api.post("/restaurants/123/device-errors", Json.parse("""
        {
          "id": "01a318f0-a0c0-7b57-8364-1e6fc225f5ce",
          "occurred_at": "2027-01-15T11:56:17+01:00",
          "level": "error",
          "code": "SOCK.timeout",
          "area": "SOCK",
          "event": "req.timeout",
          "message": "Pay bez odpovědi 20 s (b7e1)",
          "peer_key": "9bb5f040",
          "employee_name": "Jana",
          "app_version": "26.10.3",
          "refs": {
            "session": "s-3f9a",
            "tab": "o-7c21",
            "payment": "p-8f2c",
            "request": "b7e1",
            "broadcast": null
          },
          "context": [
            "{\\"t\\":\\"11:55:36.920\\",\\"seq\\":48200,\\"l\\":\\"I\\",\\"a\\":\\"UI\\",\\"e\\":\\"tap\\",\\"sess\\":\\"s-3f9a\\",\\"ord\\":\\"o-7c21\\",\\"intent\\":\\"PayCard\\",\\"sum\\":25000}",
            "{\\"t\\":\\"11:55:57.703\\",\\"seq\\":48204,\\"l\\":\\"I\\",\\"a\\":\\"PAY\\",\\"e\\":\\"terminal.ok\\",\\"pay\\":\\"p-8f2c\\",\\"auth\\":\\"1dc15286\\",\\"pan\\":\\"****4821\\",\\"ms\\":20742}",
            "{\\"t\\":\\"11:55:57.750\\",\\"seq\\":48206,\\"l\\":\\"I\\",\\"a\\":\\"SOCK\\",\\"e\\":\\"req.send\\",\\"ord\\":\\"o-7c21\\",\\"pay\\":\\"p-8f2c\\",\\"rid\\":\\"b7e1\\",\\"op\\":\\"Pay\\",\\"kb\\":1.9}",
            "{\\"t\\":\\"11:56:16.004\\",\\"seq\\":48208,\\"l\\":\\"I\\",\\"a\\":\\"ENV\\",\\"e\\":\\"net.change\\",\\"from\\":\\"wifi\\",\\"to\\":\\"lte\\",\\"ip\\":\\"10.21.4.88\\"}"
          ],
          "stack": null
        }
        """), DeviceErrorResult::fromJson); // 201
    // the client: see /v2/docs/java
    // the call blocks – on Android from a worker thread (Dispatchers.IO)
    DeviceErrorResult deviceError = api.post("/restaurants/123/device-errors", Json.parse("""
        {
          "id": "01a318f0-a0c0-7b57-8364-1e6fc225f5ce",
          "occurred_at": "2027-01-15T11:56:17+01:00",
          "level": "error",
          "code": "SOCK.timeout",
          "area": "SOCK",
          "event": "req.timeout",
          "message": "Pay bez odpovědi 20 s (b7e1)",
          "peer_key": "9bb5f040",
          "employee_name": "Jana",
          "app_version": "26.10.3",
          "refs": {
            "session": "s-3f9a",
            "tab": "o-7c21",
            "payment": "p-8f2c",
            "request": "b7e1",
            "broadcast": null
          },
          "context": [
            "{\\"t\\":\\"11:55:36.920\\",\\"seq\\":48200,\\"l\\":\\"I\\",\\"a\\":\\"UI\\",\\"e\\":\\"tap\\",\\"sess\\":\\"s-3f9a\\",\\"ord\\":\\"o-7c21\\",\\"intent\\":\\"PayCard\\",\\"sum\\":25000}",
            "{\\"t\\":\\"11:55:57.703\\",\\"seq\\":48204,\\"l\\":\\"I\\",\\"a\\":\\"PAY\\",\\"e\\":\\"terminal.ok\\",\\"pay\\":\\"p-8f2c\\",\\"auth\\":\\"1dc15286\\",\\"pan\\":\\"****4821\\",\\"ms\\":20742}",
            "{\\"t\\":\\"11:55:57.750\\",\\"seq\\":48206,\\"l\\":\\"I\\",\\"a\\":\\"SOCK\\",\\"e\\":\\"req.send\\",\\"ord\\":\\"o-7c21\\",\\"pay\\":\\"p-8f2c\\",\\"rid\\":\\"b7e1\\",\\"op\\":\\"Pay\\",\\"kb\\":1.9}",
            "{\\"t\\":\\"11:56:16.004\\",\\"seq\\":48208,\\"l\\":\\"I\\",\\"a\\":\\"ENV\\",\\"e\\":\\"net.change\\",\\"from\\":\\"wifi\\",\\"to\\":\\"lte\\",\\"ip\\":\\"10.21.4.88\\"}"
          ],
          "stack": null
        }
        """), DeviceErrorResult::fromJson); // 201
    // klient: viz /v2/docs/java
    // volání blokuje – na Androidu z pracovního vlákna (Dispatchers.IO)
    val deviceError = api.post("/restaurants/123/device-errors", mapOf(
        "id" to "01a318f0-a0c0-7b57-8364-1e6fc225f5ce",
        "occurred_at" to "2027-01-15T11:56:17+01:00",
        "level" to "error",
        "code" to "SOCK.timeout",
        "area" to "SOCK",
        "event" to "req.timeout",
        "message" to "Pay bez odpovědi 20 s (b7e1)",
        "peer_key" to "9bb5f040",
        "employee_name" to "Jana",
        "app_version" to "26.10.3",
        "refs" to mapOf(
            "session" to "s-3f9a",
            "tab" to "o-7c21",
            "payment" to "p-8f2c",
            "request" to "b7e1",
            "broadcast" to null,
        ),
        "context" to listOf(
            "{\"t\":\"11:55:36.920\",\"seq\":48200,\"l\":\"I\",\"a\":\"UI\",\"e\":\"tap\",\"sess\":\"s-3f9a\",\"ord\":\"o-7c21\",\"intent\":\"PayCard\",\"sum\":25000}",
            "{\"t\":\"11:55:57.703\",\"seq\":48204,\"l\":\"I\",\"a\":\"PAY\",\"e\":\"terminal.ok\",\"pay\":\"p-8f2c\",\"auth\":\"1dc15286\",\"pan\":\"****4821\",\"ms\":20742}",
            "{\"t\":\"11:55:57.750\",\"seq\":48206,\"l\":\"I\",\"a\":\"SOCK\",\"e\":\"req.send\",\"ord\":\"o-7c21\",\"pay\":\"p-8f2c\",\"rid\":\"b7e1\",\"op\":\"Pay\",\"kb\":1.9}",
            "{\"t\":\"11:56:16.004\",\"seq\":48208,\"l\":\"I\",\"a\":\"ENV\",\"e\":\"net.change\",\"from\":\"wifi\",\"to\":\"lte\",\"ip\":\"10.21.4.88\"}",
        ),
        "stack" to null,
    ), DeviceErrorResult::fromJson) // 201
    // the client: see /v2/docs/java
    // the call blocks – on Android from a worker thread (Dispatchers.IO)
    val deviceError = api.post("/restaurants/123/device-errors", mapOf(
        "id" to "01a318f0-a0c0-7b57-8364-1e6fc225f5ce",
        "occurred_at" to "2027-01-15T11:56:17+01:00",
        "level" to "error",
        "code" to "SOCK.timeout",
        "area" to "SOCK",
        "event" to "req.timeout",
        "message" to "Pay bez odpovědi 20 s (b7e1)",
        "peer_key" to "9bb5f040",
        "employee_name" to "Jana",
        "app_version" to "26.10.3",
        "refs" to mapOf(
            "session" to "s-3f9a",
            "tab" to "o-7c21",
            "payment" to "p-8f2c",
            "request" to "b7e1",
            "broadcast" to null,
        ),
        "context" to listOf(
            "{\"t\":\"11:55:36.920\",\"seq\":48200,\"l\":\"I\",\"a\":\"UI\",\"e\":\"tap\",\"sess\":\"s-3f9a\",\"ord\":\"o-7c21\",\"intent\":\"PayCard\",\"sum\":25000}",
            "{\"t\":\"11:55:57.703\",\"seq\":48204,\"l\":\"I\",\"a\":\"PAY\",\"e\":\"terminal.ok\",\"pay\":\"p-8f2c\",\"auth\":\"1dc15286\",\"pan\":\"****4821\",\"ms\":20742}",
            "{\"t\":\"11:55:57.750\",\"seq\":48206,\"l\":\"I\",\"a\":\"SOCK\",\"e\":\"req.send\",\"ord\":\"o-7c21\",\"pay\":\"p-8f2c\",\"rid\":\"b7e1\",\"op\":\"Pay\",\"kb\":1.9}",
            "{\"t\":\"11:56:16.004\",\"seq\":48208,\"l\":\"I\",\"a\":\"ENV\",\"e\":\"net.change\",\"from\":\"wifi\",\"to\":\"lte\",\"ip\":\"10.21.4.88\"}",
        ),
        "stack" to null,
    ), DeviceErrorResult::fromJson) // 201
    // klient: viz /v2/docs/csharp
    var deviceError = await api.PostAsync<DeviceErrorResult>("/restaurants/123/device-errors", new {
        id = "01a318f0-a0c0-7b57-8364-1e6fc225f5ce",
        occurred_at = "2027-01-15T11:56:17+01:00",
        level = "error",
        code = "SOCK.timeout",
        area = "SOCK",
        @event = "req.timeout",
        message = "Pay bez odpovědi 20 s (b7e1)",
        peer_key = "9bb5f040",
        employee_name = "Jana",
        app_version = "26.10.3",
        refs = new {
            session = "s-3f9a",
            tab = "o-7c21",
            payment = "p-8f2c",
            request = "b7e1",
            broadcast = (object?)null,
        },
        context = new[] {
            "{\"t\":\"11:55:36.920\",\"seq\":48200,\"l\":\"I\",\"a\":\"UI\",\"e\":\"tap\",\"sess\":\"s-3f9a\",\"ord\":\"o-7c21\",\"intent\":\"PayCard\",\"sum\":25000}",
            "{\"t\":\"11:55:57.703\",\"seq\":48204,\"l\":\"I\",\"a\":\"PAY\",\"e\":\"terminal.ok\",\"pay\":\"p-8f2c\",\"auth\":\"1dc15286\",\"pan\":\"****4821\",\"ms\":20742}",
            "{\"t\":\"11:55:57.750\",\"seq\":48206,\"l\":\"I\",\"a\":\"SOCK\",\"e\":\"req.send\",\"ord\":\"o-7c21\",\"pay\":\"p-8f2c\",\"rid\":\"b7e1\",\"op\":\"Pay\",\"kb\":1.9}",
            "{\"t\":\"11:56:16.004\",\"seq\":48208,\"l\":\"I\",\"a\":\"ENV\",\"e\":\"net.change\",\"from\":\"wifi\",\"to\":\"lte\",\"ip\":\"10.21.4.88\"}",
        },
        stack = (object?)null,
    }); // 201
    // the client: see /v2/docs/csharp
    var deviceError = await api.PostAsync<DeviceErrorResult>("/restaurants/123/device-errors", new {
        id = "01a318f0-a0c0-7b57-8364-1e6fc225f5ce",
        occurred_at = "2027-01-15T11:56:17+01:00",
        level = "error",
        code = "SOCK.timeout",
        area = "SOCK",
        @event = "req.timeout",
        message = "Pay bez odpovědi 20 s (b7e1)",
        peer_key = "9bb5f040",
        employee_name = "Jana",
        app_version = "26.10.3",
        refs = new {
            session = "s-3f9a",
            tab = "o-7c21",
            payment = "p-8f2c",
            request = "b7e1",
            broadcast = (object?)null,
        },
        context = new[] {
            "{\"t\":\"11:55:36.920\",\"seq\":48200,\"l\":\"I\",\"a\":\"UI\",\"e\":\"tap\",\"sess\":\"s-3f9a\",\"ord\":\"o-7c21\",\"intent\":\"PayCard\",\"sum\":25000}",
            "{\"t\":\"11:55:57.703\",\"seq\":48204,\"l\":\"I\",\"a\":\"PAY\",\"e\":\"terminal.ok\",\"pay\":\"p-8f2c\",\"auth\":\"1dc15286\",\"pan\":\"****4821\",\"ms\":20742}",
            "{\"t\":\"11:55:57.750\",\"seq\":48206,\"l\":\"I\",\"a\":\"SOCK\",\"e\":\"req.send\",\"ord\":\"o-7c21\",\"pay\":\"p-8f2c\",\"rid\":\"b7e1\",\"op\":\"Pay\",\"kb\":1.9}",
            "{\"t\":\"11:56:16.004\",\"seq\":48208,\"l\":\"I\",\"a\":\"ENV\",\"e\":\"net.change\",\"from\":\"wifi\",\"to\":\"lte\",\"ip\":\"10.21.4.88\"}",
        },
        stack = (object?)null,
    }); // 201
    # klient: viz /v2/docs/python
    device_error = api.post('/restaurants/123/device-errors', {
        'id': '01a318f0-a0c0-7b57-8364-1e6fc225f5ce',
        'occurred_at': '2027-01-15T11:56:17+01:00',
        'level': 'error',
        'code': 'SOCK.timeout',
        'area': 'SOCK',
        'event': 'req.timeout',
        'message': 'Pay bez odpovědi 20 s (b7e1)',
        'peer_key': '9bb5f040',
        'employee_name': 'Jana',
        'app_version': '26.10.3',
        'refs': {
            'session': 's-3f9a',
            'tab': 'o-7c21',
            'payment': 'p-8f2c',
            'request': 'b7e1',
            'broadcast': None,
        },
        'context': [
            '{"t":"11:55:36.920","seq":48200,"l":"I","a":"UI","e":"tap","sess":"s-3f9a","ord":"o-7c21","intent":"PayCard","sum":25000}',
            '{"t":"11:55:57.703","seq":48204,"l":"I","a":"PAY","e":"terminal.ok","pay":"p-8f2c","auth":"1dc15286","pan":"****4821","ms":20742}',
            '{"t":"11:55:57.750","seq":48206,"l":"I","a":"SOCK","e":"req.send","ord":"o-7c21","pay":"p-8f2c","rid":"b7e1","op":"Pay","kb":1.9}',
            '{"t":"11:56:16.004","seq":48208,"l":"I","a":"ENV","e":"net.change","from":"wifi","to":"lte","ip":"10.21.4.88"}',
        ],
        'stack': None,
    })  # 201
    # the client: see /v2/docs/python
    device_error = api.post('/restaurants/123/device-errors', {
        'id': '01a318f0-a0c0-7b57-8364-1e6fc225f5ce',
        'occurred_at': '2027-01-15T11:56:17+01:00',
        'level': 'error',
        'code': 'SOCK.timeout',
        'area': 'SOCK',
        'event': 'req.timeout',
        'message': 'Pay bez odpovědi 20 s (b7e1)',
        'peer_key': '9bb5f040',
        'employee_name': 'Jana',
        'app_version': '26.10.3',
        'refs': {
            'session': 's-3f9a',
            'tab': 'o-7c21',
            'payment': 'p-8f2c',
            'request': 'b7e1',
            'broadcast': None,
        },
        'context': [
            '{"t":"11:55:36.920","seq":48200,"l":"I","a":"UI","e":"tap","sess":"s-3f9a","ord":"o-7c21","intent":"PayCard","sum":25000}',
            '{"t":"11:55:57.703","seq":48204,"l":"I","a":"PAY","e":"terminal.ok","pay":"p-8f2c","auth":"1dc15286","pan":"****4821","ms":20742}',
            '{"t":"11:55:57.750","seq":48206,"l":"I","a":"SOCK","e":"req.send","ord":"o-7c21","pay":"p-8f2c","rid":"b7e1","op":"Pay","kb":1.9}',
            '{"t":"11:56:16.004","seq":48208,"l":"I","a":"ENV","e":"net.change","from":"wifi","to":"lte","ip":"10.21.4.88"}',
        ],
        'stack': None,
    })  # 201
    // klient: viz /v2/docs/swift
    let deviceError: DeviceErrorResult = try await api.post("/restaurants/123/device-errors", body: [
        "id": "01a318f0-a0c0-7b57-8364-1e6fc225f5ce",
        "occurred_at": "2027-01-15T11:56:17+01:00",
        "level": "error",
        "code": "SOCK.timeout",
        "area": "SOCK",
        "event": "req.timeout",
        "message": "Pay bez odpovědi 20 s (b7e1)",
        "peer_key": "9bb5f040",
        "employee_name": "Jana",
        "app_version": "26.10.3",
        "refs": [
            "session": "s-3f9a",
            "tab": "o-7c21",
            "payment": "p-8f2c",
            "request": "b7e1",
            "broadcast": nil,
        ],
        "context": [
            "{\"t\":\"11:55:36.920\",\"seq\":48200,\"l\":\"I\",\"a\":\"UI\",\"e\":\"tap\",\"sess\":\"s-3f9a\",\"ord\":\"o-7c21\",\"intent\":\"PayCard\",\"sum\":25000}",
            "{\"t\":\"11:55:57.703\",\"seq\":48204,\"l\":\"I\",\"a\":\"PAY\",\"e\":\"terminal.ok\",\"pay\":\"p-8f2c\",\"auth\":\"1dc15286\",\"pan\":\"****4821\",\"ms\":20742}",
            "{\"t\":\"11:55:57.750\",\"seq\":48206,\"l\":\"I\",\"a\":\"SOCK\",\"e\":\"req.send\",\"ord\":\"o-7c21\",\"pay\":\"p-8f2c\",\"rid\":\"b7e1\",\"op\":\"Pay\",\"kb\":1.9}",
            "{\"t\":\"11:56:16.004\",\"seq\":48208,\"l\":\"I\",\"a\":\"ENV\",\"e\":\"net.change\",\"from\":\"wifi\",\"to\":\"lte\",\"ip\":\"10.21.4.88\"}",
        ],
        "stack": nil,
    ]) // 201
    // the client: see /v2/docs/swift
    let deviceError: DeviceErrorResult = try await api.post("/restaurants/123/device-errors", body: [
        "id": "01a318f0-a0c0-7b57-8364-1e6fc225f5ce",
        "occurred_at": "2027-01-15T11:56:17+01:00",
        "level": "error",
        "code": "SOCK.timeout",
        "area": "SOCK",
        "event": "req.timeout",
        "message": "Pay bez odpovědi 20 s (b7e1)",
        "peer_key": "9bb5f040",
        "employee_name": "Jana",
        "app_version": "26.10.3",
        "refs": [
            "session": "s-3f9a",
            "tab": "o-7c21",
            "payment": "p-8f2c",
            "request": "b7e1",
            "broadcast": nil,
        ],
        "context": [
            "{\"t\":\"11:55:36.920\",\"seq\":48200,\"l\":\"I\",\"a\":\"UI\",\"e\":\"tap\",\"sess\":\"s-3f9a\",\"ord\":\"o-7c21\",\"intent\":\"PayCard\",\"sum\":25000}",
            "{\"t\":\"11:55:57.703\",\"seq\":48204,\"l\":\"I\",\"a\":\"PAY\",\"e\":\"terminal.ok\",\"pay\":\"p-8f2c\",\"auth\":\"1dc15286\",\"pan\":\"****4821\",\"ms\":20742}",
            "{\"t\":\"11:55:57.750\",\"seq\":48206,\"l\":\"I\",\"a\":\"SOCK\",\"e\":\"req.send\",\"ord\":\"o-7c21\",\"pay\":\"p-8f2c\",\"rid\":\"b7e1\",\"op\":\"Pay\",\"kb\":1.9}",
            "{\"t\":\"11:56:16.004\",\"seq\":48208,\"l\":\"I\",\"a\":\"ENV\",\"e\":\"net.change\",\"from\":\"wifi\",\"to\":\"lte\",\"ip\":\"10.21.4.88\"}",
        ],
        "stack": nil,
    ]) // 201
    // klient: viz /v2/docs/dart
    final deviceError = pr.DeviceErrorResult.fromJson(await api.post('/restaurants/123/device-errors', {
      'id': '01a318f0-a0c0-7b57-8364-1e6fc225f5ce',
      'occurred_at': '2027-01-15T11:56:17+01:00',
      'level': 'error',
      'code': 'SOCK.timeout',
      'area': 'SOCK',
      'event': 'req.timeout',
      'message': 'Pay bez odpovědi 20 s (b7e1)',
      'peer_key': '9bb5f040',
      'employee_name': 'Jana',
      'app_version': '26.10.3',
      'refs': {
        'session': 's-3f9a',
        'tab': 'o-7c21',
        'payment': 'p-8f2c',
        'request': 'b7e1',
        'broadcast': null,
      },
      'context': [
        '{"t":"11:55:36.920","seq":48200,"l":"I","a":"UI","e":"tap","sess":"s-3f9a","ord":"o-7c21","intent":"PayCard","sum":25000}',
        '{"t":"11:55:57.703","seq":48204,"l":"I","a":"PAY","e":"terminal.ok","pay":"p-8f2c","auth":"1dc15286","pan":"****4821","ms":20742}',
        '{"t":"11:55:57.750","seq":48206,"l":"I","a":"SOCK","e":"req.send","ord":"o-7c21","pay":"p-8f2c","rid":"b7e1","op":"Pay","kb":1.9}',
        '{"t":"11:56:16.004","seq":48208,"l":"I","a":"ENV","e":"net.change","from":"wifi","to":"lte","ip":"10.21.4.88"}',
      ],
      'stack': null,
    })); // 201
    // the client: see /v2/docs/dart
    final deviceError = pr.DeviceErrorResult.fromJson(await api.post('/restaurants/123/device-errors', {
      'id': '01a318f0-a0c0-7b57-8364-1e6fc225f5ce',
      'occurred_at': '2027-01-15T11:56:17+01:00',
      'level': 'error',
      'code': 'SOCK.timeout',
      'area': 'SOCK',
      'event': 'req.timeout',
      'message': 'Pay bez odpovědi 20 s (b7e1)',
      'peer_key': '9bb5f040',
      'employee_name': 'Jana',
      'app_version': '26.10.3',
      'refs': {
        'session': 's-3f9a',
        'tab': 'o-7c21',
        'payment': 'p-8f2c',
        'request': 'b7e1',
        'broadcast': null,
      },
      'context': [
        '{"t":"11:55:36.920","seq":48200,"l":"I","a":"UI","e":"tap","sess":"s-3f9a","ord":"o-7c21","intent":"PayCard","sum":25000}',
        '{"t":"11:55:57.703","seq":48204,"l":"I","a":"PAY","e":"terminal.ok","pay":"p-8f2c","auth":"1dc15286","pan":"****4821","ms":20742}',
        '{"t":"11:55:57.750","seq":48206,"l":"I","a":"SOCK","e":"req.send","ord":"o-7c21","pay":"p-8f2c","rid":"b7e1","op":"Pay","kb":1.9}',
        '{"t":"11:56:16.004","seq":48208,"l":"I","a":"ENV","e":"net.change","from":"wifi","to":"lte","ip":"10.21.4.88"}',
      ],
      'stack': null,
    })); // 201
    // klient: viz /v2/docs/go
    res, err := api.Post(ctx, "/restaurants/123/device-errors", map[string]any{
    	"id": "01a318f0-a0c0-7b57-8364-1e6fc225f5ce",
    	"occurred_at": "2027-01-15T11:56:17+01:00",
    	"level": "error",
    	"code": "SOCK.timeout",
    	"area": "SOCK",
    	"event": "req.timeout",
    	"message": "Pay bez odpovědi 20 s (b7e1)",
    	"peer_key": "9bb5f040",
    	"employee_name": "Jana",
    	"app_version": "26.10.3",
    	"refs": map[string]any{
    		"session": "s-3f9a",
    		"tab": "o-7c21",
    		"payment": "p-8f2c",
    		"request": "b7e1",
    		"broadcast": nil,
    	},
    	"context": []any{
    		"{\"t\":\"11:55:36.920\",\"seq\":48200,\"l\":\"I\",\"a\":\"UI\",\"e\":\"tap\",\"sess\":\"s-3f9a\",\"ord\":\"o-7c21\",\"intent\":\"PayCard\",\"sum\":25000}",
    		"{\"t\":\"11:55:57.703\",\"seq\":48204,\"l\":\"I\",\"a\":\"PAY\",\"e\":\"terminal.ok\",\"pay\":\"p-8f2c\",\"auth\":\"1dc15286\",\"pan\":\"****4821\",\"ms\":20742}",
    		"{\"t\":\"11:55:57.750\",\"seq\":48206,\"l\":\"I\",\"a\":\"SOCK\",\"e\":\"req.send\",\"ord\":\"o-7c21\",\"pay\":\"p-8f2c\",\"rid\":\"b7e1\",\"op\":\"Pay\",\"kb\":1.9}",
    		"{\"t\":\"11:56:16.004\",\"seq\":48208,\"l\":\"I\",\"a\":\"ENV\",\"e\":\"net.change\",\"from\":\"wifi\",\"to\":\"lte\",\"ip\":\"10.21.4.88\"}",
    	},
    	"stack": nil,
    }, nil)
    var deviceError model.DeviceErrorResult // 201
    if err == nil {
    	err = res.Decode(&deviceError)
    }
    // the client: see /v2/docs/go
    res, err := api.Post(ctx, "/restaurants/123/device-errors", map[string]any{
    	"id": "01a318f0-a0c0-7b57-8364-1e6fc225f5ce",
    	"occurred_at": "2027-01-15T11:56:17+01:00",
    	"level": "error",
    	"code": "SOCK.timeout",
    	"area": "SOCK",
    	"event": "req.timeout",
    	"message": "Pay bez odpovědi 20 s (b7e1)",
    	"peer_key": "9bb5f040",
    	"employee_name": "Jana",
    	"app_version": "26.10.3",
    	"refs": map[string]any{
    		"session": "s-3f9a",
    		"tab": "o-7c21",
    		"payment": "p-8f2c",
    		"request": "b7e1",
    		"broadcast": nil,
    	},
    	"context": []any{
    		"{\"t\":\"11:55:36.920\",\"seq\":48200,\"l\":\"I\",\"a\":\"UI\",\"e\":\"tap\",\"sess\":\"s-3f9a\",\"ord\":\"o-7c21\",\"intent\":\"PayCard\",\"sum\":25000}",
    		"{\"t\":\"11:55:57.703\",\"seq\":48204,\"l\":\"I\",\"a\":\"PAY\",\"e\":\"terminal.ok\",\"pay\":\"p-8f2c\",\"auth\":\"1dc15286\",\"pan\":\"****4821\",\"ms\":20742}",
    		"{\"t\":\"11:55:57.750\",\"seq\":48206,\"l\":\"I\",\"a\":\"SOCK\",\"e\":\"req.send\",\"ord\":\"o-7c21\",\"pay\":\"p-8f2c\",\"rid\":\"b7e1\",\"op\":\"Pay\",\"kb\":1.9}",
    		"{\"t\":\"11:56:16.004\",\"seq\":48208,\"l\":\"I\",\"a\":\"ENV\",\"e\":\"net.change\",\"from\":\"wifi\",\"to\":\"lte\",\"ip\":\"10.21.4.88\"}",
    	},
    	"stack": nil,
    }, nil)
    var deviceError model.DeviceErrorResult // 201
    if err == nil {
    	err = res.Decode(&deviceError)
    }
    Příklad odpovědi 200Example answer 200
    {
      "id": "90115",
      "received_at": "2027-01-15T11:56:18+01:00"
    }
  3. Na příkaz upload_logs nahrajte log po částech

    On upload_logs upload the log in parts

    PUT /log-uploads/{upload_id}/parts/{part} · putLogUploadPart

    Pro každý cíl z příkazu: gzip NDJSON za období from–to, části do 4 MB, každá část úplný proud gzip (server je jen zřetězí). Token cíle (pfl_…) je Authorization – telefon číšníka nepotřebuje vlastní token, cíl mu předá kasa po místní síti. Nahrávejte mimo frontu objednávek a během placení pozastavte.

    For every target of the command: gzip NDJSON for the period from–to, parts up to 4 MB, each part a complete gzip stream (the server just concatenates them). The token of the target (pfl_…) is the Authorization – a waiter's phone needs no token of its own, the register hands the target over on the local network. Upload outside the queue of orders and pause while the staff pays.

    curl -X PUT "https://api.mujprofirest.cz/v2/log-uploads/7742/parts/3" \
      -H "Authorization: Bearer $UPLOAD_TOKEN" \
      -H "Content-Type: application/gzip" \
      --data-binary @log-cast-3.gz
    curl -X PUT "https://api.mujprofirest.cz/v2/log-uploads/7742/parts/3" \
      -H "Authorization: Bearer $UPLOAD_TOKEN" \
      -H "Content-Type: application/gzip" \
      --data-binary @log-cast-3.gz
    // klient: viz /v2/docs/js
    // token cíle pfl_ z příkazu upload_logs (LogUploadTarget.token) místo tokenu zařízení – jde i bez párování
    const logUploadPart = await api.put('/log-uploads/7742/parts/3', partBlob, {
      contentType: 'application/gzip',
      auth: false,
      headers: { Authorization: 'Bearer ' + uploadToken },
    }); // 200
    // the client: see /v2/docs/js
    // the target's pfl_ token from the upload_logs command (LogUploadTarget.token) instead of the device's token – works unpaired too
    const logUploadPart = await api.put('/log-uploads/7742/parts/3', partBlob, {
      contentType: 'application/gzip',
      auth: false,
      headers: { Authorization: 'Bearer ' + uploadToken },
    }); // 200
    // klient: viz /v2/docs/typescript
    // token cíle pfl_ z příkazu upload_logs (LogUploadTarget.token) místo tokenu zařízení – jde i bez párování
    const logUploadPart = await api.put('/log-uploads/7742/parts/3', partBlob, {
      contentType: 'application/gzip',
      auth: false,
      headers: { Authorization: 'Bearer ' + uploadToken },
    }); // 200 LogUploadStatus
    // the client: see /v2/docs/typescript
    // the target's pfl_ token from the upload_logs command (LogUploadTarget.token) instead of the device's token – works unpaired too
    const logUploadPart = await api.put('/log-uploads/7742/parts/3', partBlob, {
      contentType: 'application/gzip',
      auth: false,
      headers: { Authorization: 'Bearer ' + uploadToken },
    }); // 200 LogUploadStatus
    // klient: viz /v2/docs/php
    // token cíle pfl_ z příkazu upload_logs (LogUploadTarget.token) místo tokenu zařízení – jde i bez párování
    $upload = $api->put('/log-uploads/7742/parts/3', file_get_contents('log-cast-3.gz'), ['contentType' => 'application/gzip', 'auth' => false, 'headers' => ['Authorization' => 'Bearer ' . $uploadToken]]);
    // the client: see /v2/docs/php
    // the target's pfl_ token from the upload_logs command (LogUploadTarget.token) instead of the device's token – works unpaired too
    $upload = $api->put('/log-uploads/7742/parts/3', file_get_contents('log-cast-3.gz'), ['contentType' => 'application/gzip', 'auth' => false, 'headers' => ['Authorization' => 'Bearer ' . $uploadToken]]);
    // klient: viz /v2/docs/java
    // volání blokuje – na Androidu z pracovního vlákna (Dispatchers.IO)
    // token cíle pfl_ z příkazu upload_logs (LogUploadTarget.token) místo tokenu zařízení – jde i bez párování
    Object upload = api.put("/log-uploads/7742/parts/3", Files.readAllBytes(Path.of("log-cast-3.gz")),
            RequestOptions.builder().contentType("application/gzip").auth(false).header("Authorization", "Bearer " + uploadToken).build());
    // the client: see /v2/docs/java
    // the call blocks – on Android from a worker thread (Dispatchers.IO)
    // the target's pfl_ token from the upload_logs command (LogUploadTarget.token) instead of the device's token – works unpaired too
    Object upload = api.put("/log-uploads/7742/parts/3", Files.readAllBytes(Path.of("log-cast-3.gz")),
            RequestOptions.builder().contentType("application/gzip").auth(false).header("Authorization", "Bearer " + uploadToken).build());
    // klient: viz /v2/docs/java
    // volání blokuje – na Androidu z pracovního vlákna (Dispatchers.IO)
    // token cíle pfl_ z příkazu upload_logs (LogUploadTarget.token) místo tokenu zařízení – jde i bez párování
    val upload = api.put("/log-uploads/7742/parts/3", File("log-cast-3.gz").readBytes(),
        RequestOptions.builder().contentType("application/gzip").auth(false).header("Authorization", "Bearer " + uploadToken).build())
    // the client: see /v2/docs/java
    // the call blocks – on Android from a worker thread (Dispatchers.IO)
    // the target's pfl_ token from the upload_logs command (LogUploadTarget.token) instead of the device's token – works unpaired too
    val upload = api.put("/log-uploads/7742/parts/3", File("log-cast-3.gz").readBytes(),
        RequestOptions.builder().contentType("application/gzip").auth(false).header("Authorization", "Bearer " + uploadToken).build())
    // klient: viz /v2/docs/csharp
    // token cíle pfl_ z příkazu upload_logs (LogUploadTarget.token) místo tokenu zařízení – jde i bez párování
    await using var part = File.OpenRead("log-cast-3.gz");
    var upload = await api.PutAsync("/log-uploads/7742/parts/3", part, new RequestOptions { ContentType = "application/gzip", Auth = false, Headers = new() { ["Authorization"] = "Bearer " + uploadToken } });
    // the client: see /v2/docs/csharp
    // the target's pfl_ token from the upload_logs command (LogUploadTarget.token) instead of the device's token – works unpaired too
    await using var part = File.OpenRead("log-cast-3.gz");
    var upload = await api.PutAsync("/log-uploads/7742/parts/3", part, new RequestOptions { ContentType = "application/gzip", Auth = false, Headers = new() { ["Authorization"] = "Bearer " + uploadToken } });
    # klient: viz /v2/docs/python
    # token cíle pfl_ z příkazu upload_logs (LogUploadTarget.token) místo tokenu zařízení – jde i bez párování
    with open('log-cast-3.gz', 'rb') as fh:
        upload = api.put('/log-uploads/7742/parts/3', fh, content_type='application/gzip', auth=False, headers={'Authorization': 'Bearer ' + upload_token})
    # the client: see /v2/docs/python
    # the target's pfl_ token from the upload_logs command (LogUploadTarget.token) instead of the device's token – works unpaired too
    with open('log-cast-3.gz', 'rb') as fh:
        upload = api.put('/log-uploads/7742/parts/3', fh, content_type='application/gzip', auth=False, headers={'Authorization': 'Bearer ' + upload_token})
    // klient: viz /v2/docs/swift
    // token cíle pfl_ z příkazu upload_logs (LogUploadTarget.token) místo tokenu zařízení – jde i bez párování
    let upload = try await api.put("/log-uploads/7742/parts/3", body: .data(try Data(contentsOf: partURL), contentType: "application/gzip"),
                                    options: .init(headers: ["Authorization": "Bearer \(uploadToken)"], auth: false))
    // the client: see /v2/docs/swift
    // the target's pfl_ token from the upload_logs command (LogUploadTarget.token) instead of the device's token – works unpaired too
    let upload = try await api.put("/log-uploads/7742/parts/3", body: .data(try Data(contentsOf: partURL), contentType: "application/gzip"),
                                    options: .init(headers: ["Authorization": "Bearer \(uploadToken)"], auth: false))
    // klient: viz /v2/docs/dart
    // token cíle pfl_ z příkazu upload_logs (LogUploadTarget.token) místo tokenu zařízení – jde i bez párování
    final upload = await api.put('/log-uploads/7742/parts/3', await File('log-cast-3.gz').readAsBytes(), contentType: 'application/gzip', auth: false, headers: {'Authorization': 'Bearer $uploadToken'});
    // the client: see /v2/docs/dart
    // the target's pfl_ token from the upload_logs command (LogUploadTarget.token) instead of the device's token – works unpaired too
    final upload = await api.put('/log-uploads/7742/parts/3', await File('log-cast-3.gz').readAsBytes(), contentType: 'application/gzip', auth: false, headers: {'Authorization': 'Bearer $uploadToken'});
    // klient: viz /v2/docs/go
    // token cíle pfl_ z příkazu upload_logs (LogUploadTarget.token) místo tokenu zařízení – jde i bez párování
    part, err := os.ReadFile("log-cast-3.gz")
    res, err := api.Put(ctx, "/log-uploads/7742/parts/3", part, &profirest.RequestOptions{ContentType: "application/gzip", NoAuth: true, Header: http.Header{"Authorization": {"Bearer " + uploadToken}}})
    // the client: see /v2/docs/go
    // the target's pfl_ token from the upload_logs command (LogUploadTarget.token) instead of the device's token – works unpaired too
    part, err := os.ReadFile("log-cast-3.gz")
    res, err := api.Put(ctx, "/log-uploads/7742/parts/3", part, &profirest.RequestOptions{ContentType: "application/gzip", NoAuth: true, Header: http.Header{"Authorization": {"Bearer " + uploadToken}}})
    Příklad odpovědi 200Example answer 200
    {
      "id": "7742",
      "request_id": "3105",
      "status": "uploading",
      "parts_received": [
        1,
        2,
        3
      ],
      "parts_expected": null,
      "bytes": 4718592,
      "from": "2027-01-14T12:00:00+01:00",
      "to": "2027-01-15T12:00:00+01:00",
      "detail": "full",
      "max_part_bytes": 4194304,
      "expires_at": "2027-01-16T12:00:35+01:00"
    }
  4. Dokončete nahrávání

    Finish the upload

    POST /log-uploads/{upload_id}/complete · completeLogUpload

    parts říká, kolik částí jste poslali; chybějící vrátí 422 upload_incomplete s čísly v detail. Po přerušení se zeptejte getLogUpload, které části server má, a pošlete jen zbytek.

    parts says how many parts you sent; missing ones answer 422 upload_incomplete with the numbers in detail. After an interruption ask getLogUpload which parts the server has and send only the rest.

    curl "https://api.mujprofirest.cz/v2/log-uploads/7742/complete" \
      -H "Authorization: Bearer $UPLOAD_TOKEN" \
      -H "Content-Type: application/json" \
      -d '{
      "parts": 3,
      "lines": 184210,
      "from": "2027-01-14T12:00:00+01:00",
      "to": "2027-01-15T11:59:58+01:00",
      "sha256": null
    }'
    curl "https://api.mujprofirest.cz/v2/log-uploads/7742/complete" \
      -H "Authorization: Bearer $UPLOAD_TOKEN" \
      -H "Content-Type: application/json" \
      -d '{
      "parts": 3,
      "lines": 184210,
      "from": "2027-01-14T12:00:00+01:00",
      "to": "2027-01-15T11:59:58+01:00",
      "sha256": null
    }'
    // klient: viz /v2/docs/js
    // token cíle pfl_ z příkazu upload_logs (LogUploadTarget.token) místo tokenu zařízení – jde i bez párování
    const logUpload = await api.post('/log-uploads/7742/complete', {
      parts: 3,
      lines: 184210,
      from: '2027-01-14T12:00:00+01:00',
      to: '2027-01-15T11:59:58+01:00',
      sha256: null,
    }, { auth: false, headers: { Authorization: 'Bearer ' + uploadToken } }); // 200
    // the client: see /v2/docs/js
    // the target's pfl_ token from the upload_logs command (LogUploadTarget.token) instead of the device's token – works unpaired too
    const logUpload = await api.post('/log-uploads/7742/complete', {
      parts: 3,
      lines: 184210,
      from: '2027-01-14T12:00:00+01:00',
      to: '2027-01-15T11:59:58+01:00',
      sha256: null,
    }, { auth: false, headers: { Authorization: 'Bearer ' + uploadToken } }); // 200
    // klient: viz /v2/docs/typescript
    // token cíle pfl_ z příkazu upload_logs (LogUploadTarget.token) místo tokenu zařízení – jde i bez párování
    const logUpload = await api.post('/log-uploads/7742/complete', {
      parts: 3,
      lines: 184210,
      from: '2027-01-14T12:00:00+01:00',
      to: '2027-01-15T11:59:58+01:00',
      sha256: null,
    }, { auth: false, headers: { Authorization: 'Bearer ' + uploadToken } }); // 200 LogUploadStatus
    // the client: see /v2/docs/typescript
    // the target's pfl_ token from the upload_logs command (LogUploadTarget.token) instead of the device's token – works unpaired too
    const logUpload = await api.post('/log-uploads/7742/complete', {
      parts: 3,
      lines: 184210,
      from: '2027-01-14T12:00:00+01:00',
      to: '2027-01-15T11:59:58+01:00',
      sha256: null,
    }, { auth: false, headers: { Authorization: 'Bearer ' + uploadToken } }); // 200 LogUploadStatus
    // klient: viz /v2/docs/php
    // token cíle pfl_ z příkazu upload_logs (LogUploadTarget.token) místo tokenu zařízení – jde i bez párování
    $logUpload = $api->post('/log-uploads/7742/complete', [
        'parts' => 3,
        'lines' => 184210,
        'from' => '2027-01-14T12:00:00+01:00',
        'to' => '2027-01-15T11:59:58+01:00',
        'sha256' => null,
    ], ['auth' => false, 'headers' => ['Authorization' => 'Bearer ' . $uploadToken]]); // 200
    // the client: see /v2/docs/php
    // the target's pfl_ token from the upload_logs command (LogUploadTarget.token) instead of the device's token – works unpaired too
    $logUpload = $api->post('/log-uploads/7742/complete', [
        'parts' => 3,
        'lines' => 184210,
        'from' => '2027-01-14T12:00:00+01:00',
        'to' => '2027-01-15T11:59:58+01:00',
        'sha256' => null,
    ], ['auth' => false, 'headers' => ['Authorization' => 'Bearer ' . $uploadToken]]); // 200
    // klient: viz /v2/docs/java
    // volání blokuje – na Androidu z pracovního vlákna (Dispatchers.IO)
    // token cíle pfl_ z příkazu upload_logs (LogUploadTarget.token) místo tokenu zařízení – jde i bez párování
    LogUploadStatus logUpload = api.post("/log-uploads/7742/complete", Json.parse("""
        {
          "parts": 3,
          "lines": 184210,
          "from": "2027-01-14T12:00:00+01:00",
          "to": "2027-01-15T11:59:58+01:00",
          "sha256": null
        }
        """), RequestOptions.builder().auth(false).header("Authorization", "Bearer " + uploadToken).build(), LogUploadStatus::fromJson); // 200
    // the client: see /v2/docs/java
    // the call blocks – on Android from a worker thread (Dispatchers.IO)
    // the target's pfl_ token from the upload_logs command (LogUploadTarget.token) instead of the device's token – works unpaired too
    LogUploadStatus logUpload = api.post("/log-uploads/7742/complete", Json.parse("""
        {
          "parts": 3,
          "lines": 184210,
          "from": "2027-01-14T12:00:00+01:00",
          "to": "2027-01-15T11:59:58+01:00",
          "sha256": null
        }
        """), RequestOptions.builder().auth(false).header("Authorization", "Bearer " + uploadToken).build(), LogUploadStatus::fromJson); // 200
    // klient: viz /v2/docs/java
    // volání blokuje – na Androidu z pracovního vlákna (Dispatchers.IO)
    // token cíle pfl_ z příkazu upload_logs (LogUploadTarget.token) místo tokenu zařízení – jde i bez párování
    val logUpload = api.post("/log-uploads/7742/complete", mapOf(
        "parts" to 3,
        "lines" to 184210,
        "from" to "2027-01-14T12:00:00+01:00",
        "to" to "2027-01-15T11:59:58+01:00",
        "sha256" to null,
    ), RequestOptions.builder().auth(false).header("Authorization", "Bearer " + uploadToken).build(), LogUploadStatus::fromJson) // 200
    // the client: see /v2/docs/java
    // the call blocks – on Android from a worker thread (Dispatchers.IO)
    // the target's pfl_ token from the upload_logs command (LogUploadTarget.token) instead of the device's token – works unpaired too
    val logUpload = api.post("/log-uploads/7742/complete", mapOf(
        "parts" to 3,
        "lines" to 184210,
        "from" to "2027-01-14T12:00:00+01:00",
        "to" to "2027-01-15T11:59:58+01:00",
        "sha256" to null,
    ), RequestOptions.builder().auth(false).header("Authorization", "Bearer " + uploadToken).build(), LogUploadStatus::fromJson) // 200
    // klient: viz /v2/docs/csharp
    // token cíle pfl_ z příkazu upload_logs (LogUploadTarget.token) místo tokenu zařízení – jde i bez párování
    var logUpload = await api.PostAsync<LogUploadStatus>("/log-uploads/7742/complete", new {
        parts = 3,
        lines = 184210,
        from = "2027-01-14T12:00:00+01:00",
        to = "2027-01-15T11:59:58+01:00",
        sha256 = (object?)null,
    }, new RequestOptions { Auth = false, Headers = new() { ["Authorization"] = "Bearer " + uploadToken } }); // 200
    // the client: see /v2/docs/csharp
    // the target's pfl_ token from the upload_logs command (LogUploadTarget.token) instead of the device's token – works unpaired too
    var logUpload = await api.PostAsync<LogUploadStatus>("/log-uploads/7742/complete", new {
        parts = 3,
        lines = 184210,
        from = "2027-01-14T12:00:00+01:00",
        to = "2027-01-15T11:59:58+01:00",
        sha256 = (object?)null,
    }, new RequestOptions { Auth = false, Headers = new() { ["Authorization"] = "Bearer " + uploadToken } }); // 200
    # klient: viz /v2/docs/python
    # token cíle pfl_ z příkazu upload_logs (LogUploadTarget.token) místo tokenu zařízení – jde i bez párování
    log_upload = api.post('/log-uploads/7742/complete', {
        'parts': 3,
        'lines': 184210,
        'from': '2027-01-14T12:00:00+01:00',
        'to': '2027-01-15T11:59:58+01:00',
        'sha256': None,
    }, auth=False, headers={'Authorization': 'Bearer ' + upload_token})  # 200
    # the client: see /v2/docs/python
    # the target's pfl_ token from the upload_logs command (LogUploadTarget.token) instead of the device's token – works unpaired too
    log_upload = api.post('/log-uploads/7742/complete', {
        'parts': 3,
        'lines': 184210,
        'from': '2027-01-14T12:00:00+01:00',
        'to': '2027-01-15T11:59:58+01:00',
        'sha256': None,
    }, auth=False, headers={'Authorization': 'Bearer ' + upload_token})  # 200
    // klient: viz /v2/docs/swift
    // token cíle pfl_ z příkazu upload_logs (LogUploadTarget.token) místo tokenu zařízení – jde i bez párování
    let logUpload: LogUploadStatus = try await api.post("/log-uploads/7742/complete", body: [
        "parts": 3,
        "lines": 184210,
        "from": "2027-01-14T12:00:00+01:00",
        "to": "2027-01-15T11:59:58+01:00",
        "sha256": nil,
    ], options: .init(headers: ["Authorization": "Bearer \(uploadToken)"], auth: false)) // 200
    // the client: see /v2/docs/swift
    // the target's pfl_ token from the upload_logs command (LogUploadTarget.token) instead of the device's token – works unpaired too
    let logUpload: LogUploadStatus = try await api.post("/log-uploads/7742/complete", body: [
        "parts": 3,
        "lines": 184210,
        "from": "2027-01-14T12:00:00+01:00",
        "to": "2027-01-15T11:59:58+01:00",
        "sha256": nil,
    ], options: .init(headers: ["Authorization": "Bearer \(uploadToken)"], auth: false)) // 200
    // klient: viz /v2/docs/dart
    // token cíle pfl_ z příkazu upload_logs (LogUploadTarget.token) místo tokenu zařízení – jde i bez párování
    final logUpload = pr.LogUploadStatus.fromJson(await api.post('/log-uploads/7742/complete', {
      'parts': 3,
      'lines': 184210,
      'from': '2027-01-14T12:00:00+01:00',
      'to': '2027-01-15T11:59:58+01:00',
      'sha256': null,
    }, auth: false, headers: {'Authorization': 'Bearer $uploadToken'})); // 200
    // the client: see /v2/docs/dart
    // the target's pfl_ token from the upload_logs command (LogUploadTarget.token) instead of the device's token – works unpaired too
    final logUpload = pr.LogUploadStatus.fromJson(await api.post('/log-uploads/7742/complete', {
      'parts': 3,
      'lines': 184210,
      'from': '2027-01-14T12:00:00+01:00',
      'to': '2027-01-15T11:59:58+01:00',
      'sha256': null,
    }, auth: false, headers: {'Authorization': 'Bearer $uploadToken'})); // 200
    // klient: viz /v2/docs/go
    // token cíle pfl_ z příkazu upload_logs (LogUploadTarget.token) místo tokenu zařízení – jde i bez párování
    res, err := api.Post(ctx, "/log-uploads/7742/complete", map[string]any{
    	"parts": 3,
    	"lines": 184210,
    	"from": "2027-01-14T12:00:00+01:00",
    	"to": "2027-01-15T11:59:58+01:00",
    	"sha256": nil,
    }, &profirest.RequestOptions{NoAuth: true, Header: http.Header{"Authorization": {"Bearer " + uploadToken}}})
    var logUpload model.LogUploadStatus // 200
    if err == nil {
    	err = res.Decode(&logUpload)
    }
    // the client: see /v2/docs/go
    // the target's pfl_ token from the upload_logs command (LogUploadTarget.token) instead of the device's token – works unpaired too
    res, err := api.Post(ctx, "/log-uploads/7742/complete", map[string]any{
    	"parts": 3,
    	"lines": 184210,
    	"from": "2027-01-14T12:00:00+01:00",
    	"to": "2027-01-15T11:59:58+01:00",
    	"sha256": nil,
    }, &profirest.RequestOptions{NoAuth: true, Header: http.Header{"Authorization": {"Bearer " + uploadToken}}})
    var logUpload model.LogUploadStatus // 200
    if err == nil {
    	err = res.Decode(&logUpload)
    }
    Příklad odpovědi 200Example answer 200
    {
      "id": "7742",
      "request_id": "3105",
      "status": "done",
      "parts_received": [
        1,
        2,
        3
      ],
      "parts_expected": 3,
      "bytes": 4718592,
      "from": "2027-01-14T12:00:00+01:00",
      "to": "2027-01-15T12:00:00+01:00",
      "detail": "full",
      "max_part_bytes": 4194304,
      "expires_at": "2027-01-16T12:00:35+01:00"
    }
  5. Co nejde, vzdejte

    Give up what cannot be served

    POST /log-uploads/{upload_id}/abort · abortLogUpload

    no_data (úložiště nesahá tak daleko), unsupported (stará verze), failed s message. Podpora vidí důvod u žádosti.

    no_data (the log store does not reach that far), unsupported (an old version), failed with a message. Support sees the reason at the request.

    curl "https://api.mujprofirest.cz/v2/log-uploads/7743/abort" \
      -H "Authorization: Bearer $UPLOAD_TOKEN" \
      -H "Content-Type: application/json" \
      -d '{
      "reason": "no_data",
      "message": "Úložiště začíná 15. 1. 06:10, žádaný začátek je 14. 1. 12:00."
    }'
    curl "https://api.mujprofirest.cz/v2/log-uploads/7743/abort" \
      -H "Authorization: Bearer $UPLOAD_TOKEN" \
      -H "Content-Type: application/json" \
      -d '{
      "reason": "no_data",
      "message": "Úložiště začíná 15. 1. 06:10, žádaný začátek je 14. 1. 12:00."
    }'
    // klient: viz /v2/docs/js
    // token cíle pfl_ z příkazu upload_logs (LogUploadTarget.token) místo tokenu zařízení – jde i bez párování
    const abortLogUpload = await api.post('/log-uploads/7743/abort', {
      reason: 'no_data',
      message: 'Úložiště začíná 15. 1. 06:10, žádaný začátek je 14. 1. 12:00.',
    }, { auth: false, headers: { Authorization: 'Bearer ' + uploadToken } }); // 200
    // the client: see /v2/docs/js
    // the target's pfl_ token from the upload_logs command (LogUploadTarget.token) instead of the device's token – works unpaired too
    const abortLogUpload = await api.post('/log-uploads/7743/abort', {
      reason: 'no_data',
      message: 'Úložiště začíná 15. 1. 06:10, žádaný začátek je 14. 1. 12:00.',
    }, { auth: false, headers: { Authorization: 'Bearer ' + uploadToken } }); // 200
    // klient: viz /v2/docs/typescript
    // token cíle pfl_ z příkazu upload_logs (LogUploadTarget.token) místo tokenu zařízení – jde i bez párování
    const abortLogUpload = await api.post('/log-uploads/7743/abort', {
      reason: 'no_data',
      message: 'Úložiště začíná 15. 1. 06:10, žádaný začátek je 14. 1. 12:00.',
    }, { auth: false, headers: { Authorization: 'Bearer ' + uploadToken } }); // 200 LogUploadStatus
    // the client: see /v2/docs/typescript
    // the target's pfl_ token from the upload_logs command (LogUploadTarget.token) instead of the device's token – works unpaired too
    const abortLogUpload = await api.post('/log-uploads/7743/abort', {
      reason: 'no_data',
      message: 'Úložiště začíná 15. 1. 06:10, žádaný začátek je 14. 1. 12:00.',
    }, { auth: false, headers: { Authorization: 'Bearer ' + uploadToken } }); // 200 LogUploadStatus
    // klient: viz /v2/docs/php
    // token cíle pfl_ z příkazu upload_logs (LogUploadTarget.token) místo tokenu zařízení – jde i bez párování
    $abortLogUpload = $api->post('/log-uploads/7743/abort', [
        'reason' => 'no_data',
        'message' => 'Úložiště začíná 15. 1. 06:10, žádaný začátek je 14. 1. 12:00.',
    ], ['auth' => false, 'headers' => ['Authorization' => 'Bearer ' . $uploadToken]]); // 200
    // the client: see /v2/docs/php
    // the target's pfl_ token from the upload_logs command (LogUploadTarget.token) instead of the device's token – works unpaired too
    $abortLogUpload = $api->post('/log-uploads/7743/abort', [
        'reason' => 'no_data',
        'message' => 'Úložiště začíná 15. 1. 06:10, žádaný začátek je 14. 1. 12:00.',
    ], ['auth' => false, 'headers' => ['Authorization' => 'Bearer ' . $uploadToken]]); // 200
    // klient: viz /v2/docs/java
    // volání blokuje – na Androidu z pracovního vlákna (Dispatchers.IO)
    // token cíle pfl_ z příkazu upload_logs (LogUploadTarget.token) místo tokenu zařízení – jde i bez párování
    LogUploadStatus abortLogUpload = api.post("/log-uploads/7743/abort", Json.parse("""
        {
          "reason": "no_data",
          "message": "Úložiště začíná 15. 1. 06:10, žádaný začátek je 14. 1. 12:00."
        }
        """), RequestOptions.builder().auth(false).header("Authorization", "Bearer " + uploadToken).build(), LogUploadStatus::fromJson); // 200
    // the client: see /v2/docs/java
    // the call blocks – on Android from a worker thread (Dispatchers.IO)
    // the target's pfl_ token from the upload_logs command (LogUploadTarget.token) instead of the device's token – works unpaired too
    LogUploadStatus abortLogUpload = api.post("/log-uploads/7743/abort", Json.parse("""
        {
          "reason": "no_data",
          "message": "Úložiště začíná 15. 1. 06:10, žádaný začátek je 14. 1. 12:00."
        }
        """), RequestOptions.builder().auth(false).header("Authorization", "Bearer " + uploadToken).build(), LogUploadStatus::fromJson); // 200
    // klient: viz /v2/docs/java
    // volání blokuje – na Androidu z pracovního vlákna (Dispatchers.IO)
    // token cíle pfl_ z příkazu upload_logs (LogUploadTarget.token) místo tokenu zařízení – jde i bez párování
    val abortLogUpload = api.post("/log-uploads/7743/abort", mapOf(
        "reason" to "no_data",
        "message" to "Úložiště začíná 15. 1. 06:10, žádaný začátek je 14. 1. 12:00.",
    ), RequestOptions.builder().auth(false).header("Authorization", "Bearer " + uploadToken).build(), LogUploadStatus::fromJson) // 200
    // the client: see /v2/docs/java
    // the call blocks – on Android from a worker thread (Dispatchers.IO)
    // the target's pfl_ token from the upload_logs command (LogUploadTarget.token) instead of the device's token – works unpaired too
    val abortLogUpload = api.post("/log-uploads/7743/abort", mapOf(
        "reason" to "no_data",
        "message" to "Úložiště začíná 15. 1. 06:10, žádaný začátek je 14. 1. 12:00.",
    ), RequestOptions.builder().auth(false).header("Authorization", "Bearer " + uploadToken).build(), LogUploadStatus::fromJson) // 200
    // klient: viz /v2/docs/csharp
    // token cíle pfl_ z příkazu upload_logs (LogUploadTarget.token) místo tokenu zařízení – jde i bez párování
    var abortLogUpload = await api.PostAsync<LogUploadStatus>("/log-uploads/7743/abort", new {
        reason = "no_data",
        message = "Úložiště začíná 15. 1. 06:10, žádaný začátek je 14. 1. 12:00.",
    }, new RequestOptions { Auth = false, Headers = new() { ["Authorization"] = "Bearer " + uploadToken } }); // 200
    // the client: see /v2/docs/csharp
    // the target's pfl_ token from the upload_logs command (LogUploadTarget.token) instead of the device's token – works unpaired too
    var abortLogUpload = await api.PostAsync<LogUploadStatus>("/log-uploads/7743/abort", new {
        reason = "no_data",
        message = "Úložiště začíná 15. 1. 06:10, žádaný začátek je 14. 1. 12:00.",
    }, new RequestOptions { Auth = false, Headers = new() { ["Authorization"] = "Bearer " + uploadToken } }); // 200
    # klient: viz /v2/docs/python
    # token cíle pfl_ z příkazu upload_logs (LogUploadTarget.token) místo tokenu zařízení – jde i bez párování
    abort_log_upload = api.post('/log-uploads/7743/abort', {
        'reason': 'no_data',
        'message': 'Úložiště začíná 15. 1. 06:10, žádaný začátek je 14. 1. 12:00.',
    }, auth=False, headers={'Authorization': 'Bearer ' + upload_token})  # 200
    # the client: see /v2/docs/python
    # the target's pfl_ token from the upload_logs command (LogUploadTarget.token) instead of the device's token – works unpaired too
    abort_log_upload = api.post('/log-uploads/7743/abort', {
        'reason': 'no_data',
        'message': 'Úložiště začíná 15. 1. 06:10, žádaný začátek je 14. 1. 12:00.',
    }, auth=False, headers={'Authorization': 'Bearer ' + upload_token})  # 200
    // klient: viz /v2/docs/swift
    // token cíle pfl_ z příkazu upload_logs (LogUploadTarget.token) místo tokenu zařízení – jde i bez párování
    let abortLogUpload: LogUploadStatus = try await api.post("/log-uploads/7743/abort", body: [
        "reason": "no_data",
        "message": "Úložiště začíná 15. 1. 06:10, žádaný začátek je 14. 1. 12:00.",
    ], options: .init(headers: ["Authorization": "Bearer \(uploadToken)"], auth: false)) // 200
    // the client: see /v2/docs/swift
    // the target's pfl_ token from the upload_logs command (LogUploadTarget.token) instead of the device's token – works unpaired too
    let abortLogUpload: LogUploadStatus = try await api.post("/log-uploads/7743/abort", body: [
        "reason": "no_data",
        "message": "Úložiště začíná 15. 1. 06:10, žádaný začátek je 14. 1. 12:00.",
    ], options: .init(headers: ["Authorization": "Bearer \(uploadToken)"], auth: false)) // 200
    // klient: viz /v2/docs/dart
    // token cíle pfl_ z příkazu upload_logs (LogUploadTarget.token) místo tokenu zařízení – jde i bez párování
    final abortLogUpload = pr.LogUploadStatus.fromJson(await api.post('/log-uploads/7743/abort', {
      'reason': 'no_data',
      'message': 'Úložiště začíná 15. 1. 06:10, žádaný začátek je 14. 1. 12:00.',
    }, auth: false, headers: {'Authorization': 'Bearer $uploadToken'})); // 200
    // the client: see /v2/docs/dart
    // the target's pfl_ token from the upload_logs command (LogUploadTarget.token) instead of the device's token – works unpaired too
    final abortLogUpload = pr.LogUploadStatus.fromJson(await api.post('/log-uploads/7743/abort', {
      'reason': 'no_data',
      'message': 'Úložiště začíná 15. 1. 06:10, žádaný začátek je 14. 1. 12:00.',
    }, auth: false, headers: {'Authorization': 'Bearer $uploadToken'})); // 200
    // klient: viz /v2/docs/go
    // token cíle pfl_ z příkazu upload_logs (LogUploadTarget.token) místo tokenu zařízení – jde i bez párování
    res, err := api.Post(ctx, "/log-uploads/7743/abort", map[string]any{
    	"reason": "no_data",
    	"message": "Úložiště začíná 15. 1. 06:10, žádaný začátek je 14. 1. 12:00.",
    }, &profirest.RequestOptions{NoAuth: true, Header: http.Header{"Authorization": {"Bearer " + uploadToken}}})
    var abortLogUpload model.LogUploadStatus // 200
    if err == nil {
    	err = res.Decode(&abortLogUpload)
    }
    // the client: see /v2/docs/go
    // the target's pfl_ token from the upload_logs command (LogUploadTarget.token) instead of the device's token – works unpaired too
    res, err := api.Post(ctx, "/log-uploads/7743/abort", map[string]any{
    	"reason": "no_data",
    	"message": "Úložiště začíná 15. 1. 06:10, žádaný začátek je 14. 1. 12:00.",
    }, &profirest.RequestOptions{NoAuth: true, Header: http.Header{"Authorization": {"Bearer " + uploadToken}}})
    var abortLogUpload model.LogUploadStatus // 200
    if err == nil {
    	err = res.Decode(&abortLogUpload)
    }
    Příklad odpovědi 200Example answer 200
    {
      "id": "7743",
      "request_id": "3105",
      "status": "no_data",
      "parts_received": [],
      "parts_expected": null,
      "bytes": 0,
      "from": "2027-01-14T12:00:00+01:00",
      "to": "2027-01-15T12:00:00+01:00",
      "detail": "full",
      "max_part_bytes": 4194304,
      "expires_at": "2027-01-16T12:00:35+01:00"
    }

Scénář

Scenario

Zákazníci, body a vouchery

Customers, points and vouchers

Partner s oprávněním customers:writeA partner with customers:write

Zákazník se pozná podle ověřeného telefonu – bez hesel. Body a vouchery pak platí v e-shopu i na pokladně.

A customer is known by a verified phone number – no passwords. Points and vouchers then work in the e-shop and at the register alike.

  1. Nový zákazník

    A new customer

    POST /customers · createCustomer

    Patří celému účtu, ne jedné provozovně. Stejný telefon podruhé vrátí 409 s existing_id.

    Belongs to the whole account, not to one restaurant. The same phone again returns 409 with existing_id.

    curl "https://api.mujprofirest.cz/v2/customers" \
      -H "Authorization: Bearer $ACCESS_TOKEN" \
      -H "Idempotency-Key: 01a318f0-a0c0-7881-8c62-365d5eae28e4" \
      -H "Content-Type: application/json" \
      -d '{
      "phone": "+420777123456",
      "name": "Jana Nováková",
      "email": "jana.novakova@example.cz",
      "external_id": "zakaznik-881",
      "metadata": {"newsletter": "ano"}
    }'
    curl "https://api.mujprofirest.cz/v2/customers" \
      -H "Authorization: Bearer $ACCESS_TOKEN" \
      -H "Idempotency-Key: 01a318f0-a0c0-7881-8c62-365d5eae28e4" \
      -H "Content-Type: application/json" \
      -d '{
      "phone": "+420777123456",
      "name": "Jana Nováková",
      "email": "jana.novakova@example.cz",
      "external_id": "zakaznik-881",
      "metadata": {"newsletter": "ano"}
    }'
    // klient: viz /v2/docs/js
    const customer = await api.post('/customers', {
      phone: '+420777123456',
      name: 'Jana Nováková',
      email: 'jana.novakova@example.cz',
      external_id: 'zakaznik-881',
      metadata: { newsletter: 'ano' },
    }); // 201
    // the client: see /v2/docs/js
    const customer = await api.post('/customers', {
      phone: '+420777123456',
      name: 'Jana Nováková',
      email: 'jana.novakova@example.cz',
      external_id: 'zakaznik-881',
      metadata: { newsletter: 'ano' },
    }); // 201
    // klient: viz /v2/docs/typescript
    const customer = await api.post('/customers', {
      phone: '+420777123456',
      name: 'Jana Nováková',
      email: 'jana.novakova@example.cz',
      external_id: 'zakaznik-881',
      metadata: { newsletter: 'ano' },
    }); // 201 Customer
    // the client: see /v2/docs/typescript
    const customer = await api.post('/customers', {
      phone: '+420777123456',
      name: 'Jana Nováková',
      email: 'jana.novakova@example.cz',
      external_id: 'zakaznik-881',
      metadata: { newsletter: 'ano' },
    }); // 201 Customer
    // klient: viz /v2/docs/php
    $customer = $api->post('/customers', [
        'phone' => '+420777123456',
        'name' => 'Jana Nováková',
        'email' => 'jana.novakova@example.cz',
        'external_id' => 'zakaznik-881',
        'metadata' => ['newsletter' => 'ano'],
    ]); // 201
    // the client: see /v2/docs/php
    $customer = $api->post('/customers', [
        'phone' => '+420777123456',
        'name' => 'Jana Nováková',
        'email' => 'jana.novakova@example.cz',
        'external_id' => 'zakaznik-881',
        'metadata' => ['newsletter' => 'ano'],
    ]); // 201
    // klient: viz /v2/docs/java
    // volání blokuje – na Androidu z pracovního vlákna (Dispatchers.IO)
    Customer customer = api.post("/customers", Json.parse("""
        {
          "phone": "+420777123456",
          "name": "Jana Nováková",
          "email": "jana.novakova@example.cz",
          "external_id": "zakaznik-881",
          "metadata": {"newsletter": "ano"}
        }
        """), Customer::fromJson); // 201
    // the client: see /v2/docs/java
    // the call blocks – on Android from a worker thread (Dispatchers.IO)
    Customer customer = api.post("/customers", Json.parse("""
        {
          "phone": "+420777123456",
          "name": "Jana Nováková",
          "email": "jana.novakova@example.cz",
          "external_id": "zakaznik-881",
          "metadata": {"newsletter": "ano"}
        }
        """), Customer::fromJson); // 201
    // klient: viz /v2/docs/java
    // volání blokuje – na Androidu z pracovního vlákna (Dispatchers.IO)
    val customer = api.post("/customers", mapOf(
        "phone" to "+420777123456",
        "name" to "Jana Nováková",
        "email" to "jana.novakova@example.cz",
        "external_id" to "zakaznik-881",
        "metadata" to mapOf("newsletter" to "ano"),
    ), Customer::fromJson) // 201
    // the client: see /v2/docs/java
    // the call blocks – on Android from a worker thread (Dispatchers.IO)
    val customer = api.post("/customers", mapOf(
        "phone" to "+420777123456",
        "name" to "Jana Nováková",
        "email" to "jana.novakova@example.cz",
        "external_id" to "zakaznik-881",
        "metadata" to mapOf("newsletter" to "ano"),
    ), Customer::fromJson) // 201
    // klient: viz /v2/docs/csharp
    var customer = await api.PostAsync<Customer>("/customers", new {
        phone = "+420777123456",
        name = "Jana Nováková",
        email = "jana.novakova@example.cz",
        external_id = "zakaznik-881",
        metadata = new { newsletter = "ano" },
    }); // 201
    // the client: see /v2/docs/csharp
    var customer = await api.PostAsync<Customer>("/customers", new {
        phone = "+420777123456",
        name = "Jana Nováková",
        email = "jana.novakova@example.cz",
        external_id = "zakaznik-881",
        metadata = new { newsletter = "ano" },
    }); // 201
    # klient: viz /v2/docs/python
    customer = api.post('/customers', {
        'phone': '+420777123456',
        'name': 'Jana Nováková',
        'email': 'jana.novakova@example.cz',
        'external_id': 'zakaznik-881',
        'metadata': {'newsletter': 'ano'},
    })  # 201
    # the client: see /v2/docs/python
    customer = api.post('/customers', {
        'phone': '+420777123456',
        'name': 'Jana Nováková',
        'email': 'jana.novakova@example.cz',
        'external_id': 'zakaznik-881',
        'metadata': {'newsletter': 'ano'},
    })  # 201
    // klient: viz /v2/docs/swift
    let customer: Customer = try await api.post("/customers", body: [
        "phone": "+420777123456",
        "name": "Jana Nováková",
        "email": "jana.novakova@example.cz",
        "external_id": "zakaznik-881",
        "metadata": ["newsletter": "ano"],
    ]) // 201
    // the client: see /v2/docs/swift
    let customer: Customer = try await api.post("/customers", body: [
        "phone": "+420777123456",
        "name": "Jana Nováková",
        "email": "jana.novakova@example.cz",
        "external_id": "zakaznik-881",
        "metadata": ["newsletter": "ano"],
    ]) // 201
    // klient: viz /v2/docs/dart
    final customer = pr.Customer.fromJson(await api.post('/customers', {
      'phone': '+420777123456',
      'name': 'Jana Nováková',
      'email': 'jana.novakova@example.cz',
      'external_id': 'zakaznik-881',
      'metadata': {'newsletter': 'ano'},
    })); // 201
    // the client: see /v2/docs/dart
    final customer = pr.Customer.fromJson(await api.post('/customers', {
      'phone': '+420777123456',
      'name': 'Jana Nováková',
      'email': 'jana.novakova@example.cz',
      'external_id': 'zakaznik-881',
      'metadata': {'newsletter': 'ano'},
    })); // 201
    // klient: viz /v2/docs/go
    res, err := api.Post(ctx, "/customers", map[string]any{
    	"phone": "+420777123456",
    	"name": "Jana Nováková",
    	"email": "jana.novakova@example.cz",
    	"external_id": "zakaznik-881",
    	"metadata": map[string]any{"newsletter": "ano"},
    }, nil)
    var customer model.Customer // 201
    if err == nil {
    	err = res.Decode(&customer)
    }
    // the client: see /v2/docs/go
    res, err := api.Post(ctx, "/customers", map[string]any{
    	"phone": "+420777123456",
    	"name": "Jana Nováková",
    	"email": "jana.novakova@example.cz",
    	"external_id": "zakaznik-881",
    	"metadata": map[string]any{"newsletter": "ano"},
    }, nil)
    var customer model.Customer // 201
    if err == nil {
    	err = res.Decode(&customer)
    }
    Příklad odpovědi 201Example answer 201
    {
      "id": "90321",
      "phone": "+420777123456",
      "name": "Jana Nováková",
      "email": "jana.novakova@example.cz",
      "phone_verified": false,
      "created_at": "2027-01-15T11:40:12+01:00",
      "external_id": "zakaznik-881",
      "metadata": {
        "newsletter": "ano"
      }
    }
  2. Ověřovací SMS

    A verification SMS

    POST /customers/{customer_id}/phone-verification · startPhoneVerification

    Šest číslic SMS; znovu poslat jde až po resend_after.

    Six digits by SMS; sending again works only after resend_after.

    curl -X POST "https://api.mujprofirest.cz/v2/customers/90321/phone-verification" \
      -H "Authorization: Bearer $ACCESS_TOKEN" \
      -H "Idempotency-Key: 01a318f0-a0c0-76ba-b77b-97ea44c8e4ec"
    curl -X POST "https://api.mujprofirest.cz/v2/customers/90321/phone-verification" \
      -H "Authorization: Bearer $ACCESS_TOKEN" \
      -H "Idempotency-Key: 01a318f0-a0c0-76ba-b77b-97ea44c8e4ec"
    // klient: viz /v2/docs/js
    const phoneVerification = await api.post('/customers/90321/phone-verification', null); // 201
    // the client: see /v2/docs/js
    const phoneVerification = await api.post('/customers/90321/phone-verification', null); // 201
    // klient: viz /v2/docs/typescript
    const phoneVerification = await api.post('/customers/90321/phone-verification', null); // 201 PhoneVerification
    // the client: see /v2/docs/typescript
    const phoneVerification = await api.post('/customers/90321/phone-verification', null); // 201 PhoneVerification
    // klient: viz /v2/docs/php
    $phoneVerification = $api->post('/customers/90321/phone-verification', null); // 201
    // the client: see /v2/docs/php
    $phoneVerification = $api->post('/customers/90321/phone-verification', null); // 201
    // klient: viz /v2/docs/java
    // volání blokuje – na Androidu z pracovního vlákna (Dispatchers.IO)
    PhoneVerification phoneVerification = api.post("/customers/90321/phone-verification", null, PhoneVerification::fromJson); // 201
    // the client: see /v2/docs/java
    // the call blocks – on Android from a worker thread (Dispatchers.IO)
    PhoneVerification phoneVerification = api.post("/customers/90321/phone-verification", null, PhoneVerification::fromJson); // 201
    // klient: viz /v2/docs/java
    // volání blokuje – na Androidu z pracovního vlákna (Dispatchers.IO)
    val phoneVerification = api.post("/customers/90321/phone-verification", null, PhoneVerification::fromJson) // 201
    // the client: see /v2/docs/java
    // the call blocks – on Android from a worker thread (Dispatchers.IO)
    val phoneVerification = api.post("/customers/90321/phone-verification", null, PhoneVerification::fromJson) // 201
    // klient: viz /v2/docs/csharp
    var phoneVerification = await api.PostAsync<PhoneVerification>("/customers/90321/phone-verification", (object?)null); // 201
    // the client: see /v2/docs/csharp
    var phoneVerification = await api.PostAsync<PhoneVerification>("/customers/90321/phone-verification", (object?)null); // 201
    # klient: viz /v2/docs/python
    phone_verification = api.post('/customers/90321/phone-verification', None)  # 201
    # the client: see /v2/docs/python
    phone_verification = api.post('/customers/90321/phone-verification', None)  # 201
    // klient: viz /v2/docs/swift
    let phoneVerification: PhoneVerification = try await api.post("/customers/90321/phone-verification", body: nil) // 201
    // the client: see /v2/docs/swift
    let phoneVerification: PhoneVerification = try await api.post("/customers/90321/phone-verification", body: nil) // 201
    // klient: viz /v2/docs/dart
    final phoneVerification = pr.PhoneVerification.fromJson(await api.post('/customers/90321/phone-verification', null)); // 201
    // the client: see /v2/docs/dart
    final phoneVerification = pr.PhoneVerification.fromJson(await api.post('/customers/90321/phone-verification', null)); // 201
    // klient: viz /v2/docs/go
    res, err := api.Post(ctx, "/customers/90321/phone-verification", nil, nil)
    var phoneVerification model.PhoneVerification // 201
    if err == nil {
    	err = res.Decode(&phoneVerification)
    }
    // the client: see /v2/docs/go
    res, err := api.Post(ctx, "/customers/90321/phone-verification", nil, nil)
    var phoneVerification model.PhoneVerification // 201
    if err == nil {
    	err = res.Decode(&phoneVerification)
    }
    Příklad odpovědi 201Example answer 201
    {
      "id": "7731",
      "expires_at": "2027-01-15T11:52:00+01:00",
      "resend_after": "2027-01-15T11:43:00+01:00"
    }
  3. Potvrzení kódu

    Confirming the code

    POST /customers/{customer_id}/phone-verification/confirm · confirmPhoneVerification

    Teprve ověřený zákazník sbírá body a smí je uplatnit.

    Only a verified customer collects and redeems points.

    curl "https://api.mujprofirest.cz/v2/customers/90321/phone-verification/confirm" \
      -H "Authorization: Bearer $ACCESS_TOKEN" \
      -H "Idempotency-Key: 01a318f0-a0c0-7fd7-98d5-af2f103c0a77" \
      -H "Content-Type: application/json" \
      -d '{"code": "482913"}'
    curl "https://api.mujprofirest.cz/v2/customers/90321/phone-verification/confirm" \
      -H "Authorization: Bearer $ACCESS_TOKEN" \
      -H "Idempotency-Key: 01a318f0-a0c0-7fd7-98d5-af2f103c0a77" \
      -H "Content-Type: application/json" \
      -d '{"code": "482913"}'
    // klient: viz /v2/docs/js
    const phoneVerification = await api.post('/customers/90321/phone-verification/confirm', { code: '482913' }); // 200
    // the client: see /v2/docs/js
    const phoneVerification = await api.post('/customers/90321/phone-verification/confirm', { code: '482913' }); // 200
    // klient: viz /v2/docs/typescript
    const phoneVerification = await api.post('/customers/90321/phone-verification/confirm', { code: '482913' }); // 200 Customer
    // the client: see /v2/docs/typescript
    const phoneVerification = await api.post('/customers/90321/phone-verification/confirm', { code: '482913' }); // 200 Customer
    // klient: viz /v2/docs/php
    $phoneVerification = $api->post('/customers/90321/phone-verification/confirm', ['code' => '482913']); // 200
    // the client: see /v2/docs/php
    $phoneVerification = $api->post('/customers/90321/phone-verification/confirm', ['code' => '482913']); // 200
    // klient: viz /v2/docs/java
    // volání blokuje – na Androidu z pracovního vlákna (Dispatchers.IO)
    Customer phoneVerification = api.post("/customers/90321/phone-verification/confirm", Json.parse("""
        {"code": "482913"}
        """), Customer::fromJson); // 200
    // the client: see /v2/docs/java
    // the call blocks – on Android from a worker thread (Dispatchers.IO)
    Customer phoneVerification = api.post("/customers/90321/phone-verification/confirm", Json.parse("""
        {"code": "482913"}
        """), Customer::fromJson); // 200
    // klient: viz /v2/docs/java
    // volání blokuje – na Androidu z pracovního vlákna (Dispatchers.IO)
    val phoneVerification = api.post(
        "/customers/90321/phone-verification/confirm",
        mapOf("code" to "482913"),
        Customer::fromJson,
    ) // 200
    // the client: see /v2/docs/java
    // the call blocks – on Android from a worker thread (Dispatchers.IO)
    val phoneVerification = api.post(
        "/customers/90321/phone-verification/confirm",
        mapOf("code" to "482913"),
        Customer::fromJson,
    ) // 200
    // klient: viz /v2/docs/csharp
    var phoneVerification = await api.PostAsync<Customer>("/customers/90321/phone-verification/confirm", new { code = "482913" }); // 200
    // the client: see /v2/docs/csharp
    var phoneVerification = await api.PostAsync<Customer>("/customers/90321/phone-verification/confirm", new { code = "482913" }); // 200
    # klient: viz /v2/docs/python
    phone_verification = api.post('/customers/90321/phone-verification/confirm', {'code': '482913'})  # 200
    # the client: see /v2/docs/python
    phone_verification = api.post('/customers/90321/phone-verification/confirm', {'code': '482913'})  # 200
    // klient: viz /v2/docs/swift
    let phoneVerification: Customer = try await api.post("/customers/90321/phone-verification/confirm", body: ["code": "482913"]) // 200
    // the client: see /v2/docs/swift
    let phoneVerification: Customer = try await api.post("/customers/90321/phone-verification/confirm", body: ["code": "482913"]) // 200
    // klient: viz /v2/docs/dart
    final phoneVerification = pr.Customer.fromJson(await api.post('/customers/90321/phone-verification/confirm', {'code': '482913'})); // 200
    // the client: see /v2/docs/dart
    final phoneVerification = pr.Customer.fromJson(await api.post('/customers/90321/phone-verification/confirm', {'code': '482913'})); // 200
    // klient: viz /v2/docs/go
    res, err := api.Post(ctx, "/customers/90321/phone-verification/confirm", map[string]any{"code": "482913"}, nil)
    var phoneVerification model.Customer // 200
    if err == nil {
    	err = res.Decode(&phoneVerification)
    }
    // the client: see /v2/docs/go
    res, err := api.Post(ctx, "/customers/90321/phone-verification/confirm", map[string]any{"code": "482913"}, nil)
    var phoneVerification model.Customer // 200
    if err == nil {
    	err = res.Decode(&phoneVerification)
    }
    Příklad odpovědi 200Example answer 200
    {
      "id": "90321",
      "phone": "+420777123456",
      "name": "Jana Nováková",
      "email": "jana.novakova@example.cz",
      "phone_verified": true,
      "created_at": "2026-11-28T18:20:00+01:00",
      "external_id": "zakaznik-881",
      "metadata": {
        "newsletter": "ano"
      }
    }
  4. Věrnostní body

    Loyalty points

    GET /customers/{customer_id}/loyalty · getCustomerLoyalty

    Stav bodů a jejich hodnota v penězích.

    The points and their value in money.

    curl "https://api.mujprofirest.cz/v2/customers/90321/loyalty" \
      -H "Authorization: Bearer $ACCESS_TOKEN"
    curl "https://api.mujprofirest.cz/v2/customers/90321/loyalty" \
      -H "Authorization: Bearer $ACCESS_TOKEN"
    // klient: viz /v2/docs/js
    const customerLoyalty = await api.get('/customers/90321/loyalty'); // 200
    // the client: see /v2/docs/js
    const customerLoyalty = await api.get('/customers/90321/loyalty'); // 200
    // klient: viz /v2/docs/typescript
    const customerLoyalty = await api.get('/customers/90321/loyalty'); // 200 Loyalty
    // the client: see /v2/docs/typescript
    const customerLoyalty = await api.get('/customers/90321/loyalty'); // 200 Loyalty
    // klient: viz /v2/docs/php
    $customerLoyalty = $api->get('/customers/90321/loyalty'); // 200
    // the client: see /v2/docs/php
    $customerLoyalty = $api->get('/customers/90321/loyalty'); // 200
    // klient: viz /v2/docs/java
    // volání blokuje – na Androidu z pracovního vlákna (Dispatchers.IO)
    Loyalty customerLoyalty = api.get("/customers/90321/loyalty", Loyalty::fromJson); // 200
    // the client: see /v2/docs/java
    // the call blocks – on Android from a worker thread (Dispatchers.IO)
    Loyalty customerLoyalty = api.get("/customers/90321/loyalty", Loyalty::fromJson); // 200
    // klient: viz /v2/docs/java
    // volání blokuje – na Androidu z pracovního vlákna (Dispatchers.IO)
    val customerLoyalty = api.get("/customers/90321/loyalty", Loyalty::fromJson) // 200
    // the client: see /v2/docs/java
    // the call blocks – on Android from a worker thread (Dispatchers.IO)
    val customerLoyalty = api.get("/customers/90321/loyalty", Loyalty::fromJson) // 200
    // klient: viz /v2/docs/csharp
    var customerLoyalty = await api.GetAsync<Loyalty>("/customers/90321/loyalty"); // 200
    // the client: see /v2/docs/csharp
    var customerLoyalty = await api.GetAsync<Loyalty>("/customers/90321/loyalty"); // 200
    # klient: viz /v2/docs/python
    customer_loyalty = api.get('/customers/90321/loyalty')  # 200
    # the client: see /v2/docs/python
    customer_loyalty = api.get('/customers/90321/loyalty')  # 200
    // klient: viz /v2/docs/swift
    let customerLoyalty: Loyalty = try await api.get("/customers/90321/loyalty") // 200
    // the client: see /v2/docs/swift
    let customerLoyalty: Loyalty = try await api.get("/customers/90321/loyalty") // 200
    // klient: viz /v2/docs/dart
    final customerLoyalty = pr.Loyalty.fromJson(await api.get('/customers/90321/loyalty')); // 200
    // the client: see /v2/docs/dart
    final customerLoyalty = pr.Loyalty.fromJson(await api.get('/customers/90321/loyalty')); // 200
    // klient: viz /v2/docs/go
    res, err := api.Get(ctx, "/customers/90321/loyalty", nil)
    var customerLoyalty model.Loyalty // 200
    if err == nil {
    	err = res.Decode(&customerLoyalty)
    }
    // the client: see /v2/docs/go
    res, err := api.Get(ctx, "/customers/90321/loyalty", nil)
    var customerLoyalty model.Loyalty // 200
    if err == nil {
    	err = res.Decode(&customerLoyalty)
    }
    Příklad odpovědi 200Example answer 200
    {
      "customer_id": "90321",
      "points": 120,
      "points_value": {
        "amount": 12000,
        "currency": "CZK"
      },
      "redeemable": false
    }
  5. Dárkový voucher

    A gift voucher

    POST /restaurants/{restaurant_id}/vouchers/check · checkVoucher

    Zůstatek a platnost před zaplacením; samotné uplatnění je platba v nabídce (vouchers).

    The balance and validity before paying; redeeming it is a payment in the quote (vouchers).

    curl "https://api.mujprofirest.cz/v2/restaurants/123/vouchers/check" \
      -H "Authorization: Bearer $ACCESS_TOKEN" \
      -H "Idempotency-Key: 01a318f0-a0c0-792f-b84a-1627013a144c" \
      -H "Content-Type: application/json" \
      -d '{"code": "KX7-9QD"}'
    curl "https://api.mujprofirest.cz/v2/restaurants/123/vouchers/check" \
      -H "Authorization: Bearer $ACCESS_TOKEN" \
      -H "Idempotency-Key: 01a318f0-a0c0-792f-b84a-1627013a144c" \
      -H "Content-Type: application/json" \
      -d '{"code": "KX7-9QD"}'
    // klient: viz /v2/docs/js
    const voucher = await api.post('/restaurants/123/vouchers/check', { code: 'KX7-9QD' }); // 200
    // the client: see /v2/docs/js
    const voucher = await api.post('/restaurants/123/vouchers/check', { code: 'KX7-9QD' }); // 200
    // klient: viz /v2/docs/typescript
    const voucher = await api.post('/restaurants/123/vouchers/check', { code: 'KX7-9QD' }); // 200 Voucher
    // the client: see /v2/docs/typescript
    const voucher = await api.post('/restaurants/123/vouchers/check', { code: 'KX7-9QD' }); // 200 Voucher
    // klient: viz /v2/docs/php
    $voucher = $api->post('/restaurants/123/vouchers/check', ['code' => 'KX7-9QD']); // 200
    // the client: see /v2/docs/php
    $voucher = $api->post('/restaurants/123/vouchers/check', ['code' => 'KX7-9QD']); // 200
    // klient: viz /v2/docs/java
    // volání blokuje – na Androidu z pracovního vlákna (Dispatchers.IO)
    Voucher voucher = api.post("/restaurants/123/vouchers/check", Json.parse("""
        {"code": "KX7-9QD"}
        """), Voucher::fromJson); // 200
    // the client: see /v2/docs/java
    // the call blocks – on Android from a worker thread (Dispatchers.IO)
    Voucher voucher = api.post("/restaurants/123/vouchers/check", Json.parse("""
        {"code": "KX7-9QD"}
        """), Voucher::fromJson); // 200
    // klient: viz /v2/docs/java
    // volání blokuje – na Androidu z pracovního vlákna (Dispatchers.IO)
    val voucher = api.post("/restaurants/123/vouchers/check", mapOf("code" to "KX7-9QD"), Voucher::fromJson) // 200
    // the client: see /v2/docs/java
    // the call blocks – on Android from a worker thread (Dispatchers.IO)
    val voucher = api.post("/restaurants/123/vouchers/check", mapOf("code" to "KX7-9QD"), Voucher::fromJson) // 200
    // klient: viz /v2/docs/csharp
    var voucher = await api.PostAsync<Voucher>("/restaurants/123/vouchers/check", new { code = "KX7-9QD" }); // 200
    // the client: see /v2/docs/csharp
    var voucher = await api.PostAsync<Voucher>("/restaurants/123/vouchers/check", new { code = "KX7-9QD" }); // 200
    # klient: viz /v2/docs/python
    voucher = api.post('/restaurants/123/vouchers/check', {'code': 'KX7-9QD'})  # 200
    # the client: see /v2/docs/python
    voucher = api.post('/restaurants/123/vouchers/check', {'code': 'KX7-9QD'})  # 200
    // klient: viz /v2/docs/swift
    let voucher: Voucher = try await api.post("/restaurants/123/vouchers/check", body: ["code": "KX7-9QD"]) // 200
    // the client: see /v2/docs/swift
    let voucher: Voucher = try await api.post("/restaurants/123/vouchers/check", body: ["code": "KX7-9QD"]) // 200
    // klient: viz /v2/docs/dart
    final voucher = pr.Voucher.fromJson(await api.post('/restaurants/123/vouchers/check', {'code': 'KX7-9QD'})); // 200
    // the client: see /v2/docs/dart
    final voucher = pr.Voucher.fromJson(await api.post('/restaurants/123/vouchers/check', {'code': 'KX7-9QD'})); // 200
    // klient: viz /v2/docs/go
    res, err := api.Post(ctx, "/restaurants/123/vouchers/check", map[string]any{"code": "KX7-9QD"}, nil)
    var voucher model.Voucher // 200
    if err == nil {
    	err = res.Decode(&voucher)
    }
    // the client: see /v2/docs/go
    res, err := api.Post(ctx, "/restaurants/123/vouchers/check", map[string]any{"code": "KX7-9QD"}, nil)
    var voucher model.Voucher // 200
    if err == nil {
    	err = res.Decode(&voucher)
    }
    Příklad odpovědi 200Example answer 200
    {
      "code": "KX7-***",
      "status": "active",
      "value": {
        "amount": 50000,
        "currency": "CZK"
      },
      "balance": {
        "amount": 30000,
        "currency": "CZK"
      },
      "valid_until": "2027-06-30",
      "partial_redemption": true,
      "accepted_here": true
    }

Scénář

Scenario

Rezervace stolů a služeb

Reservations of tables and services

Rezervační platforma, web provozovny, aplikace obsluhy (reservations:read, reservations:write)A booking platform, the restaurant's website, an application of the staff (reservations:read, reservations:write)

Host si vybere den, počet osob nebo službu a volný čas, vy rezervaci založíte a server ohlídá kapacitu – stůl, pracovník ani místnost nejsou nikdy rezervované dvakrát. Změny z administrace a pokladen vám chodí jako události.

The guest picks a day, the size of the party or a service and a free time, you create the reservation and the server keeps the capacity – a table, an employee or a room is never booked twice. Changes made in the administration and at the registers come to you as events.

  1. Pravidla provozovny

    The rules of the restaurant

    GET /restaurants/{restaurant_id}/reservation-settings · getReservationSettings

    Jestli přijímá online rezervace, jak dlouho se sedí, jak daleko dopředu a největší skupinu. Bez licence rezervací vrací operace module_not_licensed.

    Whether it takes online reservations, how long guests sit, how far ahead and the biggest party. Without the reservation licence the operations answer module_not_licensed.

    curl "https://api.mujprofirest.cz/v2/restaurants/123/reservation-settings" \
      -H "Authorization: Bearer $ACCESS_TOKEN"
    curl "https://api.mujprofirest.cz/v2/restaurants/123/reservation-settings" \
      -H "Authorization: Bearer $ACCESS_TOKEN"
    // klient: viz /v2/docs/js
    const reservationSettings = await api.get('/restaurants/123/reservation-settings'); // 200
    // the client: see /v2/docs/js
    const reservationSettings = await api.get('/restaurants/123/reservation-settings'); // 200
    // klient: viz /v2/docs/typescript
    const reservationSettings = await api.get('/restaurants/123/reservation-settings'); // 200 ReservationSettings
    // the client: see /v2/docs/typescript
    const reservationSettings = await api.get('/restaurants/123/reservation-settings'); // 200 ReservationSettings
    // klient: viz /v2/docs/php
    $reservationSettings = $api->get('/restaurants/123/reservation-settings'); // 200
    // the client: see /v2/docs/php
    $reservationSettings = $api->get('/restaurants/123/reservation-settings'); // 200
    // klient: viz /v2/docs/java
    // volání blokuje – na Androidu z pracovního vlákna (Dispatchers.IO)
    ReservationSettings reservationSettings = api.get("/restaurants/123/reservation-settings", ReservationSettings::fromJson); // 200
    // the client: see /v2/docs/java
    // the call blocks – on Android from a worker thread (Dispatchers.IO)
    ReservationSettings reservationSettings = api.get("/restaurants/123/reservation-settings", ReservationSettings::fromJson); // 200
    // klient: viz /v2/docs/java
    // volání blokuje – na Androidu z pracovního vlákna (Dispatchers.IO)
    val reservationSettings = api.get("/restaurants/123/reservation-settings", ReservationSettings::fromJson) // 200
    // the client: see /v2/docs/java
    // the call blocks – on Android from a worker thread (Dispatchers.IO)
    val reservationSettings = api.get("/restaurants/123/reservation-settings", ReservationSettings::fromJson) // 200
    // klient: viz /v2/docs/csharp
    var reservationSettings = await api.GetAsync<ReservationSettings>("/restaurants/123/reservation-settings"); // 200
    // the client: see /v2/docs/csharp
    var reservationSettings = await api.GetAsync<ReservationSettings>("/restaurants/123/reservation-settings"); // 200
    # klient: viz /v2/docs/python
    reservation_settings = api.get('/restaurants/123/reservation-settings')  # 200
    # the client: see /v2/docs/python
    reservation_settings = api.get('/restaurants/123/reservation-settings')  # 200
    // klient: viz /v2/docs/swift
    let reservationSettings: ReservationSettings = try await api.get("/restaurants/123/reservation-settings") // 200
    // the client: see /v2/docs/swift
    let reservationSettings: ReservationSettings = try await api.get("/restaurants/123/reservation-settings") // 200
    // klient: viz /v2/docs/dart
    final reservationSettings = pr.ReservationSettings.fromJson(await api.get('/restaurants/123/reservation-settings')); // 200
    // the client: see /v2/docs/dart
    final reservationSettings = pr.ReservationSettings.fromJson(await api.get('/restaurants/123/reservation-settings')); // 200
    // klient: viz /v2/docs/go
    res, err := api.Get(ctx, "/restaurants/123/reservation-settings", nil)
    var reservationSettings model.ReservationSettings // 200
    if err == nil {
    	err = res.Decode(&reservationSettings)
    }
    // the client: see /v2/docs/go
    res, err := api.Get(ctx, "/restaurants/123/reservation-settings", nil)
    var reservationSettings model.ReservationSettings // 200
    if err == nil {
    	err = res.Decode(&reservationSettings)
    }
    Příklad odpovědi 200Example answer 200
    {
      "slot_step_minutes": 15,
      "table_durations": [
        {
          "up_to_party_size": 2,
          "minutes": 90
        },
        {
          "up_to_party_size": 4,
          "minutes": 120
        },
        {
          "up_to_party_size": 99,
          "minutes": 150
        }
      ],
      "table_buffer_minutes": 15,
      "last_seating_before_close_minutes": 30,
      "use_opening_hours": true,
      "max_guests_per_slot": 12,
      "closed_dates": [
        "2027-02-14"
      ],
      "online": {
        "enabled": true,
        "confirmation": "auto",
        "confirm_within_minutes": 120,
        "lead_minutes": 60,
        "horizon_days": 60,
        "max_party_size": 8,
        "guest_cancel_hours": 2
      },
      "services_enabled": true,
      "deposit": {
        "mode": "from_party",
        "available": true,
        "from_party_size": 6,
        "per_person": {
          "amount": 20000,
          "currency": "CZK"
        },
        "per_reservation": {
          "amount": 0,
          "currency": "CZK"
        },
        "service_percent": 50,
        "pay_within_minutes": 60,
        "refund_until_hours": 24,
        "no_show_guests": true
      },
      "reminders": {
        "email_hours": 24,
        "sms_hours": 3
      },
      "feedback_enabled": true,
      "guest_max_moves": 3
    }
  2. Služby (salon, wellness)

    Services (salon, wellness)

    GET /restaurants/{restaurant_id}/reservation-services · listReservationServices

    Délka, cena a pracovníci každé služby. U restaurace bez služeb prázdné.

    Length, price and employees of every service. Empty for a restaurant without services.

    curl "https://api.mujprofirest.cz/v2/restaurants/123/reservation-services" \
      -H "Authorization: Bearer $ACCESS_TOKEN"
    curl "https://api.mujprofirest.cz/v2/restaurants/123/reservation-services" \
      -H "Authorization: Bearer $ACCESS_TOKEN"
    // klient: viz /v2/docs/js
    const listReservationServices = await api.get('/restaurants/123/reservation-services'); // 200
    // the client: see /v2/docs/js
    const listReservationServices = await api.get('/restaurants/123/reservation-services'); // 200
    // klient: viz /v2/docs/typescript
    const listReservationServices = await api.get('/restaurants/123/reservation-services'); // 200 ReservationServiceList
    // the client: see /v2/docs/typescript
    const listReservationServices = await api.get('/restaurants/123/reservation-services'); // 200 ReservationServiceList
    // klient: viz /v2/docs/php
    $listReservationServices = $api->get('/restaurants/123/reservation-services'); // 200
    // the client: see /v2/docs/php
    $listReservationServices = $api->get('/restaurants/123/reservation-services'); // 200
    // klient: viz /v2/docs/java
    // volání blokuje – na Androidu z pracovního vlákna (Dispatchers.IO)
    ReservationServiceList listReservationServices = api.get("/restaurants/123/reservation-services", ReservationServiceList::fromJson); // 200
    // the client: see /v2/docs/java
    // the call blocks – on Android from a worker thread (Dispatchers.IO)
    ReservationServiceList listReservationServices = api.get("/restaurants/123/reservation-services", ReservationServiceList::fromJson); // 200
    // klient: viz /v2/docs/java
    // volání blokuje – na Androidu z pracovního vlákna (Dispatchers.IO)
    val listReservationServices = api.get("/restaurants/123/reservation-services", ReservationServiceList::fromJson) // 200
    // the client: see /v2/docs/java
    // the call blocks – on Android from a worker thread (Dispatchers.IO)
    val listReservationServices = api.get("/restaurants/123/reservation-services", ReservationServiceList::fromJson) // 200
    // klient: viz /v2/docs/csharp
    var listReservationServices = await api.GetAsync<ReservationServiceList>("/restaurants/123/reservation-services"); // 200
    // the client: see /v2/docs/csharp
    var listReservationServices = await api.GetAsync<ReservationServiceList>("/restaurants/123/reservation-services"); // 200
    # klient: viz /v2/docs/python
    list_reservation_services = api.get('/restaurants/123/reservation-services')  # 200
    # the client: see /v2/docs/python
    list_reservation_services = api.get('/restaurants/123/reservation-services')  # 200
    // klient: viz /v2/docs/swift
    let listReservationServices: ReservationServiceList = try await api.get("/restaurants/123/reservation-services") // 200
    // the client: see /v2/docs/swift
    let listReservationServices: ReservationServiceList = try await api.get("/restaurants/123/reservation-services") // 200
    // klient: viz /v2/docs/dart
    final listReservationServices = pr.ReservationServiceList.fromJson(await api.get('/restaurants/123/reservation-services')); // 200
    // the client: see /v2/docs/dart
    final listReservationServices = pr.ReservationServiceList.fromJson(await api.get('/restaurants/123/reservation-services')); // 200
    // klient: viz /v2/docs/go
    res, err := api.Get(ctx, "/restaurants/123/reservation-services", nil)
    var listReservationServices model.ReservationServiceList // 200
    if err == nil {
    	err = res.Decode(&listReservationServices)
    }
    // the client: see /v2/docs/go
    res, err := api.Get(ctx, "/restaurants/123/reservation-services", nil)
    var listReservationServices model.ReservationServiceList // 200
    if err == nil {
    	err = res.Decode(&listReservationServices)
    }
    Příklad odpovědi 200Example answer 200
    {
      "data": [
        {
          "id": "12",
          "name": "Pánský střih",
          "category": "Vlasy",
          "description": null,
          "duration_minutes": 30,
          "buffer_minutes": 10,
          "price": {
            "amount": 45000,
            "currency": "CZK"
          },
          "max_party_size": 1,
          "online": true,
          "staff": [
            {
              "id": "58",
              "name": "Jana Dvořáková"
            },
            {
              "id": "61",
              "name": "Petr Novák"
            }
          ]
        }
      ]
    }
  3. Volné časy dne

    Free times of a day

    GET /restaurants/{restaurant_id}/reservation-availability · getReservationAvailability

    Nabídněte jen časy s available. Čas se pro vás nedrží – rezervaci založte hned po výběru.

    Offer only times with available. A time is not held for you – create the reservation right after the choice.

    curl "https://api.mujprofirest.cz/v2/restaurants/123/reservation-availability?date=2027-01-15&party_size=4" \
      -H "Authorization: Bearer $ACCESS_TOKEN"
    curl "https://api.mujprofirest.cz/v2/restaurants/123/reservation-availability?date=2027-01-15&party_size=4" \
      -H "Authorization: Bearer $ACCESS_TOKEN"
    // klient: viz /v2/docs/js
    const reservationAvailability = await api.get(
      '/restaurants/123/reservation-availability',
      { query: { date: '2027-01-15', party_size: '4' } },
    ); // 200
    // the client: see /v2/docs/js
    const reservationAvailability = await api.get(
      '/restaurants/123/reservation-availability',
      { query: { date: '2027-01-15', party_size: '4' } },
    ); // 200
    // klient: viz /v2/docs/typescript
    const reservationAvailability = await api.get(
      '/restaurants/123/reservation-availability',
      { query: { date: '2027-01-15', party_size: '4' } },
    ); // 200 ReservationAvailability
    // the client: see /v2/docs/typescript
    const reservationAvailability = await api.get(
      '/restaurants/123/reservation-availability',
      { query: { date: '2027-01-15', party_size: '4' } },
    ); // 200 ReservationAvailability
    // klient: viz /v2/docs/php
    $reservationAvailability = $api->get(
        '/restaurants/123/reservation-availability',
        ['query' => ['date' => '2027-01-15', 'party_size' => '4']],
    ); // 200
    // the client: see /v2/docs/php
    $reservationAvailability = $api->get(
        '/restaurants/123/reservation-availability',
        ['query' => ['date' => '2027-01-15', 'party_size' => '4']],
    ); // 200
    // klient: viz /v2/docs/java
    // volání blokuje – na Androidu z pracovního vlákna (Dispatchers.IO)
    ReservationAvailability reservationAvailability = api.get(
        "/restaurants/123/reservation-availability",
        RequestOptions.builder().query("date", "2027-01-15").query("party_size", "4").build(),
        ReservationAvailability::fromJson
    ); // 200
    // the client: see /v2/docs/java
    // the call blocks – on Android from a worker thread (Dispatchers.IO)
    ReservationAvailability reservationAvailability = api.get(
        "/restaurants/123/reservation-availability",
        RequestOptions.builder().query("date", "2027-01-15").query("party_size", "4").build(),
        ReservationAvailability::fromJson
    ); // 200
    // klient: viz /v2/docs/java
    // volání blokuje – na Androidu z pracovního vlákna (Dispatchers.IO)
    val reservationAvailability = api.get(
        "/restaurants/123/reservation-availability",
        RequestOptions.builder().query("date", "2027-01-15").query("party_size", "4").build(),
        ReservationAvailability::fromJson,
    ) // 200
    // the client: see /v2/docs/java
    // the call blocks – on Android from a worker thread (Dispatchers.IO)
    val reservationAvailability = api.get(
        "/restaurants/123/reservation-availability",
        RequestOptions.builder().query("date", "2027-01-15").query("party_size", "4").build(),
        ReservationAvailability::fromJson,
    ) // 200
    // klient: viz /v2/docs/csharp
    var reservationAvailability = await api.GetAsync<ReservationAvailability>(
        "/restaurants/123/reservation-availability",
        new RequestOptions { Query = new() { ["date"] = "2027-01-15", ["party_size"] = "4" } }
    ); // 200
    // the client: see /v2/docs/csharp
    var reservationAvailability = await api.GetAsync<ReservationAvailability>(
        "/restaurants/123/reservation-availability",
        new RequestOptions { Query = new() { ["date"] = "2027-01-15", ["party_size"] = "4" } }
    ); // 200
    # klient: viz /v2/docs/python
    reservation_availability = api.get(
        '/restaurants/123/reservation-availability',
        query={'date': '2027-01-15', 'party_size': '4'},
    )  # 200
    # the client: see /v2/docs/python
    reservation_availability = api.get(
        '/restaurants/123/reservation-availability',
        query={'date': '2027-01-15', 'party_size': '4'},
    )  # 200
    // klient: viz /v2/docs/swift
    let reservationAvailability: ReservationAvailability = try await api.get(
        "/restaurants/123/reservation-availability",
        options: .init(query: ["date": "2027-01-15", "party_size": "4"])
    ) // 200
    // the client: see /v2/docs/swift
    let reservationAvailability: ReservationAvailability = try await api.get(
        "/restaurants/123/reservation-availability",
        options: .init(query: ["date": "2027-01-15", "party_size": "4"])
    ) // 200
    // klient: viz /v2/docs/dart
    final reservationAvailability = pr.ReservationAvailability.fromJson(await api.get(
      '/restaurants/123/reservation-availability',
      query: {'date': '2027-01-15', 'party_size': '4'},
    )); // 200
    // the client: see /v2/docs/dart
    final reservationAvailability = pr.ReservationAvailability.fromJson(await api.get(
      '/restaurants/123/reservation-availability',
      query: {'date': '2027-01-15', 'party_size': '4'},
    )); // 200
    // klient: viz /v2/docs/go
    res, err := api.Get(
    	ctx,
    	"/restaurants/123/reservation-availability",
    	&profirest.RequestOptions{Query: map[string]any{"date": "2027-01-15", "party_size": "4"}},
    )
    var reservationAvailability model.ReservationAvailability // 200
    if err == nil {
    	err = res.Decode(&reservationAvailability)
    }
    // the client: see /v2/docs/go
    res, err := api.Get(
    	ctx,
    	"/restaurants/123/reservation-availability",
    	&profirest.RequestOptions{Query: map[string]any{"date": "2027-01-15", "party_size": "4"}},
    )
    var reservationAvailability model.ReservationAvailability // 200
    if err == nil {
    	err = res.Decode(&reservationAvailability)
    }
    Příklad odpovědi 200Example answer 200
    {
      "date": "2027-01-15",
      "slots": [
        {
          "starts_at": "2027-01-15T18:45:00+01:00",
          "available": true,
          "reason": null,
          "table_ids": [
            "7"
          ],
          "employee_id": null
        },
        {
          "starts_at": "2027-01-15T19:00:00+01:00",
          "available": true,
          "reason": null,
          "table_ids": [
            "4"
          ],
          "employee_id": null
        },
        {
          "starts_at": "2027-01-15T19:15:00+01:00",
          "available": false,
          "reason": "no_table",
          "table_ids": [],
          "employee_id": null
        }
      ]
    }
  4. Založení

    Creating it

    POST /restaurants/{restaurant_id}/reservations · createReservation

    S Idempotency-Key a ideálně vlastním uuid. Obsazený čas vrátí 409 reservation_unavailable – načtěte volné časy znovu a nabídněte jiný. Rezervace může být requested, když provozovna potvrzuje ručně nebo chce zálohu.

    With an Idempotency-Key and ideally your own uuid. A taken time answers 409 reservation_unavailable – load the free times again and offer another one. The reservation may be requested when the restaurant confirms by hand or wants a deposit.

    curl "https://api.mujprofirest.cz/v2/restaurants/123/reservations" \
      -H "Authorization: Bearer $ACCESS_TOKEN" \
      -H "Idempotency-Key: 01a318f0-a0c0-7e52-88f6-1277ae5c3ab5" \
      -H "Content-Type: application/json" \
      -d '{
      "uuid": "01a318f0-a0c0-7a44-8d8d-ba7e70efcfaf",
      "channel": "online",
      "kind": "table",
      "party_size": 4,
      "starts_at": "2027-01-15T19:00:00+01:00",
      "guest": {
        "name": "Jana Svobodová",
        "phone": "+420777123456",
        "email": "jana.svobodova@example.com"
      },
      "note_guest": "U okna, slavíme narozeniny"
    }'
    curl "https://api.mujprofirest.cz/v2/restaurants/123/reservations" \
      -H "Authorization: Bearer $ACCESS_TOKEN" \
      -H "Idempotency-Key: 01a318f0-a0c0-7e52-88f6-1277ae5c3ab5" \
      -H "Content-Type: application/json" \
      -d '{
      "uuid": "01a318f0-a0c0-7a44-8d8d-ba7e70efcfaf",
      "channel": "online",
      "kind": "table",
      "party_size": 4,
      "starts_at": "2027-01-15T19:00:00+01:00",
      "guest": {
        "name": "Jana Svobodová",
        "phone": "+420777123456",
        "email": "jana.svobodova@example.com"
      },
      "note_guest": "U okna, slavíme narozeniny"
    }'
    // klient: viz /v2/docs/js
    const reservation = await api.post('/restaurants/123/reservations', {
      uuid: '01a318f0-a0c0-7a44-8d8d-ba7e70efcfaf',
      channel: 'online',
      kind: 'table',
      party_size: 4,
      starts_at: '2027-01-15T19:00:00+01:00',
      guest: {
        name: 'Jana Svobodová',
        phone: '+420777123456',
        email: 'jana.svobodova@example.com',
      },
      note_guest: 'U okna, slavíme narozeniny',
    }); // 201
    // the client: see /v2/docs/js
    const reservation = await api.post('/restaurants/123/reservations', {
      uuid: '01a318f0-a0c0-7a44-8d8d-ba7e70efcfaf',
      channel: 'online',
      kind: 'table',
      party_size: 4,
      starts_at: '2027-01-15T19:00:00+01:00',
      guest: {
        name: 'Jana Svobodová',
        phone: '+420777123456',
        email: 'jana.svobodova@example.com',
      },
      note_guest: 'U okna, slavíme narozeniny',
    }); // 201
    // klient: viz /v2/docs/typescript
    const reservation = await api.post('/restaurants/123/reservations', {
      uuid: '01a318f0-a0c0-7a44-8d8d-ba7e70efcfaf',
      channel: 'online',
      kind: 'table',
      party_size: 4,
      starts_at: '2027-01-15T19:00:00+01:00',
      guest: {
        name: 'Jana Svobodová',
        phone: '+420777123456',
        email: 'jana.svobodova@example.com',
      },
      note_guest: 'U okna, slavíme narozeniny',
    }); // 201 Reservation
    // the client: see /v2/docs/typescript
    const reservation = await api.post('/restaurants/123/reservations', {
      uuid: '01a318f0-a0c0-7a44-8d8d-ba7e70efcfaf',
      channel: 'online',
      kind: 'table',
      party_size: 4,
      starts_at: '2027-01-15T19:00:00+01:00',
      guest: {
        name: 'Jana Svobodová',
        phone: '+420777123456',
        email: 'jana.svobodova@example.com',
      },
      note_guest: 'U okna, slavíme narozeniny',
    }); // 201 Reservation
    // klient: viz /v2/docs/php
    $reservation = $api->post('/restaurants/123/reservations', [
        'uuid' => '01a318f0-a0c0-7a44-8d8d-ba7e70efcfaf',
        'channel' => 'online',
        'kind' => 'table',
        'party_size' => 4,
        'starts_at' => '2027-01-15T19:00:00+01:00',
        'guest' => [
            'name' => 'Jana Svobodová',
            'phone' => '+420777123456',
            'email' => 'jana.svobodova@example.com',
        ],
        'note_guest' => 'U okna, slavíme narozeniny',
    ]); // 201
    // the client: see /v2/docs/php
    $reservation = $api->post('/restaurants/123/reservations', [
        'uuid' => '01a318f0-a0c0-7a44-8d8d-ba7e70efcfaf',
        'channel' => 'online',
        'kind' => 'table',
        'party_size' => 4,
        'starts_at' => '2027-01-15T19:00:00+01:00',
        'guest' => [
            'name' => 'Jana Svobodová',
            'phone' => '+420777123456',
            'email' => 'jana.svobodova@example.com',
        ],
        'note_guest' => 'U okna, slavíme narozeniny',
    ]); // 201
    // klient: viz /v2/docs/java
    // volání blokuje – na Androidu z pracovního vlákna (Dispatchers.IO)
    Reservation reservation = api.post("/restaurants/123/reservations", Json.parse("""
        {
          "uuid": "01a318f0-a0c0-7a44-8d8d-ba7e70efcfaf",
          "channel": "online",
          "kind": "table",
          "party_size": 4,
          "starts_at": "2027-01-15T19:00:00+01:00",
          "guest": {
            "name": "Jana Svobodová",
            "phone": "+420777123456",
            "email": "jana.svobodova@example.com"
          },
          "note_guest": "U okna, slavíme narozeniny"
        }
        """), Reservation::fromJson); // 201
    // the client: see /v2/docs/java
    // the call blocks – on Android from a worker thread (Dispatchers.IO)
    Reservation reservation = api.post("/restaurants/123/reservations", Json.parse("""
        {
          "uuid": "01a318f0-a0c0-7a44-8d8d-ba7e70efcfaf",
          "channel": "online",
          "kind": "table",
          "party_size": 4,
          "starts_at": "2027-01-15T19:00:00+01:00",
          "guest": {
            "name": "Jana Svobodová",
            "phone": "+420777123456",
            "email": "jana.svobodova@example.com"
          },
          "note_guest": "U okna, slavíme narozeniny"
        }
        """), Reservation::fromJson); // 201
    // klient: viz /v2/docs/java
    // volání blokuje – na Androidu z pracovního vlákna (Dispatchers.IO)
    val reservation = api.post("/restaurants/123/reservations", mapOf(
        "uuid" to "01a318f0-a0c0-7a44-8d8d-ba7e70efcfaf",
        "channel" to "online",
        "kind" to "table",
        "party_size" to 4,
        "starts_at" to "2027-01-15T19:00:00+01:00",
        "guest" to mapOf(
            "name" to "Jana Svobodová",
            "phone" to "+420777123456",
            "email" to "jana.svobodova@example.com",
        ),
        "note_guest" to "U okna, slavíme narozeniny",
    ), Reservation::fromJson) // 201
    // the client: see /v2/docs/java
    // the call blocks – on Android from a worker thread (Dispatchers.IO)
    val reservation = api.post("/restaurants/123/reservations", mapOf(
        "uuid" to "01a318f0-a0c0-7a44-8d8d-ba7e70efcfaf",
        "channel" to "online",
        "kind" to "table",
        "party_size" to 4,
        "starts_at" to "2027-01-15T19:00:00+01:00",
        "guest" to mapOf(
            "name" to "Jana Svobodová",
            "phone" to "+420777123456",
            "email" to "jana.svobodova@example.com",
        ),
        "note_guest" to "U okna, slavíme narozeniny",
    ), Reservation::fromJson) // 201
    // klient: viz /v2/docs/csharp
    var reservation = await api.PostAsync<Reservation>("/restaurants/123/reservations", new {
        uuid = "01a318f0-a0c0-7a44-8d8d-ba7e70efcfaf",
        channel = "online",
        kind = "table",
        party_size = 4,
        starts_at = "2027-01-15T19:00:00+01:00",
        guest = new {
            name = "Jana Svobodová",
            phone = "+420777123456",
            email = "jana.svobodova@example.com",
        },
        note_guest = "U okna, slavíme narozeniny",
    }); // 201
    // the client: see /v2/docs/csharp
    var reservation = await api.PostAsync<Reservation>("/restaurants/123/reservations", new {
        uuid = "01a318f0-a0c0-7a44-8d8d-ba7e70efcfaf",
        channel = "online",
        kind = "table",
        party_size = 4,
        starts_at = "2027-01-15T19:00:00+01:00",
        guest = new {
            name = "Jana Svobodová",
            phone = "+420777123456",
            email = "jana.svobodova@example.com",
        },
        note_guest = "U okna, slavíme narozeniny",
    }); // 201
    # klient: viz /v2/docs/python
    reservation = api.post('/restaurants/123/reservations', {
        'uuid': '01a318f0-a0c0-7a44-8d8d-ba7e70efcfaf',
        'channel': 'online',
        'kind': 'table',
        'party_size': 4,
        'starts_at': '2027-01-15T19:00:00+01:00',
        'guest': {
            'name': 'Jana Svobodová',
            'phone': '+420777123456',
            'email': 'jana.svobodova@example.com',
        },
        'note_guest': 'U okna, slavíme narozeniny',
    })  # 201
    # the client: see /v2/docs/python
    reservation = api.post('/restaurants/123/reservations', {
        'uuid': '01a318f0-a0c0-7a44-8d8d-ba7e70efcfaf',
        'channel': 'online',
        'kind': 'table',
        'party_size': 4,
        'starts_at': '2027-01-15T19:00:00+01:00',
        'guest': {
            'name': 'Jana Svobodová',
            'phone': '+420777123456',
            'email': 'jana.svobodova@example.com',
        },
        'note_guest': 'U okna, slavíme narozeniny',
    })  # 201
    // klient: viz /v2/docs/swift
    let reservation: Reservation = try await api.post("/restaurants/123/reservations", body: [
        "uuid": "01a318f0-a0c0-7a44-8d8d-ba7e70efcfaf",
        "channel": "online",
        "kind": "table",
        "party_size": 4,
        "starts_at": "2027-01-15T19:00:00+01:00",
        "guest": [
            "name": "Jana Svobodová",
            "phone": "+420777123456",
            "email": "jana.svobodova@example.com",
        ],
        "note_guest": "U okna, slavíme narozeniny",
    ]) // 201
    // the client: see /v2/docs/swift
    let reservation: Reservation = try await api.post("/restaurants/123/reservations", body: [
        "uuid": "01a318f0-a0c0-7a44-8d8d-ba7e70efcfaf",
        "channel": "online",
        "kind": "table",
        "party_size": 4,
        "starts_at": "2027-01-15T19:00:00+01:00",
        "guest": [
            "name": "Jana Svobodová",
            "phone": "+420777123456",
            "email": "jana.svobodova@example.com",
        ],
        "note_guest": "U okna, slavíme narozeniny",
    ]) // 201
    // klient: viz /v2/docs/dart
    final reservation = pr.Reservation.fromJson(await api.post('/restaurants/123/reservations', {
      'uuid': '01a318f0-a0c0-7a44-8d8d-ba7e70efcfaf',
      'channel': 'online',
      'kind': 'table',
      'party_size': 4,
      'starts_at': '2027-01-15T19:00:00+01:00',
      'guest': {
        'name': 'Jana Svobodová',
        'phone': '+420777123456',
        'email': 'jana.svobodova@example.com',
      },
      'note_guest': 'U okna, slavíme narozeniny',
    })); // 201
    // the client: see /v2/docs/dart
    final reservation = pr.Reservation.fromJson(await api.post('/restaurants/123/reservations', {
      'uuid': '01a318f0-a0c0-7a44-8d8d-ba7e70efcfaf',
      'channel': 'online',
      'kind': 'table',
      'party_size': 4,
      'starts_at': '2027-01-15T19:00:00+01:00',
      'guest': {
        'name': 'Jana Svobodová',
        'phone': '+420777123456',
        'email': 'jana.svobodova@example.com',
      },
      'note_guest': 'U okna, slavíme narozeniny',
    })); // 201
    // klient: viz /v2/docs/go
    res, err := api.Post(ctx, "/restaurants/123/reservations", map[string]any{
    	"uuid": "01a318f0-a0c0-7a44-8d8d-ba7e70efcfaf",
    	"channel": "online",
    	"kind": "table",
    	"party_size": 4,
    	"starts_at": "2027-01-15T19:00:00+01:00",
    	"guest": map[string]any{
    		"name": "Jana Svobodová",
    		"phone": "+420777123456",
    		"email": "jana.svobodova@example.com",
    	},
    	"note_guest": "U okna, slavíme narozeniny",
    }, nil)
    var reservation model.Reservation // 201
    if err == nil {
    	err = res.Decode(&reservation)
    }
    // the client: see /v2/docs/go
    res, err := api.Post(ctx, "/restaurants/123/reservations", map[string]any{
    	"uuid": "01a318f0-a0c0-7a44-8d8d-ba7e70efcfaf",
    	"channel": "online",
    	"kind": "table",
    	"party_size": 4,
    	"starts_at": "2027-01-15T19:00:00+01:00",
    	"guest": map[string]any{
    		"name": "Jana Svobodová",
    		"phone": "+420777123456",
    		"email": "jana.svobodova@example.com",
    	},
    	"note_guest": "U okna, slavíme narozeniny",
    }, nil)
    var reservation model.Reservation // 201
    if err == nil {
    	err = res.Decode(&reservation)
    }
    Příklad odpovědi 201Example answer 201
    {
      "id": "5120",
      "uuid": "01a318f0-a0c0-7a44-8d8d-ba7e70efcfaf",
      "restaurant_id": "123",
      "kind": "table",
      "status": "confirmed",
      "source": "online",
      "party_size": 4,
      "starts_at": "2027-01-15T19:00:00+01:00",
      "ends_at": "2027-01-15T21:00:00+01:00",
      "blocked_until": "2027-01-15T21:15:00+01:00",
      "table_ids": [
        "4"
      ],
      "service_id": null,
      "employee_id": null,
      "employee_any": false,
      "resource_id": null,
      "guest": {
        "name": "Jana Svobodová",
        "phone": "+420777123456",
        "email": "jana.svobodova@example.com",
        "customer_id": null
      },
      "note_guest": "U okna, slavíme narozeniny",
      "note_internal": null,
      "tags": [
        "narozeniny"
      ],
      "deposit": {
        "amount": {
          "amount": 0,
          "currency": "CZK"
        },
        "status": "none",
        "due_at": null
      },
      "confirm_due_at": null,
      "tab_id": null,
      "cancel_reason": null,
      "version": 1,
      "created_at": "2027-01-15T11:40:12+01:00",
      "updated_at": "2027-01-15T11:40:12+01:00"
    }
  5. Sledujte změny

    Follow the changes

    GET /events · listEvents

    reservation.status_changed řekne, že ji provozovna potvrdila, zrušila nebo že host přišel. Kontakty hosta v události nejsou – načtěte je přes getReservation.

    reservation.status_changed tells you the restaurant confirmed or cancelled it or that the guest arrived. The guest's contacts are not in the event – read them with getReservation.

    curl "https://api.mujprofirest.cz/v2/events?cursor=eyJzZXEiOjkxMDU1MH0&restaurant_id=123&limit=100" \
      -H "Authorization: Bearer $ACCESS_TOKEN"
    curl "https://api.mujprofirest.cz/v2/events?cursor=eyJzZXEiOjkxMDU1MH0&restaurant_id=123&limit=100" \
      -H "Authorization: Bearer $ACCESS_TOKEN"
    // klient: viz /v2/docs/js
    const feed = api.watchEvents({
      restaurantId: '123',
      onEvents: async (events) => {
        for (const event of events) handle(event); // kurzor se posune až potom
      },
      onReset: () => reloadEverything(), // 410 cursor_expired: načtěte stav znovu
    });
    // the client: see /v2/docs/js
    const feed = api.watchEvents({
      restaurantId: '123',
      onEvents: async (events) => {
        for (const event of events) handle(event); // the cursor moves only afterwards
      },
      onReset: () => reloadEverything(), // 410 cursor_expired: reload the state
    });
    // klient: viz /v2/docs/typescript
    const feed = api.watchEvents({
      restaurantId: '123',
      onEvents: async (events) => {
        for (const event of events) handle(event); // kurzor se posune až potom
      },
      onReset: () => reloadEverything(), // 410 cursor_expired: načtěte stav znovu
    });
    // the client: see /v2/docs/typescript
    const feed = api.watchEvents({
      restaurantId: '123',
      onEvents: async (events) => {
        for (const event of events) handle(event); // the cursor moves only afterwards
      },
      onReset: () => reloadEverything(), // 410 cursor_expired: reload the state
    });
    // klient: viz /v2/docs/php
    $api->watchEvents([
        'restaurantId' => '123',
        'onEvents' => function (array $events): void {
            foreach ($events as $event) { handle($event); } // kurzor se posune až potom
        },
        'onReset' => fn() => reloadEverything(), // 410 cursor_expired: načtěte stav znovu
    ])->run();
    // the client: see /v2/docs/php
    $api->watchEvents([
        'restaurantId' => '123',
        'onEvents' => function (array $events): void {
            foreach ($events as $event) { handle($event); } // the cursor moves only afterwards
        },
        'onReset' => fn() => reloadEverything(), // 410 cursor_expired: reload the state
    ])->run();
    // klient: viz /v2/docs/java
    // volání blokuje – na Androidu z pracovního vlákna (Dispatchers.IO)
    EventWatcher feed = api.watchEvents(WatchOptions.builder()
            .restaurantId("123")
            .onEvents(events -> events.forEach(this::handle)) // kurzor se posune až potom
            .onReset(error -> reloadEverything()) // 410 cursor_expired: načtěte stav znovu
            .build());
    feed.start();
    // the client: see /v2/docs/java
    // the call blocks – on Android from a worker thread (Dispatchers.IO)
    EventWatcher feed = api.watchEvents(WatchOptions.builder()
            .restaurantId("123")
            .onEvents(events -> events.forEach(this::handle)) // the cursor moves only afterwards
            .onReset(error -> reloadEverything()) // 410 cursor_expired: reload the state
            .build());
    feed.start();
    // klient: viz /v2/docs/java
    // volání blokuje – na Androidu z pracovního vlákna (Dispatchers.IO)
    val feed = api.watchEvents(WatchOptions.builder()
        .restaurantId("123")
        .onEvents { events -> events.forEach { handle(it) } } // kurzor se posune až potom
        .onReset { reloadEverything() } // 410 cursor_expired: načtěte stav znovu
        .build())
    feed.start()
    // the client: see /v2/docs/java
    // the call blocks – on Android from a worker thread (Dispatchers.IO)
    val feed = api.watchEvents(WatchOptions.builder()
        .restaurantId("123")
        .onEvents { events -> events.forEach { handle(it) } } // the cursor moves only afterwards
        .onReset { reloadEverything() } // 410 cursor_expired: reload the state
        .build())
    feed.start()
    // klient: viz /v2/docs/csharp
    await api.WatchEventsAsync(new WatchOptions
    {
        RestaurantId = "123",
        OnEvents = async (events, ct) => { foreach (var e in events) await HandleAsync(e, ct); }, // kurzor se posune až potom
        OnReset = _ => ReloadEverythingAsync(), // 410 cursor_expired: načtěte stav znovu
    }, stoppingToken);
    // the client: see /v2/docs/csharp
    await api.WatchEventsAsync(new WatchOptions
    {
        RestaurantId = "123",
        OnEvents = async (events, ct) => { foreach (var e in events) await HandleAsync(e, ct); }, // the cursor moves only afterwards
        OnReset = _ => ReloadEverythingAsync(), // 410 cursor_expired: reload the state
    }, stoppingToken);
    # klient: viz /v2/docs/python
    feed = api.watch_events(
        lambda events: [handle(event) for event in events],  # kurzor se posune až potom
        restaurant_id='123',
        on_reset=lambda error: reload_everything(),  # 410 cursor_expired: načtěte stav znovu
    )
    feed.start()
    # the client: see /v2/docs/python
    feed = api.watch_events(
        lambda events: [handle(event) for event in events],  # the cursor moves only afterwards
        restaurant_id='123',
        on_reset=lambda error: reload_everything(),  # 410 cursor_expired: reload the state
    )
    feed.start()
    // klient: viz /v2/docs/swift
    let feed = api.watchEvents(.init(
        restaurantID: "123",
        onEvents: { events in for event in events { handle(event) } }, // kurzor se posune až potom
        onReset: { _ in reloadEverything() } // 410 cursor_expired: načtěte stav znovu
    ))
    // feed.cancel() čtení ukončí
    // the client: see /v2/docs/swift
    let feed = api.watchEvents(.init(
        restaurantID: "123",
        onEvents: { events in for event in events { handle(event) } }, // the cursor moves only afterwards
        onReset: { _ in reloadEverything() } // 410 cursor_expired: reload the state
    ))
    // feed.cancel() čtení ukončí
    // klient: viz /v2/docs/dart
    final feed = api.watchEvents(
      restaurantId: '123',
      onEvents: (events) async { for (final event in events) handle(event); }, // kurzor se posune až potom
      onReset: (error) => reloadEverything(), // 410 cursor_expired: načtěte stav znovu
    )..start();
    // the client: see /v2/docs/dart
    final feed = api.watchEvents(
      restaurantId: '123',
      onEvents: (events) async { for (final event in events) handle(event); }, // the cursor moves only afterwards
      onReset: (error) => reloadEverything(), // 410 cursor_expired: reload the state
    )..start();
    // klient: viz /v2/docs/go
    err := api.WatchEvents(ctx, profirest.WatchOptions{
    	RestaurantID: "123",
    	OnEvents: func(ctx context.Context, events []model.Event) error {
    		for _, event := range events {
    			handle(event) // kurzor se posune až potom
    		}
    		return nil
    	},
    	OnReset: func(*profirest.APIError) { reloadEverything() }, // 410 cursor_expired: načtěte stav znovu
    })
    // the client: see /v2/docs/go
    err := api.WatchEvents(ctx, profirest.WatchOptions{
    	RestaurantID: "123",
    	OnEvents: func(ctx context.Context, events []model.Event) error {
    		for _, event := range events {
    			handle(event) // the cursor moves only afterwards
    		}
    		return nil
    	},
    	OnReset: func(*profirest.APIError) { reloadEverything() }, // 410 cursor_expired: reload the state
    })
    Příklad odpovědi 200Example answer 200
    {
      "data": [
        {
          "id": "910551",
          "api_version": "2",
          "sequence": 910551,
          "type": "order.created",
          "occurred_at": "2027-01-15T11:42:31+01:00",
          "connection_id": "2208",
          "account_id": "7",
          "restaurant_id": "123",
          "data": {
            "id": "184223",
            "restaurant_id": "123",
            "kitchen_number": "027",
            "status": "received",
            "status_changed_at": "2027-01-15T11:42:31+01:00",
            "created_at": "2027-01-15T11:42:31+01:00",
            "payment_deadline": null,
            "fulfillment": {
              "type": "pickup",
              "speed": "standard",
              "asap": true,
              "time": null,
              "estimated_at": "2027-01-15T12:05:00+01:00"
            },
            "customer": {
              "customer_id": null,
              "name": "Jana Nováková",
              "phone": "+420777123456",
              "email": "jana.novakova@example.cz"
            },
            "delivery": null,
            "lines": [
              {
                "id": "1",
                "type": "product",
                "product_id": "4567",
                "name": "Svíčková na smetaně, houskový knedlík",
                "quantity": 2,
                "base_unit_price": {
                  "amount": 19900,
                  "currency": "CZK"
                },
                "unit_price": {
                  "amount": 19900,
                  "currency": "CZK"
                },
                "packaging_unit_price": null,
                "vat_rate": "12",
                "add_ons": [],
                "options": [],
                "parts": null,
                "removed_ingredients": [],
                "note": null,
                "total": {
                  "amount": 39800,
                  "currency": "CZK"
                },
                "gift_of": null
              }
            ],
            "charges": [],
            "discounts": [],
            "totals": {
              "items": {
                "amount": 39800,
                "currency": "CZK"
              },
              "charges": {
                "amount": 0,
                "currency": "CZK"
              },
              "discounts": {
                "amount": 0,
                "currency": "CZK"
              },
              "rounding": {
                "amount": 0,
                "currency": "CZK"
              },
              "total": {
                "amount": 39800,
                "currency": "CZK"
              },
              "vat": [
                {
                  "rate": "12",
                  "base": {
                    "amount": 35536,
                    "currency": "CZK"
                  },
                  "vat": {
                    "amount": 4264,
                    "currency": "CZK"
                  },
                  "total": {
                    "amount": 39800,
                    "currency": "CZK"
                  }
                }
              ]
            },
            "payments": [
              {
                "id": "301877",
                "method": "cash",
                "status": "unpaid",
                "amount": {
                  "amount": 39800,
                  "currency": "CZK"
                },
                "provider": null,
                "reference": null,
                "voucher_code": null,
                "forfeited": null
              }
            ],
            "amount_to_collect": {
              "amount": 39800,
              "currency": "CZK"
            },
            "loyalty_points_earned": null,
            "note": null,
            "cancellation": null,
            "external_id": "A-2027-000123",
            "metadata": {
              "branch": "praha-3"
            }
          }
        },
        {
          "id": "910563",
          "api_version": "2",
          "sequence": 910563,
          "type": "order.status_changed",
          "occurred_at": "2027-01-15T11:44:02+01:00",
          "connection_id": "2208",
          "account_id": "7",
          "restaurant_id": "123",
          "data": {
            "id": "184223",
            "restaurant_id": "123",
            "kitchen_number": "027",
            "status": "preparing",
            "status_changed_at": "2027-01-15T11:44:02+01:00",
            "created_at": "2027-01-15T11:42:31+01:00",
            "payment_deadline": null,
            "fulfillment": {
              "type": "pickup",
              "speed": "standard",
              "asap": true,
              "time": null,
              "estimated_at": "2027-01-15T12:05:00+01:00"
            },
            "customer": {
              "customer_id": null,
              "name": "Jana Nováková",
              "phone": "+420777123456",
              "email": "jana.novakova@example.cz"
            },
            "delivery": null,
            "lines": [
              {
                "id": "1",
                "type": "product",
                "product_id": "4567",
                "name": "Svíčková na smetaně, houskový knedlík",
                "quantity": 2,
                "base_unit_price": {
                  "amount": 19900,
                  "currency": "CZK"
                },
                "unit_price": {
                  "amount": 19900,
                  "currency": "CZK"
                },
                "packaging_unit_price": null,
                "vat_rate": "12",
                "add_ons": [],
                "options": [],
                "parts": null,
                "removed_ingredients": [],
                "note": null,
                "total": {
                  "amount": 39800,
                  "currency": "CZK"
                },
                "gift_of": null
              }
            ],
            "charges": [],
            "discounts": [],
            "totals": {
              "items": {
                "amount": 39800,
                "currency": "CZK"
              },
              "charges": {
                "amount": 0,
                "currency": "CZK"
              },
              "discounts": {
                "amount": 0,
                "currency": "CZK"
              },
              "rounding": {
                "amount": 0,
                "currency": "CZK"
              },
              "total": {
                "amount": 39800,
                "currency": "CZK"
              },
              "vat": [
                {
                  "rate": "12",
                  "base": {
                    "amount": 35536,
                    "currency": "CZK"
                  },
                  "vat": {
                    "amount": 4264,
                    "currency": "CZK"
                  },
                  "total": {
                    "amount": 39800,
                    "currency": "CZK"
                  }
                }
              ]
            },
            "payments": [
              {
                "id": "301877",
                "method": "cash",
                "status": "unpaid",
                "amount": {
                  "amount": 39800,
                  "currency": "CZK"
                },
                "provider": null,
                "reference": null,
                "voucher_code": null,
                "forfeited": null
              }
            ],
            "amount_to_collect": {
              "amount": 39800,
              "currency": "CZK"
            },
            "loyalty_points_earned": null,
            "note": null,
            "cancellation": null,
            "external_id": "A-2027-000123",
            "metadata": {
              "branch": "praha-3"
            }
          }
        },
        {
          "id": "910570",
          "api_version": "2",
          "sequence": 910570,
          "type": "availability.changed",
          "occurred_at": "2027-01-15T11:45:10+01:00",
          "connection_id": "2208",
          "account_id": "7",
          "restaurant_id": "123",
          "data": {
            "restaurant_id": "123"
          }
        }
      ],
      "next_cursor": "eyJzZXEiOjkxMDU3MH0"
    }
  6. Zrušení hostem

    Cancelled by the guest

    POST /restaurants/{restaurant_id}/reservations/{reservation_id}/cancel · cancelReservation

    S důvodem v reason; ukončenou rezervaci vrátí 409 reservation_state_conflict.

    With a reason; a finished reservation answers 409 reservation_state_conflict.

    curl "https://api.mujprofirest.cz/v2/restaurants/123/reservations/5120/cancel" \
      -H "Authorization: Bearer $ACCESS_TOKEN" \
      -H "Idempotency-Key: 01a318f0-a0c0-7ae7-8f65-832d26999a79" \
      -H "Content-Type: application/json" \
      -d '{"reason": "Host onemocněl"}'
    curl "https://api.mujprofirest.cz/v2/restaurants/123/reservations/5120/cancel" \
      -H "Authorization: Bearer $ACCESS_TOKEN" \
      -H "Idempotency-Key: 01a318f0-a0c0-7ae7-8f65-832d26999a79" \
      -H "Content-Type: application/json" \
      -d '{"reason": "Host onemocněl"}'
    // klient: viz /v2/docs/js
    const reservation = await api.post('/restaurants/123/reservations/5120/cancel', { reason: 'Host onemocněl' }); // 200
    // the client: see /v2/docs/js
    const reservation = await api.post('/restaurants/123/reservations/5120/cancel', { reason: 'Host onemocněl' }); // 200
    // klient: viz /v2/docs/typescript
    const reservation = await api.post('/restaurants/123/reservations/5120/cancel', { reason: 'Host onemocněl' }); // 200 Reservation
    // the client: see /v2/docs/typescript
    const reservation = await api.post('/restaurants/123/reservations/5120/cancel', { reason: 'Host onemocněl' }); // 200 Reservation
    // klient: viz /v2/docs/php
    $reservation = $api->post('/restaurants/123/reservations/5120/cancel', ['reason' => 'Host onemocněl']); // 200
    // the client: see /v2/docs/php
    $reservation = $api->post('/restaurants/123/reservations/5120/cancel', ['reason' => 'Host onemocněl']); // 200
    // klient: viz /v2/docs/java
    // volání blokuje – na Androidu z pracovního vlákna (Dispatchers.IO)
    Reservation reservation = api.post("/restaurants/123/reservations/5120/cancel", Json.parse("""
        {"reason": "Host onemocněl"}
        """), Reservation::fromJson); // 200
    // the client: see /v2/docs/java
    // the call blocks – on Android from a worker thread (Dispatchers.IO)
    Reservation reservation = api.post("/restaurants/123/reservations/5120/cancel", Json.parse("""
        {"reason": "Host onemocněl"}
        """), Reservation::fromJson); // 200
    // klient: viz /v2/docs/java
    // volání blokuje – na Androidu z pracovního vlákna (Dispatchers.IO)
    val reservation = api.post(
        "/restaurants/123/reservations/5120/cancel",
        mapOf("reason" to "Host onemocněl"),
        Reservation::fromJson,
    ) // 200
    // the client: see /v2/docs/java
    // the call blocks – on Android from a worker thread (Dispatchers.IO)
    val reservation = api.post(
        "/restaurants/123/reservations/5120/cancel",
        mapOf("reason" to "Host onemocněl"),
        Reservation::fromJson,
    ) // 200
    // klient: viz /v2/docs/csharp
    var reservation = await api.PostAsync<Reservation>(
        "/restaurants/123/reservations/5120/cancel",
        new { reason = "Host onemocněl" }
    ); // 200
    // the client: see /v2/docs/csharp
    var reservation = await api.PostAsync<Reservation>(
        "/restaurants/123/reservations/5120/cancel",
        new { reason = "Host onemocněl" }
    ); // 200
    # klient: viz /v2/docs/python
    reservation = api.post('/restaurants/123/reservations/5120/cancel', {'reason': 'Host onemocněl'})  # 200
    # the client: see /v2/docs/python
    reservation = api.post('/restaurants/123/reservations/5120/cancel', {'reason': 'Host onemocněl'})  # 200
    // klient: viz /v2/docs/swift
    let reservation: Reservation = try await api.post("/restaurants/123/reservations/5120/cancel", body: ["reason": "Host onemocněl"]) // 200
    // the client: see /v2/docs/swift
    let reservation: Reservation = try await api.post("/restaurants/123/reservations/5120/cancel", body: ["reason": "Host onemocněl"]) // 200
    // klient: viz /v2/docs/dart
    final reservation = pr.Reservation.fromJson(await api.post('/restaurants/123/reservations/5120/cancel', {'reason': 'Host onemocněl'})); // 200
    // the client: see /v2/docs/dart
    final reservation = pr.Reservation.fromJson(await api.post('/restaurants/123/reservations/5120/cancel', {'reason': 'Host onemocněl'})); // 200
    // klient: viz /v2/docs/go
    res, err := api.Post(
    	ctx,
    	"/restaurants/123/reservations/5120/cancel",
    	map[string]any{"reason": "Host onemocněl"},
    	nil,
    )
    var reservation model.Reservation // 200
    if err == nil {
    	err = res.Decode(&reservation)
    }
    // the client: see /v2/docs/go
    res, err := api.Post(
    	ctx,
    	"/restaurants/123/reservations/5120/cancel",
    	map[string]any{"reason": "Host onemocněl"},
    	nil,
    )
    var reservation model.Reservation // 200
    if err == nil {
    	err = res.Decode(&reservation)
    }
    Příklad odpovědi 200Example answer 200
    {
      "id": "5120",
      "uuid": "01a318f0-a0c0-7a44-8d8d-ba7e70efcfaf",
      "restaurant_id": "123",
      "kind": "table",
      "status": "cancelled",
      "source": "online",
      "party_size": 4,
      "starts_at": "2027-01-15T19:00:00+01:00",
      "ends_at": "2027-01-15T21:00:00+01:00",
      "blocked_until": "2027-01-15T21:15:00+01:00",
      "table_ids": [
        "4"
      ],
      "service_id": null,
      "employee_id": null,
      "employee_any": false,
      "resource_id": null,
      "guest": {
        "name": "Jana Svobodová",
        "phone": "+420777123456",
        "email": "jana.svobodova@example.com",
        "customer_id": null
      },
      "note_guest": "U okna, slavíme narozeniny",
      "note_internal": null,
      "tags": [
        "narozeniny"
      ],
      "deposit": {
        "amount": {
          "amount": 0,
          "currency": "CZK"
        },
        "status": "none",
        "due_at": null
      },
      "confirm_due_at": null,
      "tab_id": null,
      "cancel_reason": "Host onemocněl",
      "version": 2,
      "created_at": "2027-01-15T11:40:12+01:00",
      "updated_at": "2027-01-15T11:40:12+01:00"
    }
  7. Které stoly jsou volné teď

    Which tables are free now

    GET /restaurants/{restaurant_id}/table-status · getTableStatus

    Pro walk-in a obrazovky u vstupu: obsazené účtem i rezervací, s další rezervací dne. Hosty bez rezervace usadíte přes createReservation s channel=staff a walk_in: true.

    For walk-ins and screens at the entrance: taken by a tab or a reservation, with the next reservation of the day. Seat guests without a reservation with createReservation, channel=staff and walk_in: true.

    curl "https://api.mujprofirest.cz/v2/restaurants/123/table-status" \
      -H "Authorization: Bearer $ACCESS_TOKEN"
    curl "https://api.mujprofirest.cz/v2/restaurants/123/table-status" \
      -H "Authorization: Bearer $ACCESS_TOKEN"
    // klient: viz /v2/docs/js
    const tableStatus = await api.get('/restaurants/123/table-status'); // 200
    // the client: see /v2/docs/js
    const tableStatus = await api.get('/restaurants/123/table-status'); // 200
    // klient: viz /v2/docs/typescript
    const tableStatus = await api.get('/restaurants/123/table-status'); // 200 TableStatus
    // the client: see /v2/docs/typescript
    const tableStatus = await api.get('/restaurants/123/table-status'); // 200 TableStatus
    // klient: viz /v2/docs/php
    $tableStatus = $api->get('/restaurants/123/table-status'); // 200
    // the client: see /v2/docs/php
    $tableStatus = $api->get('/restaurants/123/table-status'); // 200
    // klient: viz /v2/docs/java
    // volání blokuje – na Androidu z pracovního vlákna (Dispatchers.IO)
    TableStatus tableStatus = api.get("/restaurants/123/table-status", TableStatus::fromJson); // 200
    // the client: see /v2/docs/java
    // the call blocks – on Android from a worker thread (Dispatchers.IO)
    TableStatus tableStatus = api.get("/restaurants/123/table-status", TableStatus::fromJson); // 200
    // klient: viz /v2/docs/java
    // volání blokuje – na Androidu z pracovního vlákna (Dispatchers.IO)
    val tableStatus = api.get("/restaurants/123/table-status", TableStatus::fromJson) // 200
    // the client: see /v2/docs/java
    // the call blocks – on Android from a worker thread (Dispatchers.IO)
    val tableStatus = api.get("/restaurants/123/table-status", TableStatus::fromJson) // 200
    // klient: viz /v2/docs/csharp
    var tableStatus = await api.GetAsync<TableStatus>("/restaurants/123/table-status"); // 200
    // the client: see /v2/docs/csharp
    var tableStatus = await api.GetAsync<TableStatus>("/restaurants/123/table-status"); // 200
    # klient: viz /v2/docs/python
    table_status = api.get('/restaurants/123/table-status')  # 200
    # the client: see /v2/docs/python
    table_status = api.get('/restaurants/123/table-status')  # 200
    // klient: viz /v2/docs/swift
    let tableStatus: TableStatus = try await api.get("/restaurants/123/table-status") // 200
    // the client: see /v2/docs/swift
    let tableStatus: TableStatus = try await api.get("/restaurants/123/table-status") // 200
    // klient: viz /v2/docs/dart
    final tableStatus = pr.TableStatus.fromJson(await api.get('/restaurants/123/table-status')); // 200
    // the client: see /v2/docs/dart
    final tableStatus = pr.TableStatus.fromJson(await api.get('/restaurants/123/table-status')); // 200
    // klient: viz /v2/docs/go
    res, err := api.Get(ctx, "/restaurants/123/table-status", nil)
    var tableStatus model.TableStatus // 200
    if err == nil {
    	err = res.Decode(&tableStatus)
    }
    // the client: see /v2/docs/go
    res, err := api.Get(ctx, "/restaurants/123/table-status", nil)
    var tableStatus model.TableStatus // 200
    if err == nil {
    	err = res.Decode(&tableStatus)
    }
    Příklad odpovědi 200Example answer 200
    {
      "at": "2027-01-15T18:40:00+01:00",
      "tables": [
        {
          "id": "4",
          "name": "Stůl 4",
          "room": "Restaurace",
          "seats_min": 2,
          "seats_max": 4,
          "state": "reserved",
          "tab_id": null,
          "reservation_id": "5120",
          "next_reservation": null
        },
        {
          "id": "7",
          "name": "Stůl 7",
          "room": "Restaurace",
          "seats_min": 2,
          "seats_max": 6,
          "state": "occupied",
          "tab_id": "01a318f0-a0c0-7b5f-897a-975233c4fa9d",
          "reservation_id": null,
          "next_reservation": {
            "id": "5133",
            "starts_at": "2027-01-15T20:30:00+01:00",
            "party_size": 6
          }
        }
      ]
    }
  8. Kdo volá (aplikace obsluhy)

    Who is calling (staff application)

    GET /restaurants/{restaurant_id}/reservation-guest · getReservationGuest

    Podle telefonu ukažte, kolikrát host přišel, nepřišel nebo zrušil, a jeho štítky (alergie, VIP).

    By the phone number show how many times the guest came, did not come or cancelled, and their tags (allergies, VIP).

    curl "https://api.mujprofirest.cz/v2/restaurants/123/reservation-guest?phone=%2B420777123456" \
      -H "Authorization: Bearer $ACCESS_TOKEN"
    curl "https://api.mujprofirest.cz/v2/restaurants/123/reservation-guest?phone=%2B420777123456" \
      -H "Authorization: Bearer $ACCESS_TOKEN"
    // klient: viz /v2/docs/js
    const reservationGuest = await api.get('/restaurants/123/reservation-guest', { query: { phone: '+420777123456' } }); // 200
    // the client: see /v2/docs/js
    const reservationGuest = await api.get('/restaurants/123/reservation-guest', { query: { phone: '+420777123456' } }); // 200
    // klient: viz /v2/docs/typescript
    const reservationGuest = await api.get('/restaurants/123/reservation-guest', { query: { phone: '+420777123456' } }); // 200 ReservationGuestHistory
    // the client: see /v2/docs/typescript
    const reservationGuest = await api.get('/restaurants/123/reservation-guest', { query: { phone: '+420777123456' } }); // 200 ReservationGuestHistory
    // klient: viz /v2/docs/php
    $reservationGuest = $api->get('/restaurants/123/reservation-guest', ['query' => ['phone' => '+420777123456']]); // 200
    // the client: see /v2/docs/php
    $reservationGuest = $api->get('/restaurants/123/reservation-guest', ['query' => ['phone' => '+420777123456']]); // 200
    // klient: viz /v2/docs/java
    // volání blokuje – na Androidu z pracovního vlákna (Dispatchers.IO)
    ReservationGuestHistory reservationGuest = api.get(
        "/restaurants/123/reservation-guest",
        RequestOptions.builder().query("phone", "+420777123456").build(),
        ReservationGuestHistory::fromJson
    ); // 200
    // the client: see /v2/docs/java
    // the call blocks – on Android from a worker thread (Dispatchers.IO)
    ReservationGuestHistory reservationGuest = api.get(
        "/restaurants/123/reservation-guest",
        RequestOptions.builder().query("phone", "+420777123456").build(),
        ReservationGuestHistory::fromJson
    ); // 200
    // klient: viz /v2/docs/java
    // volání blokuje – na Androidu z pracovního vlákna (Dispatchers.IO)
    val reservationGuest = api.get(
        "/restaurants/123/reservation-guest",
        RequestOptions.builder().query("phone", "+420777123456").build(),
        ReservationGuestHistory::fromJson,
    ) // 200
    // the client: see /v2/docs/java
    // the call blocks – on Android from a worker thread (Dispatchers.IO)
    val reservationGuest = api.get(
        "/restaurants/123/reservation-guest",
        RequestOptions.builder().query("phone", "+420777123456").build(),
        ReservationGuestHistory::fromJson,
    ) // 200
    // klient: viz /v2/docs/csharp
    var reservationGuest = await api.GetAsync<ReservationGuestHistory>(
        "/restaurants/123/reservation-guest",
        new RequestOptions { Query = new() { ["phone"] = "+420777123456" } }
    ); // 200
    // the client: see /v2/docs/csharp
    var reservationGuest = await api.GetAsync<ReservationGuestHistory>(
        "/restaurants/123/reservation-guest",
        new RequestOptions { Query = new() { ["phone"] = "+420777123456" } }
    ); // 200
    # klient: viz /v2/docs/python
    reservation_guest = api.get('/restaurants/123/reservation-guest', query={'phone': '+420777123456'})  # 200
    # the client: see /v2/docs/python
    reservation_guest = api.get('/restaurants/123/reservation-guest', query={'phone': '+420777123456'})  # 200
    // klient: viz /v2/docs/swift
    let reservationGuest: ReservationGuestHistory = try await api.get("/restaurants/123/reservation-guest", options: .init(query: ["phone": "+420777123456"])) // 200
    // the client: see /v2/docs/swift
    let reservationGuest: ReservationGuestHistory = try await api.get("/restaurants/123/reservation-guest", options: .init(query: ["phone": "+420777123456"])) // 200
    // klient: viz /v2/docs/dart
    final reservationGuest = pr.ReservationGuestHistory.fromJson(await api.get('/restaurants/123/reservation-guest', query: {'phone': '+420777123456'})); // 200
    // the client: see /v2/docs/dart
    final reservationGuest = pr.ReservationGuestHistory.fromJson(await api.get('/restaurants/123/reservation-guest', query: {'phone': '+420777123456'})); // 200
    // klient: viz /v2/docs/go
    res, err := api.Get(
    	ctx,
    	"/restaurants/123/reservation-guest",
    	&profirest.RequestOptions{Query: map[string]any{"phone": "+420777123456"}},
    )
    var reservationGuest model.ReservationGuestHistory // 200
    if err == nil {
    	err = res.Decode(&reservationGuest)
    }
    // the client: see /v2/docs/go
    res, err := api.Get(
    	ctx,
    	"/restaurants/123/reservation-guest",
    	&profirest.RequestOptions{Query: map[string]any{"phone": "+420777123456"}},
    )
    var reservationGuest model.ReservationGuestHistory // 200
    if err == nil {
    	err = res.Decode(&reservationGuest)
    }
    Příklad odpovědi 200Example answer 200
    {
      "known": true,
      "name": "Jana Svobodová",
      "phone": "+420777123456",
      "email": "jana.svobodova@example.com",
      "visits": 7,
      "no_shows": 1,
      "cancelled": 1,
      "upcoming": 1,
      "last_visit_at": "2026-10-24T19:00:00+02:00",
      "tags": [
        "narozeniny",
        "alergie: ořechy"
      ]
    }
  9. Čekací listina u dveří

    The waiting list at the door

    POST /restaurants/{restaurant_id}/waitlist · addToWaitlist

    Host bez stolu jde na listinu; až se stůl uvolní, notifyWaitlistEntry mu pošle SMS a closeWaitlistEntry ho usadí (s rezervací hosta bez rezervace) nebo vyřadí.

    A guest without a table goes on the list; when a table is free, notifyWaitlistEntry sends them an SMS and closeWaitlistEntry seats them (with the walk-in reservation) or removes them.

    curl "https://api.mujprofirest.cz/v2/restaurants/123/waitlist" \
      -H "Authorization: Bearer $ACCESS_TOKEN" \
      -H "Idempotency-Key: 01a318f0-a0c0-7950-81cc-c942616c01ca" \
      -H "Content-Type: application/json" \
      -d '{
      "name": "Rodina Nováková",
      "phone": "+420603123456",
      "party_size": 4,
      "note": "s kočárkem"
    }'
    curl "https://api.mujprofirest.cz/v2/restaurants/123/waitlist" \
      -H "Authorization: Bearer $ACCESS_TOKEN" \
      -H "Idempotency-Key: 01a318f0-a0c0-7950-81cc-c942616c01ca" \
      -H "Content-Type: application/json" \
      -d '{
      "name": "Rodina Nováková",
      "phone": "+420603123456",
      "party_size": 4,
      "note": "s kočárkem"
    }'
    // klient: viz /v2/docs/js
    const toWaitlist = await api.post(
      '/restaurants/123/waitlist',
      { name: 'Rodina Nováková', phone: '+420603123456', party_size: 4, note: 's kočárkem' },
    ); // 201
    // the client: see /v2/docs/js
    const toWaitlist = await api.post(
      '/restaurants/123/waitlist',
      { name: 'Rodina Nováková', phone: '+420603123456', party_size: 4, note: 's kočárkem' },
    ); // 201
    // klient: viz /v2/docs/typescript
    const toWaitlist = await api.post(
      '/restaurants/123/waitlist',
      { name: 'Rodina Nováková', phone: '+420603123456', party_size: 4, note: 's kočárkem' },
    ); // 201 WaitlistEntry
    // the client: see /v2/docs/typescript
    const toWaitlist = await api.post(
      '/restaurants/123/waitlist',
      { name: 'Rodina Nováková', phone: '+420603123456', party_size: 4, note: 's kočárkem' },
    ); // 201 WaitlistEntry
    // klient: viz /v2/docs/php
    $toWaitlist = $api->post('/restaurants/123/waitlist', [
        'name' => 'Rodina Nováková',
        'phone' => '+420603123456',
        'party_size' => 4,
        'note' => 's kočárkem',
    ]); // 201
    // the client: see /v2/docs/php
    $toWaitlist = $api->post('/restaurants/123/waitlist', [
        'name' => 'Rodina Nováková',
        'phone' => '+420603123456',
        'party_size' => 4,
        'note' => 's kočárkem',
    ]); // 201
    // klient: viz /v2/docs/java
    // volání blokuje – na Androidu z pracovního vlákna (Dispatchers.IO)
    WaitlistEntry toWaitlist = api.post("/restaurants/123/waitlist", Json.parse("""
        {
          "name": "Rodina Nováková",
          "phone": "+420603123456",
          "party_size": 4,
          "note": "s kočárkem"
        }
        """), WaitlistEntry::fromJson); // 201
    // the client: see /v2/docs/java
    // the call blocks – on Android from a worker thread (Dispatchers.IO)
    WaitlistEntry toWaitlist = api.post("/restaurants/123/waitlist", Json.parse("""
        {
          "name": "Rodina Nováková",
          "phone": "+420603123456",
          "party_size": 4,
          "note": "s kočárkem"
        }
        """), WaitlistEntry::fromJson); // 201
    // klient: viz /v2/docs/java
    // volání blokuje – na Androidu z pracovního vlákna (Dispatchers.IO)
    val toWaitlist = api.post("/restaurants/123/waitlist", mapOf(
        "name" to "Rodina Nováková",
        "phone" to "+420603123456",
        "party_size" to 4,
        "note" to "s kočárkem",
    ), WaitlistEntry::fromJson) // 201
    // the client: see /v2/docs/java
    // the call blocks – on Android from a worker thread (Dispatchers.IO)
    val toWaitlist = api.post("/restaurants/123/waitlist", mapOf(
        "name" to "Rodina Nováková",
        "phone" to "+420603123456",
        "party_size" to 4,
        "note" to "s kočárkem",
    ), WaitlistEntry::fromJson) // 201
    // klient: viz /v2/docs/csharp
    var toWaitlist = await api.PostAsync<WaitlistEntry>("/restaurants/123/waitlist", new {
        name = "Rodina Nováková",
        phone = "+420603123456",
        party_size = 4,
        note = "s kočárkem",
    }); // 201
    // the client: see /v2/docs/csharp
    var toWaitlist = await api.PostAsync<WaitlistEntry>("/restaurants/123/waitlist", new {
        name = "Rodina Nováková",
        phone = "+420603123456",
        party_size = 4,
        note = "s kočárkem",
    }); // 201
    # klient: viz /v2/docs/python
    to_waitlist = api.post('/restaurants/123/waitlist', {
        'name': 'Rodina Nováková',
        'phone': '+420603123456',
        'party_size': 4,
        'note': 's kočárkem',
    })  # 201
    # the client: see /v2/docs/python
    to_waitlist = api.post('/restaurants/123/waitlist', {
        'name': 'Rodina Nováková',
        'phone': '+420603123456',
        'party_size': 4,
        'note': 's kočárkem',
    })  # 201
    // klient: viz /v2/docs/swift
    let toWaitlist: WaitlistEntry = try await api.post("/restaurants/123/waitlist", body: [
        "name": "Rodina Nováková",
        "phone": "+420603123456",
        "party_size": 4,
        "note": "s kočárkem",
    ]) // 201
    // the client: see /v2/docs/swift
    let toWaitlist: WaitlistEntry = try await api.post("/restaurants/123/waitlist", body: [
        "name": "Rodina Nováková",
        "phone": "+420603123456",
        "party_size": 4,
        "note": "s kočárkem",
    ]) // 201
    // klient: viz /v2/docs/dart
    final toWaitlist = pr.WaitlistEntry.fromJson(await api.post('/restaurants/123/waitlist', {
      'name': 'Rodina Nováková',
      'phone': '+420603123456',
      'party_size': 4,
      'note': 's kočárkem',
    })); // 201
    // the client: see /v2/docs/dart
    final toWaitlist = pr.WaitlistEntry.fromJson(await api.post('/restaurants/123/waitlist', {
      'name': 'Rodina Nováková',
      'phone': '+420603123456',
      'party_size': 4,
      'note': 's kočárkem',
    })); // 201
    // klient: viz /v2/docs/go
    res, err := api.Post(ctx, "/restaurants/123/waitlist", map[string]any{
    	"name": "Rodina Nováková",
    	"phone": "+420603123456",
    	"party_size": 4,
    	"note": "s kočárkem",
    }, nil)
    var toWaitlist model.WaitlistEntry // 201
    if err == nil {
    	err = res.Decode(&toWaitlist)
    }
    // the client: see /v2/docs/go
    res, err := api.Post(ctx, "/restaurants/123/waitlist", map[string]any{
    	"name": "Rodina Nováková",
    	"phone": "+420603123456",
    	"party_size": 4,
    	"note": "s kočárkem",
    }, nil)
    var toWaitlist model.WaitlistEntry // 201
    if err == nil {
    	err = res.Decode(&toWaitlist)
    }
    Příklad odpovědi 201Example answer 201
    {
      "id": "88",
      "name": "Rodina Nováková",
      "phone": "+420603123456",
      "party_size": 4,
      "note": "s kočárkem",
      "status": "waiting",
      "created_at": "2027-01-15T18:35:10+01:00",
      "notified_at": null,
      "can_sms": true
    }
  10. Záloha u rezervace z telefonu

    A deposit for a booking by phone

    POST /restaurants/{restaurant_id}/reservations/{reservation_id}/payment-link · sendReservationPaymentLink

    Rezervace se zálohou čeká (deposit.status pending). Odkaz k zaplacení kartou dostane host e-mailem a vy ho máte i pro SMS; zálohu jde také odpustit přes waiveReservationDeposit.

    A reservation with a deposit waits (deposit.status pending). The guest gets the link to pay by card by e-mail and you get it for an SMS too; the deposit can also be waived with waiveReservationDeposit.

    curl -X POST "https://api.mujprofirest.cz/v2/restaurants/123/reservations/5120/payment-link" \
      -H "Authorization: Bearer $ACCESS_TOKEN" \
      -H "Idempotency-Key: 01a318f0-a0c0-7ccf-871c-3bcd8509ecf8"
    curl -X POST "https://api.mujprofirest.cz/v2/restaurants/123/reservations/5120/payment-link" \
      -H "Authorization: Bearer $ACCESS_TOKEN" \
      -H "Idempotency-Key: 01a318f0-a0c0-7ccf-871c-3bcd8509ecf8"
    // klient: viz /v2/docs/js
    const sendReservationPaymentLink = await api.post('/restaurants/123/reservations/5120/payment-link', null); // 200
    // the client: see /v2/docs/js
    const sendReservationPaymentLink = await api.post('/restaurants/123/reservations/5120/payment-link', null); // 200
    // klient: viz /v2/docs/typescript
    const sendReservationPaymentLink = await api.post('/restaurants/123/reservations/5120/payment-link', null); // 200 ReservationPaymentLink
    // the client: see /v2/docs/typescript
    const sendReservationPaymentLink = await api.post('/restaurants/123/reservations/5120/payment-link', null); // 200 ReservationPaymentLink
    // klient: viz /v2/docs/php
    $sendReservationPaymentLink = $api->post('/restaurants/123/reservations/5120/payment-link', null); // 200
    // the client: see /v2/docs/php
    $sendReservationPaymentLink = $api->post('/restaurants/123/reservations/5120/payment-link', null); // 200
    // klient: viz /v2/docs/java
    // volání blokuje – na Androidu z pracovního vlákna (Dispatchers.IO)
    ReservationPaymentLink sendReservationPaymentLink = api.post("/restaurants/123/reservations/5120/payment-link", null, ReservationPaymentLink::fromJson); // 200
    // the client: see /v2/docs/java
    // the call blocks – on Android from a worker thread (Dispatchers.IO)
    ReservationPaymentLink sendReservationPaymentLink = api.post("/restaurants/123/reservations/5120/payment-link", null, ReservationPaymentLink::fromJson); // 200
    // klient: viz /v2/docs/java
    // volání blokuje – na Androidu z pracovního vlákna (Dispatchers.IO)
    val sendReservationPaymentLink = api.post("/restaurants/123/reservations/5120/payment-link", null, ReservationPaymentLink::fromJson) // 200
    // the client: see /v2/docs/java
    // the call blocks – on Android from a worker thread (Dispatchers.IO)
    val sendReservationPaymentLink = api.post("/restaurants/123/reservations/5120/payment-link", null, ReservationPaymentLink::fromJson) // 200
    // klient: viz /v2/docs/csharp
    var sendReservationPaymentLink = await api.PostAsync<ReservationPaymentLink>(
        "/restaurants/123/reservations/5120/payment-link",
        (object?)null
    ); // 200
    // the client: see /v2/docs/csharp
    var sendReservationPaymentLink = await api.PostAsync<ReservationPaymentLink>(
        "/restaurants/123/reservations/5120/payment-link",
        (object?)null
    ); // 200
    # klient: viz /v2/docs/python
    send_reservation_payment_link = api.post('/restaurants/123/reservations/5120/payment-link', None)  # 200
    # the client: see /v2/docs/python
    send_reservation_payment_link = api.post('/restaurants/123/reservations/5120/payment-link', None)  # 200
    // klient: viz /v2/docs/swift
    let sendReservationPaymentLink: ReservationPaymentLink = try await api.post("/restaurants/123/reservations/5120/payment-link", body: nil) // 200
    // the client: see /v2/docs/swift
    let sendReservationPaymentLink: ReservationPaymentLink = try await api.post("/restaurants/123/reservations/5120/payment-link", body: nil) // 200
    // klient: viz /v2/docs/dart
    final sendReservationPaymentLink = pr.ReservationPaymentLink.fromJson(await api.post('/restaurants/123/reservations/5120/payment-link', null)); // 200
    // the client: see /v2/docs/dart
    final sendReservationPaymentLink = pr.ReservationPaymentLink.fromJson(await api.post('/restaurants/123/reservations/5120/payment-link', null)); // 200
    // klient: viz /v2/docs/go
    res, err := api.Post(ctx, "/restaurants/123/reservations/5120/payment-link", nil, nil)
    var sendReservationPaymentLink model.ReservationPaymentLink // 200
    if err == nil {
    	err = res.Decode(&sendReservationPaymentLink)
    }
    // the client: see /v2/docs/go
    res, err := api.Post(ctx, "/restaurants/123/reservations/5120/payment-link", nil, nil)
    var sendReservationPaymentLink model.ReservationPaymentLink // 200
    if err == nil {
    	err = res.Decode(&sendReservationPaymentLink)
    }
    Příklad odpovědi 200Example answer 200
    {
      "url": "https://www.mujprofirest.cz/rezervace/sprava/4f1d0c9a7b2e8f61a3d5c7e9b0a2c4e6f8a1b3d5c7e9f0a2",
      "emailed": true,
      "due_at": "2027-01-15T12:40:12+01:00"
    }
  11. Přehled pro majitele a BI

    Statistics for the owner and BI

    GET /restaurants/{restaurant_id}/reservation-stats · getReservationStats

    Stejná čísla jako Přehled v Knize rezervací: kolik hostů přišlo a kolik ne, odkud rezervace přišly, zálohy a hodnocení. table_turn ukáže, jak dlouho hosté skutečně sedí, a navrhne lepší dobu u stolu; pravidla záloh (i pro hosty, kteří už nepřišli) jsou v getReservationSettings.

    The same numbers as the Overview of the reservation book: how many guests came and how many did not, where reservations came from, deposits and ratings. table_turn shows how long guests really sit and suggests a better table time; the deposit rules (also for guests who did not come before) are in getReservationSettings.

    curl "https://api.mujprofirest.cz/v2/restaurants/123/reservation-stats?from=2026-11-01&to=2026-11-30" \
      -H "Authorization: Bearer $ACCESS_TOKEN"
    curl "https://api.mujprofirest.cz/v2/restaurants/123/reservation-stats?from=2026-11-01&to=2026-11-30" \
      -H "Authorization: Bearer $ACCESS_TOKEN"
    // klient: viz /v2/docs/js
    const reservationStats = await api.get('/restaurants/123/reservation-stats', { query: { from: '2026-11-01', to: '2026-11-30' } }); // 200
    // the client: see /v2/docs/js
    const reservationStats = await api.get('/restaurants/123/reservation-stats', { query: { from: '2026-11-01', to: '2026-11-30' } }); // 200
    // klient: viz /v2/docs/typescript
    const reservationStats = await api.get('/restaurants/123/reservation-stats', { query: { from: '2026-11-01', to: '2026-11-30' } }); // 200 ReservationStats
    // the client: see /v2/docs/typescript
    const reservationStats = await api.get('/restaurants/123/reservation-stats', { query: { from: '2026-11-01', to: '2026-11-30' } }); // 200 ReservationStats
    // klient: viz /v2/docs/php
    $reservationStats = $api->get(
        '/restaurants/123/reservation-stats',
        ['query' => ['from' => '2026-11-01', 'to' => '2026-11-30']],
    ); // 200
    // the client: see /v2/docs/php
    $reservationStats = $api->get(
        '/restaurants/123/reservation-stats',
        ['query' => ['from' => '2026-11-01', 'to' => '2026-11-30']],
    ); // 200
    // klient: viz /v2/docs/java
    // volání blokuje – na Androidu z pracovního vlákna (Dispatchers.IO)
    ReservationStats reservationStats = api.get(
        "/restaurants/123/reservation-stats",
        RequestOptions.builder().query("from", "2026-11-01").query("to", "2026-11-30").build(),
        ReservationStats::fromJson
    ); // 200
    // the client: see /v2/docs/java
    // the call blocks – on Android from a worker thread (Dispatchers.IO)
    ReservationStats reservationStats = api.get(
        "/restaurants/123/reservation-stats",
        RequestOptions.builder().query("from", "2026-11-01").query("to", "2026-11-30").build(),
        ReservationStats::fromJson
    ); // 200
    // klient: viz /v2/docs/java
    // volání blokuje – na Androidu z pracovního vlákna (Dispatchers.IO)
    val reservationStats = api.get(
        "/restaurants/123/reservation-stats",
        RequestOptions.builder().query("from", "2026-11-01").query("to", "2026-11-30").build(),
        ReservationStats::fromJson,
    ) // 200
    // the client: see /v2/docs/java
    // the call blocks – on Android from a worker thread (Dispatchers.IO)
    val reservationStats = api.get(
        "/restaurants/123/reservation-stats",
        RequestOptions.builder().query("from", "2026-11-01").query("to", "2026-11-30").build(),
        ReservationStats::fromJson,
    ) // 200
    // klient: viz /v2/docs/csharp
    var reservationStats = await api.GetAsync<ReservationStats>(
        "/restaurants/123/reservation-stats",
        new RequestOptions { Query = new() { ["from"] = "2026-11-01", ["to"] = "2026-11-30" } }
    ); // 200
    // the client: see /v2/docs/csharp
    var reservationStats = await api.GetAsync<ReservationStats>(
        "/restaurants/123/reservation-stats",
        new RequestOptions { Query = new() { ["from"] = "2026-11-01", ["to"] = "2026-11-30" } }
    ); // 200
    # klient: viz /v2/docs/python
    reservation_stats = api.get('/restaurants/123/reservation-stats', query={'from': '2026-11-01', 'to': '2026-11-30'})  # 200
    # the client: see /v2/docs/python
    reservation_stats = api.get('/restaurants/123/reservation-stats', query={'from': '2026-11-01', 'to': '2026-11-30'})  # 200
    // klient: viz /v2/docs/swift
    let reservationStats: ReservationStats = try await api.get(
        "/restaurants/123/reservation-stats",
        options: .init(query: ["from": "2026-11-01", "to": "2026-11-30"])
    ) // 200
    // the client: see /v2/docs/swift
    let reservationStats: ReservationStats = try await api.get(
        "/restaurants/123/reservation-stats",
        options: .init(query: ["from": "2026-11-01", "to": "2026-11-30"])
    ) // 200
    // klient: viz /v2/docs/dart
    final reservationStats = pr.ReservationStats.fromJson(await api.get('/restaurants/123/reservation-stats', query: {'from': '2026-11-01', 'to': '2026-11-30'})); // 200
    // the client: see /v2/docs/dart
    final reservationStats = pr.ReservationStats.fromJson(await api.get('/restaurants/123/reservation-stats', query: {'from': '2026-11-01', 'to': '2026-11-30'})); // 200
    // klient: viz /v2/docs/go
    res, err := api.Get(
    	ctx,
    	"/restaurants/123/reservation-stats",
    	&profirest.RequestOptions{Query: map[string]any{"from": "2026-11-01", "to": "2026-11-30"}},
    )
    var reservationStats model.ReservationStats // 200
    if err == nil {
    	err = res.Decode(&reservationStats)
    }
    // the client: see /v2/docs/go
    res, err := api.Get(
    	ctx,
    	"/restaurants/123/reservation-stats",
    	&profirest.RequestOptions{Query: map[string]any{"from": "2026-11-01", "to": "2026-11-30"}},
    )
    var reservationStats model.ReservationStats // 200
    if err == nil {
    	err = res.Decode(&reservationStats)
    }
    Příklad odpovědi 200Example answer 200
    {
      "from": "2026-11-01",
      "to": "2026-11-30",
      "reservations": 412,
      "guests": 1386,
      "arrived": 371,
      "arrived_guests": 1251,
      "no_show": 9,
      "no_show_rate": 2.4,
      "cancelled": 24,
      "rejected": 2,
      "expired": 3,
      "upcoming": 0,
      "unresolved": 3,
      "avg_party_size": 3.4,
      "avg_lead_days": 4.2,
      "returning_guests": 58,
      "sources": [
        {
          "source": "online",
          "count": 238
        },
        {
          "source": "phone",
          "count": 121
        },
        {
          "source": "admin",
          "count": 53
        }
      ],
      "weekdays": [
        118,
        132,
        160,
        201,
        288,
        310,
        177
      ],
      "hours": [
        {
          "hour": 12,
          "guests": 214
        },
        {
          "hour": 18,
          "guests": 402
        },
        {
          "hour": 19,
          "guests": 466
        },
        {
          "hour": 20,
          "guests": 304
        }
      ],
      "deposits": {
        "paid": {
          "amount": 1840000,
          "currency": "CZK"
        },
        "refunded": {
          "amount": 120000,
          "currency": "CZK"
        },
        "forfeited": {
          "amount": 60000,
          "currency": "CZK"
        }
      },
      "ratings": {
        "count": 96,
        "average": 4.6,
        "low": 5
      },
      "services": [],
      "employees": [],
      "table_turn": {
        "measured": 342,
        "groups": [
          {
            "up_to_party_size": 2,
            "planned_minutes": 90,
            "measured": 151,
            "median_minutes": 68
          },
          {
            "up_to_party_size": 4,
            "planned_minutes": 120,
            "measured": 140,
            "median_minutes": 112
          },
          {
            "up_to_party_size": 99,
            "planned_minutes": 150,
            "measured": 51,
            "median_minutes": 158
          }
        ],
        "suggestions": [
          {
            "up_to_party_size": 2,
            "planned_minutes": 90,
            "median_minutes": 68,
            "suggested_minutes": 75,
            "measured": 151
          }
        ]
      }
    }

Scénář

Scenario

Útrata na pokoj (hotelová restaurace a bar)

Charging bills to a room (hotel restaurant and bar)

Pokladna hotelové restaurace nebo baru (lodging:read, lodging:write)The register of a hotel restaurant or bar (lodging:read, lodging:write)

Ubytovaný host si dá večeři nebo drink a neplatí hned – obsluha útratu zapíše na jeho pokoj a host ji zaplatí při odjezdu na recepci. Útrata se objeví v účtu pokoje na plachtě i na vyúčtování.

A staying guest has dinner or a drink and does not pay at once – the staff charge it to the room and the guest pays at the reception at departure. The charge shows in the account of the room on the room plan and on the bill.

  1. Má provozovna ubytování?

    Does the restaurant have accommodation?

    GET /restaurants/{restaurant_id}/device-settings · getDeviceSettings

    Tlačítko „Na pokoj“ ukažte, jen když je features.lodging true. Jinak operace vrací module_not_licensed.

    Show the „To the room“ button only when features.lodging is true. Otherwise the operations answer module_not_licensed.

    curl "https://api.mujprofirest.cz/v2/restaurants/123/device-settings" \
      -H "Authorization: Bearer $ACCESS_TOKEN"
    curl "https://api.mujprofirest.cz/v2/restaurants/123/device-settings" \
      -H "Authorization: Bearer $ACCESS_TOKEN"
    // klient: viz /v2/docs/js
    const deviceSettings = await api.get('/restaurants/123/device-settings'); // 200
    // the client: see /v2/docs/js
    const deviceSettings = await api.get('/restaurants/123/device-settings'); // 200
    // klient: viz /v2/docs/typescript
    const deviceSettings = await api.get('/restaurants/123/device-settings'); // 200 DeviceSettings
    // the client: see /v2/docs/typescript
    const deviceSettings = await api.get('/restaurants/123/device-settings'); // 200 DeviceSettings
    // klient: viz /v2/docs/php
    $deviceSettings = $api->get('/restaurants/123/device-settings'); // 200
    // the client: see /v2/docs/php
    $deviceSettings = $api->get('/restaurants/123/device-settings'); // 200
    // klient: viz /v2/docs/java
    // volání blokuje – na Androidu z pracovního vlákna (Dispatchers.IO)
    DeviceSettings deviceSettings = api.get("/restaurants/123/device-settings", DeviceSettings::fromJson); // 200
    // the client: see /v2/docs/java
    // the call blocks – on Android from a worker thread (Dispatchers.IO)
    DeviceSettings deviceSettings = api.get("/restaurants/123/device-settings", DeviceSettings::fromJson); // 200
    // klient: viz /v2/docs/java
    // volání blokuje – na Androidu z pracovního vlákna (Dispatchers.IO)
    val deviceSettings = api.get("/restaurants/123/device-settings", DeviceSettings::fromJson) // 200
    // the client: see /v2/docs/java
    // the call blocks – on Android from a worker thread (Dispatchers.IO)
    val deviceSettings = api.get("/restaurants/123/device-settings", DeviceSettings::fromJson) // 200
    // klient: viz /v2/docs/csharp
    var deviceSettings = await api.GetAsync<DeviceSettings>("/restaurants/123/device-settings"); // 200
    // the client: see /v2/docs/csharp
    var deviceSettings = await api.GetAsync<DeviceSettings>("/restaurants/123/device-settings"); // 200
    # klient: viz /v2/docs/python
    device_settings = api.get('/restaurants/123/device-settings')  # 200
    # the client: see /v2/docs/python
    device_settings = api.get('/restaurants/123/device-settings')  # 200
    // klient: viz /v2/docs/swift
    let deviceSettings: DeviceSettings = try await api.get("/restaurants/123/device-settings") // 200
    // the client: see /v2/docs/swift
    let deviceSettings: DeviceSettings = try await api.get("/restaurants/123/device-settings") // 200
    // klient: viz /v2/docs/dart
    final deviceSettings = pr.DeviceSettings.fromJson(await api.get('/restaurants/123/device-settings')); // 200
    // the client: see /v2/docs/dart
    final deviceSettings = pr.DeviceSettings.fromJson(await api.get('/restaurants/123/device-settings')); // 200
    // klient: viz /v2/docs/go
    res, err := api.Get(ctx, "/restaurants/123/device-settings", nil)
    var deviceSettings model.DeviceSettings // 200
    if err == nil {
    	err = res.Decode(&deviceSettings)
    }
    // the client: see /v2/docs/go
    res, err := api.Get(ctx, "/restaurants/123/device-settings", nil)
    var deviceSettings model.DeviceSettings // 200
    if err == nil {
    	err = res.Decode(&deviceSettings)
    }
    Příklad odpovědi 200Example answer 200
    {
      "restaurant": {
        "name": "Bistro U Lípy",
        "phone": "+420222333444",
        "website": "https://www.bistroulipy.cz",
        "address": {
          "street": "Vinohradská 1200/48",
          "city": "Praha 2",
          "postal_code": "120 00"
        },
        "location": {
          "lat": 50.0769,
          "lon": 14.4459
        },
        "currency": "CZK",
        "timezone": "Europe/Prague"
      },
      "company": {
        "name": "U Lípy gastro s.r.o.",
        "registration_number": "12345678",
        "vat_number": "CZ12345678",
        "vat_payer": true,
        "address": {
          "street": "Vinohradská 1200/48",
          "city": "Praha 2",
          "postal_code": "120 00"
        },
        "email": "ucetni@bistroulipy.cz"
      },
      "receipt_layouts": {
        "receipt": null,
        "takeaway": null
      },
      "predefined_notes": [
        {
          "id": "11",
          "text": "Bez cibule"
        },
        {
          "id": "12",
          "text": "Pálivé"
        },
        {
          "id": "13",
          "text": "S sebou"
        }
      ],
      "printers": [
        {
          "id": "5",
          "name": "Účtenky – bar",
          "sections": "all",
          "auto_print": false
        },
        {
          "id": "6",
          "name": "Bony – kuchyň",
          "sections": "kitchen",
          "auto_print": true
        }
      ],
      "kitchen_stations": [
        {
          "id": "2",
          "name": "Teplá kuchyně",
          "sections": "kitchen",
          "auto_print": false
        },
        {
          "id": "3",
          "name": "Pizza",
          "sections": "kitchen",
          "auto_print": false
        }
      ],
      "rooms": [
        {
          "id": "1",
          "name": "Restaurace",
          "width": 100,
          "height": 100,
          "tables": [
            {
              "id": "4",
              "name": "Stůl 4",
              "kind": "table",
              "code": "K7M2Q9XB",
              "left": 12,
              "top": 20,
              "width": 14,
              "height": 10
            },
            {
              "id": "7",
              "name": "Stůl 7",
              "kind": "table",
              "code": "3HFD8R2W",
              "left": 52,
              "top": 20,
              "width": 14,
              "height": 10
            },
            {
              "id": "30",
              "name": "Bar",
              "kind": "item",
              "code": null,
              "left": 80,
              "top": 70,
              "width": 18,
              "height": 25
            }
          ]
        }
      ],
      "kitchen": {
        "portion_mode": "local",
        "extra_ticket": false,
        "redirect_restaurant_id": null,
        "ready_sms": true
      },
      "eet": {
        "enabled": true,
        "premises_id": "273",
        "certificate_valid_to": "2029-12-31T23:59:59+01:00"
      },
      "features": {
        "kitchen": true,
        "multiple_cash_registers": true,
        "multiple_kitchen_devices": true,
        "other_devices": true,
        "attendance": true,
        "reservations": false,
        "lodging": false,
        "daily_menu": true,
        "table_map": true,
        "customer_database": true
      },
      "paid_until": "2027-12-31T23:59:59+01:00",
      "table_ordering": {
        "enabled": true,
        "confirm_mode": "first",
        "empty_table": "staff",
        "join_code_enabled": true,
        "max_quantity": 10,
        "expire_minutes": 10,
        "respect_opening_hours": true,
        "category_ids": [
          "320"
        ],
        "note_max_length": 32,
        "wifi_ssid": "U Lípy – hosté"
      },
      "pos": {
        "receipt_cancel_by": "staff",
        "takeaway_only": false,
        "calculator": {
          "enabled": true,
          "keys": [
            {
              "id": "17",
              "name": "Pečivo",
              "vat_rate": "12",
              "color": "#119b2d",
              "position": 1
            },
            {
              "id": "18",
              "name": "Zboží",
              "vat_rate": "21",
              "color": "#5b4ac0",
              "position": 2
            }
          ]
        }
      }
    }
  2. Výběr pokoje

    Picking the room

    GET /restaurants/{restaurant_id}/lodging/in-house · listInHouseStays

    Jen právě ubytovaní hosté, seřazení podle pokoje. Obsluha si podle jména ověří, že jde o správného hosta.

    Only guests staying now, ordered by room. The staff check by the name it is the right guest.

    curl "https://api.mujprofirest.cz/v2/restaurants/123/lodging/in-house" \
      -H "Authorization: Bearer $ACCESS_TOKEN"
    curl "https://api.mujprofirest.cz/v2/restaurants/123/lodging/in-house" \
      -H "Authorization: Bearer $ACCESS_TOKEN"
    // klient: viz /v2/docs/js
    const listInHouseStays = await api.get('/restaurants/123/lodging/in-house'); // 200
    // the client: see /v2/docs/js
    const listInHouseStays = await api.get('/restaurants/123/lodging/in-house'); // 200
    // klient: viz /v2/docs/typescript
    const listInHouseStays = await api.get('/restaurants/123/lodging/in-house'); // 200 InHouseStays
    // the client: see /v2/docs/typescript
    const listInHouseStays = await api.get('/restaurants/123/lodging/in-house'); // 200 InHouseStays
    // klient: viz /v2/docs/php
    $listInHouseStays = $api->get('/restaurants/123/lodging/in-house'); // 200
    // the client: see /v2/docs/php
    $listInHouseStays = $api->get('/restaurants/123/lodging/in-house'); // 200
    // klient: viz /v2/docs/java
    // volání blokuje – na Androidu z pracovního vlákna (Dispatchers.IO)
    InHouseStays listInHouseStays = api.get("/restaurants/123/lodging/in-house", InHouseStays::fromJson); // 200
    // the client: see /v2/docs/java
    // the call blocks – on Android from a worker thread (Dispatchers.IO)
    InHouseStays listInHouseStays = api.get("/restaurants/123/lodging/in-house", InHouseStays::fromJson); // 200
    // klient: viz /v2/docs/java
    // volání blokuje – na Androidu z pracovního vlákna (Dispatchers.IO)
    val listInHouseStays = api.get("/restaurants/123/lodging/in-house", InHouseStays::fromJson) // 200
    // the client: see /v2/docs/java
    // the call blocks – on Android from a worker thread (Dispatchers.IO)
    val listInHouseStays = api.get("/restaurants/123/lodging/in-house", InHouseStays::fromJson) // 200
    // klient: viz /v2/docs/csharp
    var listInHouseStays = await api.GetAsync<InHouseStays>("/restaurants/123/lodging/in-house"); // 200
    // the client: see /v2/docs/csharp
    var listInHouseStays = await api.GetAsync<InHouseStays>("/restaurants/123/lodging/in-house"); // 200
    # klient: viz /v2/docs/python
    list_in_house_stays = api.get('/restaurants/123/lodging/in-house')  # 200
    # the client: see /v2/docs/python
    list_in_house_stays = api.get('/restaurants/123/lodging/in-house')  # 200
    // klient: viz /v2/docs/swift
    let listInHouseStays: InHouseStays = try await api.get("/restaurants/123/lodging/in-house") // 200
    // the client: see /v2/docs/swift
    let listInHouseStays: InHouseStays = try await api.get("/restaurants/123/lodging/in-house") // 200
    // klient: viz /v2/docs/dart
    final listInHouseStays = pr.InHouseStays.fromJson(await api.get('/restaurants/123/lodging/in-house')); // 200
    // the client: see /v2/docs/dart
    final listInHouseStays = pr.InHouseStays.fromJson(await api.get('/restaurants/123/lodging/in-house')); // 200
    // klient: viz /v2/docs/go
    res, err := api.Get(ctx, "/restaurants/123/lodging/in-house", nil)
    var listInHouseStays model.InHouseStays // 200
    if err == nil {
    	err = res.Decode(&listInHouseStays)
    }
    // the client: see /v2/docs/go
    res, err := api.Get(ctx, "/restaurants/123/lodging/in-house", nil)
    var listInHouseStays model.InHouseStays // 200
    if err == nil {
    	err = res.Decode(&listInHouseStays)
    }
    Příklad odpovědi 200Example answer 200
    {
      "stays": [
        {
          "id": "193",
          "room": "101",
          "guest_name": "Jana Svobodová",
          "arrival": "2026-11-10",
          "departure": "2026-11-12",
          "guests": 2,
          "balance": {
            "amount": 496500,
            "currency": "CZK"
          },
          "package": null
        },
        {
          "id": "197",
          "room": "201",
          "guest_name": "Tomáš Král",
          "arrival": "2026-11-09",
          "departure": "2026-11-14",
          "guests": 4,
          "balance": {
            "amount": 1850000,
            "currency": "CZK"
          },
          "package": {
            "id": "7",
            "name": "3 + 1 noc zdarma s wellness"
          }
        }
      ]
    }
  3. Zápis útraty

    Charging the bill

    POST /restaurants/{restaurant_id}/lodging/stays/{stay_id}/charges · chargeToStay

    Celkovou částku s DPH a číslo dokladu v reference – opakovaný pokus se stejnou referencí útratu nezdvojí. Účet s více sazbami DPH pošlete jako více útrat. Host, který už odjel, vrátí 409 lodging_state_conflict.

    The total with VAT and the receipt number in reference – a repeated attempt with the same reference does not charge twice. Send a bill with more VAT rates as more charges. A guest who has left answers 409 lodging_state_conflict.

    curl "https://api.mujprofirest.cz/v2/restaurants/123/lodging/stays/193/charges" \
      -H "Authorization: Bearer $ACCESS_TOKEN" \
      -H "Idempotency-Key: 01a318f0-a0c0-7b45-99df-39be8ab7315f" \
      -H "Content-Type: application/json" \
      -d '{
      "name": "Restaurace – účet 2026/1184",
      "amount": {"amount": 84500, "currency": "CZK"},
      "vat_rate": 12,
      "reference": "pokladna-1:2026/1184"
    }'
    curl "https://api.mujprofirest.cz/v2/restaurants/123/lodging/stays/193/charges" \
      -H "Authorization: Bearer $ACCESS_TOKEN" \
      -H "Idempotency-Key: 01a318f0-a0c0-7b45-99df-39be8ab7315f" \
      -H "Content-Type: application/json" \
      -d '{
      "name": "Restaurace – účet 2026/1184",
      "amount": {"amount": 84500, "currency": "CZK"},
      "vat_rate": 12,
      "reference": "pokladna-1:2026/1184"
    }'
    // klient: viz /v2/docs/js
    const chargeToStay = await api.post('/restaurants/123/lodging/stays/193/charges', {
      name: 'Restaurace – účet 2026/1184',
      amount: { amount: 84500, currency: 'CZK' },
      vat_rate: 12,
      reference: 'pokladna-1:2026/1184',
    }); // 201
    // the client: see /v2/docs/js
    const chargeToStay = await api.post('/restaurants/123/lodging/stays/193/charges', {
      name: 'Restaurace – účet 2026/1184',
      amount: { amount: 84500, currency: 'CZK' },
      vat_rate: 12,
      reference: 'pokladna-1:2026/1184',
    }); // 201
    // klient: viz /v2/docs/typescript
    const chargeToStay = await api.post('/restaurants/123/lodging/stays/193/charges', {
      name: 'Restaurace – účet 2026/1184',
      amount: { amount: 84500, currency: 'CZK' },
      vat_rate: 12,
      reference: 'pokladna-1:2026/1184',
    }); // 201 StayFolio
    // the client: see /v2/docs/typescript
    const chargeToStay = await api.post('/restaurants/123/lodging/stays/193/charges', {
      name: 'Restaurace – účet 2026/1184',
      amount: { amount: 84500, currency: 'CZK' },
      vat_rate: 12,
      reference: 'pokladna-1:2026/1184',
    }); // 201 StayFolio
    // klient: viz /v2/docs/php
    $chargeToStay = $api->post('/restaurants/123/lodging/stays/193/charges', [
        'name' => 'Restaurace – účet 2026/1184',
        'amount' => ['amount' => 84500, 'currency' => 'CZK'],
        'vat_rate' => 12,
        'reference' => 'pokladna-1:2026/1184',
    ]); // 201
    // the client: see /v2/docs/php
    $chargeToStay = $api->post('/restaurants/123/lodging/stays/193/charges', [
        'name' => 'Restaurace – účet 2026/1184',
        'amount' => ['amount' => 84500, 'currency' => 'CZK'],
        'vat_rate' => 12,
        'reference' => 'pokladna-1:2026/1184',
    ]); // 201
    // klient: viz /v2/docs/java
    // volání blokuje – na Androidu z pracovního vlákna (Dispatchers.IO)
    StayFolio chargeToStay = api.post("/restaurants/123/lodging/stays/193/charges", Json.parse("""
        {
          "name": "Restaurace – účet 2026/1184",
          "amount": {"amount": 84500, "currency": "CZK"},
          "vat_rate": 12,
          "reference": "pokladna-1:2026/1184"
        }
        """), StayFolio::fromJson); // 201
    // the client: see /v2/docs/java
    // the call blocks – on Android from a worker thread (Dispatchers.IO)
    StayFolio chargeToStay = api.post("/restaurants/123/lodging/stays/193/charges", Json.parse("""
        {
          "name": "Restaurace – účet 2026/1184",
          "amount": {"amount": 84500, "currency": "CZK"},
          "vat_rate": 12,
          "reference": "pokladna-1:2026/1184"
        }
        """), StayFolio::fromJson); // 201
    // klient: viz /v2/docs/java
    // volání blokuje – na Androidu z pracovního vlákna (Dispatchers.IO)
    val chargeToStay = api.post("/restaurants/123/lodging/stays/193/charges", mapOf(
        "name" to "Restaurace – účet 2026/1184",
        "amount" to mapOf("amount" to 84500, "currency" to "CZK"),
        "vat_rate" to 12,
        "reference" to "pokladna-1:2026/1184",
    ), StayFolio::fromJson) // 201
    // the client: see /v2/docs/java
    // the call blocks – on Android from a worker thread (Dispatchers.IO)
    val chargeToStay = api.post("/restaurants/123/lodging/stays/193/charges", mapOf(
        "name" to "Restaurace – účet 2026/1184",
        "amount" to mapOf("amount" to 84500, "currency" to "CZK"),
        "vat_rate" to 12,
        "reference" to "pokladna-1:2026/1184",
    ), StayFolio::fromJson) // 201
    // klient: viz /v2/docs/csharp
    var chargeToStay = await api.PostAsync<StayFolio>("/restaurants/123/lodging/stays/193/charges", new {
        name = "Restaurace – účet 2026/1184",
        amount = new { amount = 84500, currency = "CZK" },
        vat_rate = 12,
        reference = "pokladna-1:2026/1184",
    }); // 201
    // the client: see /v2/docs/csharp
    var chargeToStay = await api.PostAsync<StayFolio>("/restaurants/123/lodging/stays/193/charges", new {
        name = "Restaurace – účet 2026/1184",
        amount = new { amount = 84500, currency = "CZK" },
        vat_rate = 12,
        reference = "pokladna-1:2026/1184",
    }); // 201
    # klient: viz /v2/docs/python
    charge_to_stay = api.post('/restaurants/123/lodging/stays/193/charges', {
        'name': 'Restaurace – účet 2026/1184',
        'amount': {'amount': 84500, 'currency': 'CZK'},
        'vat_rate': 12,
        'reference': 'pokladna-1:2026/1184',
    })  # 201
    # the client: see /v2/docs/python
    charge_to_stay = api.post('/restaurants/123/lodging/stays/193/charges', {
        'name': 'Restaurace – účet 2026/1184',
        'amount': {'amount': 84500, 'currency': 'CZK'},
        'vat_rate': 12,
        'reference': 'pokladna-1:2026/1184',
    })  # 201
    // klient: viz /v2/docs/swift
    let chargeToStay: StayFolio = try await api.post("/restaurants/123/lodging/stays/193/charges", body: [
        "name": "Restaurace – účet 2026/1184",
        "amount": ["amount": 84500, "currency": "CZK"],
        "vat_rate": 12,
        "reference": "pokladna-1:2026/1184",
    ]) // 201
    // the client: see /v2/docs/swift
    let chargeToStay: StayFolio = try await api.post("/restaurants/123/lodging/stays/193/charges", body: [
        "name": "Restaurace – účet 2026/1184",
        "amount": ["amount": 84500, "currency": "CZK"],
        "vat_rate": 12,
        "reference": "pokladna-1:2026/1184",
    ]) // 201
    // klient: viz /v2/docs/dart
    final chargeToStay = pr.StayFolio.fromJson(await api.post('/restaurants/123/lodging/stays/193/charges', {
      'name': 'Restaurace – účet 2026/1184',
      'amount': {'amount': 84500, 'currency': 'CZK'},
      'vat_rate': 12,
      'reference': 'pokladna-1:2026/1184',
    })); // 201
    // the client: see /v2/docs/dart
    final chargeToStay = pr.StayFolio.fromJson(await api.post('/restaurants/123/lodging/stays/193/charges', {
      'name': 'Restaurace – účet 2026/1184',
      'amount': {'amount': 84500, 'currency': 'CZK'},
      'vat_rate': 12,
      'reference': 'pokladna-1:2026/1184',
    })); // 201
    // klient: viz /v2/docs/go
    res, err := api.Post(ctx, "/restaurants/123/lodging/stays/193/charges", map[string]any{
    	"name": "Restaurace – účet 2026/1184",
    	"amount": map[string]any{"amount": 84500, "currency": "CZK"},
    	"vat_rate": 12,
    	"reference": "pokladna-1:2026/1184",
    }, nil)
    var chargeToStay model.StayFolio // 201
    if err == nil {
    	err = res.Decode(&chargeToStay)
    }
    // the client: see /v2/docs/go
    res, err := api.Post(ctx, "/restaurants/123/lodging/stays/193/charges", map[string]any{
    	"name": "Restaurace – účet 2026/1184",
    	"amount": map[string]any{"amount": 84500, "currency": "CZK"},
    	"vat_rate": 12,
    	"reference": "pokladna-1:2026/1184",
    }, nil)
    var chargeToStay model.StayFolio // 201
    if err == nil {
    	err = res.Decode(&chargeToStay)
    }
    Příklad odpovědi 200Example answer 200
    {
      "stay_id": "193",
      "status": "checked_in",
      "package": null,
      "room": "101",
      "guest_name": "Jana Svobodová",
      "arrival": "2026-11-10",
      "departure": "2026-11-12",
      "accommodation": {
        "amount": 600000,
        "currency": "CZK"
      },
      "city_tax": {
        "amount": {
          "amount": 12000,
          "currency": "CZK"
        },
        "estimate": false
      },
      "lines": [
        {
          "id": "301",
          "kind": "service",
          "name": "Snídaně",
          "quantity": 4,
          "unit_price": {
            "amount": 25000,
            "currency": "CZK"
          },
          "total": {
            "amount": 100000,
            "currency": "CZK"
          },
          "vat_rate": 12,
          "date_from": "2026-11-10",
          "date_to": "2026-11-12",
          "reference": null,
          "created_at": "2026-11-10T15:12:40+01:00"
        },
        {
          "id": "305",
          "kind": "pos",
          "name": "Restaurace – účet 2026/1184",
          "quantity": 1,
          "unit_price": {
            "amount": 84500,
            "currency": "CZK"
          },
          "total": {
            "amount": 84500,
            "currency": "CZK"
          },
          "vat_rate": 12,
          "date_from": null,
          "date_to": null,
          "reference": "pokladna-1:2026/1184",
          "created_at": "2026-11-10T21:04:12+01:00"
        }
      ],
      "total": {
        "amount": 796500,
        "currency": "CZK"
      },
      "payments": [
        {
          "id": "41",
          "amount": {
            "amount": 300000,
            "currency": "CZK"
          },
          "method": "transfer",
          "note": "záloha",
          "paid_at": "2026-11-03T09:30:00+01:00"
        }
      ],
      "paid": {
        "amount": 300000,
        "currency": "CZK"
      },
      "balance": {
        "amount": 496500,
        "currency": "CZK"
      }
    }
  4. Kolik host dluží

    What the guest owes

    GET /restaurants/{restaurant_id}/lodging/stays/{stay_id}/folio · getStayFolio

    Celý účet pokoje se zůstatkem – třeba pro bar, který chce vidět útratu hosta před dalším drinkem.

    The whole account of the room with the balance – for example for a bar that wants to see the guest's charges before the next drink.

    curl "https://api.mujprofirest.cz/v2/restaurants/123/lodging/stays/193/folio" \
      -H "Authorization: Bearer $ACCESS_TOKEN"
    curl "https://api.mujprofirest.cz/v2/restaurants/123/lodging/stays/193/folio" \
      -H "Authorization: Bearer $ACCESS_TOKEN"
    // klient: viz /v2/docs/js
    const stayFolio = await api.get('/restaurants/123/lodging/stays/193/folio'); // 200
    // the client: see /v2/docs/js
    const stayFolio = await api.get('/restaurants/123/lodging/stays/193/folio'); // 200
    // klient: viz /v2/docs/typescript
    const stayFolio = await api.get('/restaurants/123/lodging/stays/193/folio'); // 200 StayFolio
    // the client: see /v2/docs/typescript
    const stayFolio = await api.get('/restaurants/123/lodging/stays/193/folio'); // 200 StayFolio
    // klient: viz /v2/docs/php
    $stayFolio = $api->get('/restaurants/123/lodging/stays/193/folio'); // 200
    // the client: see /v2/docs/php
    $stayFolio = $api->get('/restaurants/123/lodging/stays/193/folio'); // 200
    // klient: viz /v2/docs/java
    // volání blokuje – na Androidu z pracovního vlákna (Dispatchers.IO)
    StayFolio stayFolio = api.get("/restaurants/123/lodging/stays/193/folio", StayFolio::fromJson); // 200
    // the client: see /v2/docs/java
    // the call blocks – on Android from a worker thread (Dispatchers.IO)
    StayFolio stayFolio = api.get("/restaurants/123/lodging/stays/193/folio", StayFolio::fromJson); // 200
    // klient: viz /v2/docs/java
    // volání blokuje – na Androidu z pracovního vlákna (Dispatchers.IO)
    val stayFolio = api.get("/restaurants/123/lodging/stays/193/folio", StayFolio::fromJson) // 200
    // the client: see /v2/docs/java
    // the call blocks – on Android from a worker thread (Dispatchers.IO)
    val stayFolio = api.get("/restaurants/123/lodging/stays/193/folio", StayFolio::fromJson) // 200
    // klient: viz /v2/docs/csharp
    var stayFolio = await api.GetAsync<StayFolio>("/restaurants/123/lodging/stays/193/folio"); // 200
    // the client: see /v2/docs/csharp
    var stayFolio = await api.GetAsync<StayFolio>("/restaurants/123/lodging/stays/193/folio"); // 200
    # klient: viz /v2/docs/python
    stay_folio = api.get('/restaurants/123/lodging/stays/193/folio')  # 200
    # the client: see /v2/docs/python
    stay_folio = api.get('/restaurants/123/lodging/stays/193/folio')  # 200
    // klient: viz /v2/docs/swift
    let stayFolio: StayFolio = try await api.get("/restaurants/123/lodging/stays/193/folio") // 200
    // the client: see /v2/docs/swift
    let stayFolio: StayFolio = try await api.get("/restaurants/123/lodging/stays/193/folio") // 200
    // klient: viz /v2/docs/dart
    final stayFolio = pr.StayFolio.fromJson(await api.get('/restaurants/123/lodging/stays/193/folio')); // 200
    // the client: see /v2/docs/dart
    final stayFolio = pr.StayFolio.fromJson(await api.get('/restaurants/123/lodging/stays/193/folio')); // 200
    // klient: viz /v2/docs/go
    res, err := api.Get(ctx, "/restaurants/123/lodging/stays/193/folio", nil)
    var stayFolio model.StayFolio // 200
    if err == nil {
    	err = res.Decode(&stayFolio)
    }
    // the client: see /v2/docs/go
    res, err := api.Get(ctx, "/restaurants/123/lodging/stays/193/folio", nil)
    var stayFolio model.StayFolio // 200
    if err == nil {
    	err = res.Decode(&stayFolio)
    }
    Příklad odpovědi 200Example answer 200
    {
      "stay_id": "193",
      "status": "checked_in",
      "package": null,
      "room": "101",
      "guest_name": "Jana Svobodová",
      "arrival": "2026-11-10",
      "departure": "2026-11-12",
      "accommodation": {
        "amount": 600000,
        "currency": "CZK"
      },
      "city_tax": {
        "amount": {
          "amount": 12000,
          "currency": "CZK"
        },
        "estimate": false
      },
      "lines": [
        {
          "id": "301",
          "kind": "service",
          "name": "Snídaně",
          "quantity": 4,
          "unit_price": {
            "amount": 25000,
            "currency": "CZK"
          },
          "total": {
            "amount": 100000,
            "currency": "CZK"
          },
          "vat_rate": 12,
          "date_from": "2026-11-10",
          "date_to": "2026-11-12",
          "reference": null,
          "created_at": "2026-11-10T15:12:40+01:00"
        },
        {
          "id": "305",
          "kind": "pos",
          "name": "Restaurace – účet 2026/1184",
          "quantity": 1,
          "unit_price": {
            "amount": 84500,
            "currency": "CZK"
          },
          "total": {
            "amount": 84500,
            "currency": "CZK"
          },
          "vat_rate": 12,
          "date_from": null,
          "date_to": null,
          "reference": "pokladna-1:2026/1184",
          "created_at": "2026-11-10T21:04:12+01:00"
        }
      ],
      "total": {
        "amount": 796500,
        "currency": "CZK"
      },
      "payments": [
        {
          "id": "41",
          "amount": {
            "amount": 300000,
            "currency": "CZK"
          },
          "method": "transfer",
          "note": "záloha",
          "paid_at": "2026-11-03T09:30:00+01:00"
        }
      ],
      "paid": {
        "amount": 300000,
        "currency": "CZK"
      },
      "balance": {
        "amount": 496500,
        "currency": "CZK"
      }
    }

Scénář

Scenario

Turniket wellness a čtečka na snídani

A wellness gate and a breakfast reader

Turniket, čtečka u vstupu, aplikace obsluhy (guest_passes:check)A gate, a reader at the entrance, a staff application (guest_passes:check)

Host má QR kód na stránce pobytu a na kartě hosta. Čtečka ho pošle serveru, ten podle účtu pokoje řekne, jestli host smí dovnitř (neomezeně, tolik osob denně, tolikrát za pobyt), a vstup zapíše.

The guest has a QR code on the stay page and on the guest card. The reader sends it to the server, which says by the account of the room whether the guest may go in (unlimited, so many persons a day, so many times a stay) and records the entry.

  1. Ověření a vstup

    Check and entry

    POST /restaurants/{restaurant_id}/guest-passes/check · checkGuestPass

    result ok = otevřít; denied = nepustit a ukázat text. Kolik osob jde najednou, pošlete v persons; jen ověřit bez zápisu jde s record: false.

    result ok = open; denied = do not let in and show text. Send how many persons go in at once in persons; to check without recording use record: false.

    curl "https://api.mujprofirest.cz/v2/restaurants/123/guest-passes/check" \
      -H "Authorization: Bearer $ACCESS_TOKEN" \
      -H "Idempotency-Key: 01a318f0-a0c0-72d4-9c43-6a44935e72ff" \
      -H "Content-Type: application/json" \
      -d '{
      "code": "PRU-300-3EE8T62F7H",
      "place": "wellness",
      "persons": 2,
      "device": "Vstup do wellness"
    }'
    curl "https://api.mujprofirest.cz/v2/restaurants/123/guest-passes/check" \
      -H "Authorization: Bearer $ACCESS_TOKEN" \
      -H "Idempotency-Key: 01a318f0-a0c0-72d4-9c43-6a44935e72ff" \
      -H "Content-Type: application/json" \
      -d '{
      "code": "PRU-300-3EE8T62F7H",
      "place": "wellness",
      "persons": 2,
      "device": "Vstup do wellness"
    }'
    // klient: viz /v2/docs/js
    const guestPass = await api.post('/restaurants/123/guest-passes/check', {
      code: 'PRU-300-3EE8T62F7H',
      place: 'wellness',
      persons: 2,
      device: 'Vstup do wellness',
    }); // 200
    // the client: see /v2/docs/js
    const guestPass = await api.post('/restaurants/123/guest-passes/check', {
      code: 'PRU-300-3EE8T62F7H',
      place: 'wellness',
      persons: 2,
      device: 'Vstup do wellness',
    }); // 200
    // klient: viz /v2/docs/typescript
    const guestPass = await api.post('/restaurants/123/guest-passes/check', {
      code: 'PRU-300-3EE8T62F7H',
      place: 'wellness',
      persons: 2,
      device: 'Vstup do wellness',
    }); // 200 GuestPassCheck
    // the client: see /v2/docs/typescript
    const guestPass = await api.post('/restaurants/123/guest-passes/check', {
      code: 'PRU-300-3EE8T62F7H',
      place: 'wellness',
      persons: 2,
      device: 'Vstup do wellness',
    }); // 200 GuestPassCheck
    // klient: viz /v2/docs/php
    $guestPass = $api->post('/restaurants/123/guest-passes/check', [
        'code' => 'PRU-300-3EE8T62F7H',
        'place' => 'wellness',
        'persons' => 2,
        'device' => 'Vstup do wellness',
    ]); // 200
    // the client: see /v2/docs/php
    $guestPass = $api->post('/restaurants/123/guest-passes/check', [
        'code' => 'PRU-300-3EE8T62F7H',
        'place' => 'wellness',
        'persons' => 2,
        'device' => 'Vstup do wellness',
    ]); // 200
    // klient: viz /v2/docs/java
    // volání blokuje – na Androidu z pracovního vlákna (Dispatchers.IO)
    GuestPassCheck guestPass = api.post("/restaurants/123/guest-passes/check", Json.parse("""
        {
          "code": "PRU-300-3EE8T62F7H",
          "place": "wellness",
          "persons": 2,
          "device": "Vstup do wellness"
        }
        """), GuestPassCheck::fromJson); // 200
    // the client: see /v2/docs/java
    // the call blocks – on Android from a worker thread (Dispatchers.IO)
    GuestPassCheck guestPass = api.post("/restaurants/123/guest-passes/check", Json.parse("""
        {
          "code": "PRU-300-3EE8T62F7H",
          "place": "wellness",
          "persons": 2,
          "device": "Vstup do wellness"
        }
        """), GuestPassCheck::fromJson); // 200
    // klient: viz /v2/docs/java
    // volání blokuje – na Androidu z pracovního vlákna (Dispatchers.IO)
    val guestPass = api.post("/restaurants/123/guest-passes/check", mapOf(
        "code" to "PRU-300-3EE8T62F7H",
        "place" to "wellness",
        "persons" to 2,
        "device" to "Vstup do wellness",
    ), GuestPassCheck::fromJson) // 200
    // the client: see /v2/docs/java
    // the call blocks – on Android from a worker thread (Dispatchers.IO)
    val guestPass = api.post("/restaurants/123/guest-passes/check", mapOf(
        "code" to "PRU-300-3EE8T62F7H",
        "place" to "wellness",
        "persons" to 2,
        "device" to "Vstup do wellness",
    ), GuestPassCheck::fromJson) // 200
    // klient: viz /v2/docs/csharp
    var guestPass = await api.PostAsync<GuestPassCheck>("/restaurants/123/guest-passes/check", new {
        code = "PRU-300-3EE8T62F7H",
        place = "wellness",
        persons = 2,
        device = "Vstup do wellness",
    }); // 200
    // the client: see /v2/docs/csharp
    var guestPass = await api.PostAsync<GuestPassCheck>("/restaurants/123/guest-passes/check", new {
        code = "PRU-300-3EE8T62F7H",
        place = "wellness",
        persons = 2,
        device = "Vstup do wellness",
    }); // 200
    # klient: viz /v2/docs/python
    guest_pass = api.post('/restaurants/123/guest-passes/check', {
        'code': 'PRU-300-3EE8T62F7H',
        'place': 'wellness',
        'persons': 2,
        'device': 'Vstup do wellness',
    })  # 200
    # the client: see /v2/docs/python
    guest_pass = api.post('/restaurants/123/guest-passes/check', {
        'code': 'PRU-300-3EE8T62F7H',
        'place': 'wellness',
        'persons': 2,
        'device': 'Vstup do wellness',
    })  # 200
    // klient: viz /v2/docs/swift
    let guestPass: GuestPassCheck = try await api.post("/restaurants/123/guest-passes/check", body: [
        "code": "PRU-300-3EE8T62F7H",
        "place": "wellness",
        "persons": 2,
        "device": "Vstup do wellness",
    ]) // 200
    // the client: see /v2/docs/swift
    let guestPass: GuestPassCheck = try await api.post("/restaurants/123/guest-passes/check", body: [
        "code": "PRU-300-3EE8T62F7H",
        "place": "wellness",
        "persons": 2,
        "device": "Vstup do wellness",
    ]) // 200
    // klient: viz /v2/docs/dart
    final guestPass = pr.GuestPassCheck.fromJson(await api.post('/restaurants/123/guest-passes/check', {
      'code': 'PRU-300-3EE8T62F7H',
      'place': 'wellness',
      'persons': 2,
      'device': 'Vstup do wellness',
    })); // 200
    // the client: see /v2/docs/dart
    final guestPass = pr.GuestPassCheck.fromJson(await api.post('/restaurants/123/guest-passes/check', {
      'code': 'PRU-300-3EE8T62F7H',
      'place': 'wellness',
      'persons': 2,
      'device': 'Vstup do wellness',
    })); // 200
    // klient: viz /v2/docs/go
    res, err := api.Post(ctx, "/restaurants/123/guest-passes/check", map[string]any{
    	"code": "PRU-300-3EE8T62F7H",
    	"place": "wellness",
    	"persons": 2,
    	"device": "Vstup do wellness",
    }, nil)
    var guestPass model.GuestPassCheck // 200
    if err == nil {
    	err = res.Decode(&guestPass)
    }
    // the client: see /v2/docs/go
    res, err := api.Post(ctx, "/restaurants/123/guest-passes/check", map[string]any{
    	"code": "PRU-300-3EE8T62F7H",
    	"place": "wellness",
    	"persons": 2,
    	"device": "Vstup do wellness",
    }, nil)
    var guestPass model.GuestPassCheck // 200
    if err == nil {
    	err = res.Decode(&guestPass)
    }
    Příklad odpovědi 200Example answer 200
    {
      "result": "ok",
      "title": "Pokoj 201 · 2 osoby",
      "text": "Wellness neomezeně do 5. 11.",
      "check_id": "5521",
      "stay": {
        "id": "300",
        "room": "201",
        "persons": 2,
        "arrival": "2026-11-01",
        "departure": "2026-11-05",
        "package": "3 + 1 noc zdarma s wellness"
      },
      "used_today": 2,
      "allowed_today": null
    }
  2. Host nakonec nešel

    The guest did not go in

    POST /restaurants/{restaurant_id}/guest-passes/checks/{check_id}/undo · undoGuestPassCheck

    Vstup se vrátí a nepočítá do denního limitu.

    The entry is undone and does not count to the daily limit.

    curl -X POST "https://api.mujprofirest.cz/v2/restaurants/123/guest-passes/checks/5521/undo" \
      -H "Authorization: Bearer $ACCESS_TOKEN" \
      -H "Idempotency-Key: 01a318f0-a0c0-7e7e-998e-3c5af3025287"
    curl -X POST "https://api.mujprofirest.cz/v2/restaurants/123/guest-passes/checks/5521/undo" \
      -H "Authorization: Bearer $ACCESS_TOKEN" \
      -H "Idempotency-Key: 01a318f0-a0c0-7e7e-998e-3c5af3025287"
    // klient: viz /v2/docs/js
    await api.post('/restaurants/123/guest-passes/checks/5521/undo', null);
    // the client: see /v2/docs/js
    await api.post('/restaurants/123/guest-passes/checks/5521/undo', null);
    // klient: viz /v2/docs/typescript
    await api.post('/restaurants/123/guest-passes/checks/5521/undo', null);
    // the client: see /v2/docs/typescript
    await api.post('/restaurants/123/guest-passes/checks/5521/undo', null);
    // klient: viz /v2/docs/php
    $api->post('/restaurants/123/guest-passes/checks/5521/undo', null);
    // the client: see /v2/docs/php
    $api->post('/restaurants/123/guest-passes/checks/5521/undo', null);
    // klient: viz /v2/docs/java
    // volání blokuje – na Androidu z pracovního vlákna (Dispatchers.IO)
    api.post("/restaurants/123/guest-passes/checks/5521/undo", null);
    // the client: see /v2/docs/java
    // the call blocks – on Android from a worker thread (Dispatchers.IO)
    api.post("/restaurants/123/guest-passes/checks/5521/undo", null);
    // klient: viz /v2/docs/java
    // volání blokuje – na Androidu z pracovního vlákna (Dispatchers.IO)
    api.post("/restaurants/123/guest-passes/checks/5521/undo", null)
    // the client: see /v2/docs/java
    // the call blocks – on Android from a worker thread (Dispatchers.IO)
    api.post("/restaurants/123/guest-passes/checks/5521/undo", null)
    // klient: viz /v2/docs/csharp
    await api.PostAsync("/restaurants/123/guest-passes/checks/5521/undo", (object?)null);
    // the client: see /v2/docs/csharp
    await api.PostAsync("/restaurants/123/guest-passes/checks/5521/undo", (object?)null);
    # klient: viz /v2/docs/python
    api.post('/restaurants/123/guest-passes/checks/5521/undo', None)
    # the client: see /v2/docs/python
    api.post('/restaurants/123/guest-passes/checks/5521/undo', None)
    // klient: viz /v2/docs/swift
    try await api.post("/restaurants/123/guest-passes/checks/5521/undo", body: nil)
    // the client: see /v2/docs/swift
    try await api.post("/restaurants/123/guest-passes/checks/5521/undo", body: nil)
    // klient: viz /v2/docs/dart
    await api.post('/restaurants/123/guest-passes/checks/5521/undo', null);
    // the client: see /v2/docs/dart
    await api.post('/restaurants/123/guest-passes/checks/5521/undo', null);
    // klient: viz /v2/docs/go
    _, err := api.Post(ctx, "/restaurants/123/guest-passes/checks/5521/undo", nil, nil)
    // the client: see /v2/docs/go
    _, err := api.Post(ctx, "/restaurants/123/guest-passes/checks/5521/undo", nil, nil)
  3. Co balíčky obsahují

    What packages include

    GET /restaurants/{restaurant_id}/lodging/packages · listLodgingPackages

    Pro informační obrazovky a web: noci zdarma, sleva, příplatek a služby v ceně.

    For information screens and the website: free nights, discount, surcharge and included services.

    curl "https://api.mujprofirest.cz/v2/restaurants/123/lodging/packages" \
      -H "Authorization: Bearer $ACCESS_TOKEN"
    curl "https://api.mujprofirest.cz/v2/restaurants/123/lodging/packages" \
      -H "Authorization: Bearer $ACCESS_TOKEN"
    // klient: viz /v2/docs/js
    const listLodgingPackages = await api.get('/restaurants/123/lodging/packages'); // 200
    // the client: see /v2/docs/js
    const listLodgingPackages = await api.get('/restaurants/123/lodging/packages'); // 200
    // klient: viz /v2/docs/typescript
    const listLodgingPackages = await api.get('/restaurants/123/lodging/packages'); // 200 LodgingPackageList
    // the client: see /v2/docs/typescript
    const listLodgingPackages = await api.get('/restaurants/123/lodging/packages'); // 200 LodgingPackageList
    // klient: viz /v2/docs/php
    $listLodgingPackages = $api->get('/restaurants/123/lodging/packages'); // 200
    // the client: see /v2/docs/php
    $listLodgingPackages = $api->get('/restaurants/123/lodging/packages'); // 200
    // klient: viz /v2/docs/java
    // volání blokuje – na Androidu z pracovního vlákna (Dispatchers.IO)
    LodgingPackageList listLodgingPackages = api.get("/restaurants/123/lodging/packages", LodgingPackageList::fromJson); // 200
    // the client: see /v2/docs/java
    // the call blocks – on Android from a worker thread (Dispatchers.IO)
    LodgingPackageList listLodgingPackages = api.get("/restaurants/123/lodging/packages", LodgingPackageList::fromJson); // 200
    // klient: viz /v2/docs/java
    // volání blokuje – na Androidu z pracovního vlákna (Dispatchers.IO)
    val listLodgingPackages = api.get("/restaurants/123/lodging/packages", LodgingPackageList::fromJson) // 200
    // the client: see /v2/docs/java
    // the call blocks – on Android from a worker thread (Dispatchers.IO)
    val listLodgingPackages = api.get("/restaurants/123/lodging/packages", LodgingPackageList::fromJson) // 200
    // klient: viz /v2/docs/csharp
    var listLodgingPackages = await api.GetAsync<LodgingPackageList>("/restaurants/123/lodging/packages"); // 200
    // the client: see /v2/docs/csharp
    var listLodgingPackages = await api.GetAsync<LodgingPackageList>("/restaurants/123/lodging/packages"); // 200
    # klient: viz /v2/docs/python
    list_lodging_packages = api.get('/restaurants/123/lodging/packages')  # 200
    # the client: see /v2/docs/python
    list_lodging_packages = api.get('/restaurants/123/lodging/packages')  # 200
    // klient: viz /v2/docs/swift
    let listLodgingPackages: LodgingPackageList = try await api.get("/restaurants/123/lodging/packages") // 200
    // the client: see /v2/docs/swift
    let listLodgingPackages: LodgingPackageList = try await api.get("/restaurants/123/lodging/packages") // 200
    // klient: viz /v2/docs/dart
    final listLodgingPackages = pr.LodgingPackageList.fromJson(await api.get('/restaurants/123/lodging/packages')); // 200
    // the client: see /v2/docs/dart
    final listLodgingPackages = pr.LodgingPackageList.fromJson(await api.get('/restaurants/123/lodging/packages')); // 200
    // klient: viz /v2/docs/go
    res, err := api.Get(ctx, "/restaurants/123/lodging/packages", nil)
    var listLodgingPackages model.LodgingPackageList // 200
    if err == nil {
    	err = res.Decode(&listLodgingPackages)
    }
    // the client: see /v2/docs/go
    res, err := api.Get(ctx, "/restaurants/123/lodging/packages", nil)
    var listLodgingPackages model.LodgingPackageList // 200
    if err == nil {
    	err = res.Decode(&listLodgingPackages)
    }
    Příklad odpovědi 200Example answer 200
    {
      "data": [
        {
          "id": "7",
          "name": "3 + 1 noc zdarma s wellness",
          "description": "Čtvrtou noc máte od nás. Wellness bez omezení a snídaně v ceně.",
          "room_type_ids": [],
          "min_nights": 4,
          "pay_nights": 3,
          "free_nights": 1,
          "discount_percent": 0,
          "price_extra": {
            "amount": 0,
            "currency": "CZK"
          },
          "services": [
            {
              "id": "4",
              "name": "Snídaně",
              "category": "breakfast"
            },
            {
              "id": "9",
              "name": "Wellness neomezeně",
              "category": "wellness"
            }
          ],
          "valid_from": null,
          "valid_to": null,
          "online": true
        },
        {
          "id": "8",
          "name": "Romantický víkend",
          "description": "Lahev sektu na pokoji a masáž.",
          "room_type_ids": [
            "43"
          ],
          "min_nights": 2,
          "pay_nights": 0,
          "free_nights": 0,
          "discount_percent": 0,
          "price_extra": {
            "amount": 149000,
            "currency": "CZK"
          },
          "services": [
            {
              "id": "6",
              "name": "Lahev sektu",
              "category": "drink"
            }
          ],
          "valid_from": "2026-11-01",
          "valid_to": "2027-02-28",
          "online": true
        }
      ]
    }

Scénář

Scenario

Aplikace pro pokojské a údržbu

An application for housekeepers and maintenance

Aplikace pokojských, systém údržby (housekeeping:read, housekeeping:write)A housekeeping application, a maintenance system (housekeeping:read, housekeeping:write)

Pokojská má v telefonu pokoje, které dnes uklízí, odškrtává hotové a hlásí závady. Recepce na plachtě hned vidí, který pokoj je uklizený, a pokoj se závadou se sám vyřadí z prodeje.

The housekeeper has the rooms to clean today in her phone, ticks off what is done and reports faults. The reception sees at once on the room plan which room is clean, and a room with a fault takes itself out of sale.

  1. Úkoly dne

    The tasks of the day

    GET /restaurants/{restaurant_id}/housekeeping · getHousekeepingDay

    Pokoje jsou seřazené od nejnaléhavějšího: kam dnes přijíždí host do neuklizeného pokoje. assigned_employee_id řekne, kterou pokojskou má pokoj přidělenou – ukažte jí jen její pokoje. Jména hostů tu nejsou.

    The rooms are ordered from the most urgent: where guests arrive today to a room not cleaned yet. assigned_employee_id tells which housekeeper the room is assigned to – show her only her rooms. Guests' names are not there.

    curl "https://api.mujprofirest.cz/v2/restaurants/123/housekeeping?date=2026-11-05" \
      -H "Authorization: Bearer $ACCESS_TOKEN" \
      -H "Profirest-Staff-Token: $STAFF_TOKEN"
    curl "https://api.mujprofirest.cz/v2/restaurants/123/housekeeping?date=2026-11-05" \
      -H "Authorization: Bearer $ACCESS_TOKEN" \
      -H "Profirest-Staff-Token: $STAFF_TOKEN"
    // klient: viz /v2/docs/js
    // token zaměstnance přidá knihovna sama (po přihlášení zaměstnance)
    const housekeepingDay = await api.get('/restaurants/123/housekeeping', { query: { date: '2026-11-05' } }); // 200
    // the client: see /v2/docs/js
    // the library adds the employee's token itself (after the employee signs in)
    const housekeepingDay = await api.get('/restaurants/123/housekeeping', { query: { date: '2026-11-05' } }); // 200
    // klient: viz /v2/docs/typescript
    // token zaměstnance přidá knihovna sama (po přihlášení zaměstnance)
    const housekeepingDay = await api.get('/restaurants/123/housekeeping', { query: { date: '2026-11-05' } }); // 200 HousekeepingDay
    // the client: see /v2/docs/typescript
    // the library adds the employee's token itself (after the employee signs in)
    const housekeepingDay = await api.get('/restaurants/123/housekeeping', { query: { date: '2026-11-05' } }); // 200 HousekeepingDay
    // klient: viz /v2/docs/php
    // token zaměstnance přidá knihovna sama (po přihlášení zaměstnance)
    $housekeepingDay = $api->get('/restaurants/123/housekeeping', ['query' => ['date' => '2026-11-05']]); // 200
    // the client: see /v2/docs/php
    // the library adds the employee's token itself (after the employee signs in)
    $housekeepingDay = $api->get('/restaurants/123/housekeeping', ['query' => ['date' => '2026-11-05']]); // 200
    // klient: viz /v2/docs/java
    // volání blokuje – na Androidu z pracovního vlákna (Dispatchers.IO)
    // token zaměstnance přidá knihovna sama (po přihlášení zaměstnance)
    HousekeepingDay housekeepingDay = api.get(
        "/restaurants/123/housekeeping",
        RequestOptions.builder().query("date", "2026-11-05").build(),
        HousekeepingDay::fromJson
    ); // 200
    // the client: see /v2/docs/java
    // the call blocks – on Android from a worker thread (Dispatchers.IO)
    // the library adds the employee's token itself (after the employee signs in)
    HousekeepingDay housekeepingDay = api.get(
        "/restaurants/123/housekeeping",
        RequestOptions.builder().query("date", "2026-11-05").build(),
        HousekeepingDay::fromJson
    ); // 200
    // klient: viz /v2/docs/java
    // volání blokuje – na Androidu z pracovního vlákna (Dispatchers.IO)
    // token zaměstnance přidá knihovna sama (po přihlášení zaměstnance)
    val housekeepingDay = api.get(
        "/restaurants/123/housekeeping",
        RequestOptions.builder().query("date", "2026-11-05").build(),
        HousekeepingDay::fromJson,
    ) // 200
    // the client: see /v2/docs/java
    // the call blocks – on Android from a worker thread (Dispatchers.IO)
    // the library adds the employee's token itself (after the employee signs in)
    val housekeepingDay = api.get(
        "/restaurants/123/housekeeping",
        RequestOptions.builder().query("date", "2026-11-05").build(),
        HousekeepingDay::fromJson,
    ) // 200
    // klient: viz /v2/docs/csharp
    // token zaměstnance přidá knihovna sama (po přihlášení zaměstnance)
    var housekeepingDay = await api.GetAsync<HousekeepingDay>(
        "/restaurants/123/housekeeping",
        new RequestOptions { Query = new() { ["date"] = "2026-11-05" } }
    ); // 200
    // the client: see /v2/docs/csharp
    // the library adds the employee's token itself (after the employee signs in)
    var housekeepingDay = await api.GetAsync<HousekeepingDay>(
        "/restaurants/123/housekeeping",
        new RequestOptions { Query = new() { ["date"] = "2026-11-05" } }
    ); // 200
    # klient: viz /v2/docs/python
    # token zaměstnance přidá knihovna sama (po přihlášení zaměstnance)
    housekeeping_day = api.get('/restaurants/123/housekeeping', query={'date': '2026-11-05'})  # 200
    # the client: see /v2/docs/python
    # the library adds the employee's token itself (after the employee signs in)
    housekeeping_day = api.get('/restaurants/123/housekeeping', query={'date': '2026-11-05'})  # 200
    // klient: viz /v2/docs/swift
    // token zaměstnance přidá knihovna sama (po přihlášení zaměstnance)
    let housekeepingDay: HousekeepingDay = try await api.get("/restaurants/123/housekeeping", options: .init(query: ["date": "2026-11-05"])) // 200
    // the client: see /v2/docs/swift
    // the library adds the employee's token itself (after the employee signs in)
    let housekeepingDay: HousekeepingDay = try await api.get("/restaurants/123/housekeeping", options: .init(query: ["date": "2026-11-05"])) // 200
    // klient: viz /v2/docs/dart
    // token zaměstnance přidá knihovna sama (po přihlášení zaměstnance)
    final housekeepingDay = pr.HousekeepingDay.fromJson(await api.get('/restaurants/123/housekeeping', query: {'date': '2026-11-05'})); // 200
    // the client: see /v2/docs/dart
    // the library adds the employee's token itself (after the employee signs in)
    final housekeepingDay = pr.HousekeepingDay.fromJson(await api.get('/restaurants/123/housekeeping', query: {'date': '2026-11-05'})); // 200
    // klient: viz /v2/docs/go
    // token zaměstnance přidá knihovna sama (po přihlášení zaměstnance)
    res, err := api.Get(
    	ctx,
    	"/restaurants/123/housekeeping",
    	&profirest.RequestOptions{Query: map[string]any{"date": "2026-11-05"}},
    )
    var housekeepingDay model.HousekeepingDay // 200
    if err == nil {
    	err = res.Decode(&housekeepingDay)
    }
    // the client: see /v2/docs/go
    // the library adds the employee's token itself (after the employee signs in)
    res, err := api.Get(
    	ctx,
    	"/restaurants/123/housekeeping",
    	&profirest.RequestOptions{Query: map[string]any{"date": "2026-11-05"}},
    )
    var housekeepingDay model.HousekeepingDay // 200
    if err == nil {
    	err = res.Decode(&housekeepingDay)
    }
    Příklad odpovědi 200Example answer 200
    {
      "date": "2026-11-05",
      "inspection": false,
      "summary": {
        "tasks": 5,
        "done": 0,
        "rooms": 3,
        "arrivals": 1,
        "waiting": 1
      },
      "rooms": [
        {
          "id": "104",
          "name": "104",
          "floor": "1",
          "type": "Dvoulůžkový",
          "status": "dirty",
          "occupied": false,
          "arrival": {
            "persons": 3,
            "extra_beds": 1,
            "from": "14:00",
            "checked_in": false
          },
          "departure": {
            "left": true
          },
          "tasks": [
            {
              "key": "checkout",
              "name": "Úklid po odjezdu",
              "done": false,
              "done_at": null,
              "done_by_employee_id": null,
              "waiting": false,
              "note": null,
              "manual": false
            },
            {
              "key": "extra_bed",
              "name": "Připravit přistýlku",
              "done": false,
              "done_at": null,
              "done_by_employee_id": null,
              "waiting": false,
              "note": null,
              "manual": false
            }
          ],
          "assigned_employee_id": "102",
          "issues": []
        },
        {
          "id": "201",
          "name": "201",
          "floor": "2",
          "type": "Jednolůžkový",
          "status": "clean",
          "occupied": true,
          "arrival": null,
          "departure": {
            "left": false
          },
          "tasks": [
            {
              "key": "checkout",
              "name": "Úklid po odjezdu",
              "done": false,
              "done_at": null,
              "done_by_employee_id": null,
              "waiting": true,
              "note": "Host ještě neodjel (odjezd do 10:00)",
              "manual": false
            }
          ],
          "assigned_employee_id": "101",
          "issues": []
        },
        {
          "id": "102",
          "name": "102",
          "floor": "1",
          "type": "Dvoulůžkový",
          "status": "clean",
          "occupied": true,
          "arrival": null,
          "departure": null,
          "tasks": [
            {
              "key": "stay",
              "name": "Úklid obsazeného pokoje",
              "done": false,
              "done_at": null,
              "done_by_employee_id": null,
              "waiting": false,
              "note": null,
              "manual": false
            },
            {
              "key": "rule:3",
              "name": "Výměna ručníků",
              "done": false,
              "done_at": null,
              "done_by_employee_id": null,
              "waiting": false,
              "note": null,
              "manual": false
            }
          ],
          "assigned_employee_id": "102",
          "issues": [
            {
              "id": "57",
              "room_id": "102",
              "room": "102",
              "text": "Kape kohoutek v koupelně",
              "blocks_room": false,
              "status": "open",
              "created_at": "2026-11-05T09:12:40+01:00",
              "created_by_employee_id": "102",
              "fixed_at": null,
              "fix_note": null
            }
          ]
        }
      ]
    }
  2. Odškrtnutí

    Ticking off

    POST /restaurants/{restaurant_id}/housekeeping/rooms/{room_id}/done · completeHousekeepingTask

    Úkol s waiting ještě nejde (host neodjel) – vrátí 409 lodging_state_conflict. Se staff tokenem se zapíše, která pokojská úkol udělala.

    A task with waiting cannot be done yet (the guest has not left) – it answers 409 lodging_state_conflict. With a staff token the housekeeper who did it is recorded.

    curl "https://api.mujprofirest.cz/v2/restaurants/123/housekeeping/rooms/104/done" \
      -H "Authorization: Bearer $ACCESS_TOKEN" \
      -H "Profirest-Staff-Token: $STAFF_TOKEN" \
      -H "Idempotency-Key: 01a318f0-a0c0-7b36-947a-2c030af53645" \
      -H "Content-Type: application/json" \
      -d '{"task": "checkout", "date": "2026-11-05"}'
    curl "https://api.mujprofirest.cz/v2/restaurants/123/housekeeping/rooms/104/done" \
      -H "Authorization: Bearer $ACCESS_TOKEN" \
      -H "Profirest-Staff-Token: $STAFF_TOKEN" \
      -H "Idempotency-Key: 01a318f0-a0c0-7b36-947a-2c030af53645" \
      -H "Content-Type: application/json" \
      -d '{"task": "checkout", "date": "2026-11-05"}'
    // klient: viz /v2/docs/js
    // token zaměstnance přidá knihovna sama (po přihlášení zaměstnance)
    const housekeepingTask = await api.post('/restaurants/123/housekeeping/rooms/104/done', { task: 'checkout', date: '2026-11-05' }); // 200
    // the client: see /v2/docs/js
    // the library adds the employee's token itself (after the employee signs in)
    const housekeepingTask = await api.post('/restaurants/123/housekeeping/rooms/104/done', { task: 'checkout', date: '2026-11-05' }); // 200
    // klient: viz /v2/docs/typescript
    // token zaměstnance přidá knihovna sama (po přihlášení zaměstnance)
    const housekeepingTask = await api.post('/restaurants/123/housekeeping/rooms/104/done', { task: 'checkout', date: '2026-11-05' }); // 200 HousekeepingRoom
    // the client: see /v2/docs/typescript
    // the library adds the employee's token itself (after the employee signs in)
    const housekeepingTask = await api.post('/restaurants/123/housekeeping/rooms/104/done', { task: 'checkout', date: '2026-11-05' }); // 200 HousekeepingRoom
    // klient: viz /v2/docs/php
    // token zaměstnance přidá knihovna sama (po přihlášení zaměstnance)
    $housekeepingTask = $api->post(
        '/restaurants/123/housekeeping/rooms/104/done',
        ['task' => 'checkout', 'date' => '2026-11-05'],
    ); // 200
    // the client: see /v2/docs/php
    // the library adds the employee's token itself (after the employee signs in)
    $housekeepingTask = $api->post(
        '/restaurants/123/housekeeping/rooms/104/done',
        ['task' => 'checkout', 'date' => '2026-11-05'],
    ); // 200
    // klient: viz /v2/docs/java
    // volání blokuje – na Androidu z pracovního vlákna (Dispatchers.IO)
    // token zaměstnance přidá knihovna sama (po přihlášení zaměstnance)
    HousekeepingRoom housekeepingTask = api.post("/restaurants/123/housekeeping/rooms/104/done", Json.parse("""
        {"task": "checkout", "date": "2026-11-05"}
        """), HousekeepingRoom::fromJson); // 200
    // the client: see /v2/docs/java
    // the call blocks – on Android from a worker thread (Dispatchers.IO)
    // the library adds the employee's token itself (after the employee signs in)
    HousekeepingRoom housekeepingTask = api.post("/restaurants/123/housekeeping/rooms/104/done", Json.parse("""
        {"task": "checkout", "date": "2026-11-05"}
        """), HousekeepingRoom::fromJson); // 200
    // klient: viz /v2/docs/java
    // volání blokuje – na Androidu z pracovního vlákna (Dispatchers.IO)
    // token zaměstnance přidá knihovna sama (po přihlášení zaměstnance)
    val housekeepingTask = api.post(
        "/restaurants/123/housekeeping/rooms/104/done",
        mapOf("task" to "checkout", "date" to "2026-11-05"),
        HousekeepingRoom::fromJson,
    ) // 200
    // the client: see /v2/docs/java
    // the call blocks – on Android from a worker thread (Dispatchers.IO)
    // the library adds the employee's token itself (after the employee signs in)
    val housekeepingTask = api.post(
        "/restaurants/123/housekeeping/rooms/104/done",
        mapOf("task" to "checkout", "date" to "2026-11-05"),
        HousekeepingRoom::fromJson,
    ) // 200
    // klient: viz /v2/docs/csharp
    // token zaměstnance přidá knihovna sama (po přihlášení zaměstnance)
    var housekeepingTask = await api.PostAsync<HousekeepingRoom>(
        "/restaurants/123/housekeeping/rooms/104/done",
        new { task = "checkout", date = "2026-11-05" }
    ); // 200
    // the client: see /v2/docs/csharp
    // the library adds the employee's token itself (after the employee signs in)
    var housekeepingTask = await api.PostAsync<HousekeepingRoom>(
        "/restaurants/123/housekeeping/rooms/104/done",
        new { task = "checkout", date = "2026-11-05" }
    ); // 200
    # klient: viz /v2/docs/python
    # token zaměstnance přidá knihovna sama (po přihlášení zaměstnance)
    housekeeping_task = api.post('/restaurants/123/housekeeping/rooms/104/done', {'task': 'checkout', 'date': '2026-11-05'})  # 200
    # the client: see /v2/docs/python
    # the library adds the employee's token itself (after the employee signs in)
    housekeeping_task = api.post('/restaurants/123/housekeeping/rooms/104/done', {'task': 'checkout', 'date': '2026-11-05'})  # 200
    // klient: viz /v2/docs/swift
    // token zaměstnance přidá knihovna sama (po přihlášení zaměstnance)
    let housekeepingTask: HousekeepingRoom = try await api.post(
        "/restaurants/123/housekeeping/rooms/104/done",
        body: ["task": "checkout", "date": "2026-11-05"]
    ) // 200
    // the client: see /v2/docs/swift
    // the library adds the employee's token itself (after the employee signs in)
    let housekeepingTask: HousekeepingRoom = try await api.post(
        "/restaurants/123/housekeeping/rooms/104/done",
        body: ["task": "checkout", "date": "2026-11-05"]
    ) // 200
    // klient: viz /v2/docs/dart
    // token zaměstnance přidá knihovna sama (po přihlášení zaměstnance)
    final housekeepingTask = pr.HousekeepingRoom.fromJson(await api.post('/restaurants/123/housekeeping/rooms/104/done', {'task': 'checkout', 'date': '2026-11-05'})); // 200
    // the client: see /v2/docs/dart
    // the library adds the employee's token itself (after the employee signs in)
    final housekeepingTask = pr.HousekeepingRoom.fromJson(await api.post('/restaurants/123/housekeeping/rooms/104/done', {'task': 'checkout', 'date': '2026-11-05'})); // 200
    // klient: viz /v2/docs/go
    // token zaměstnance přidá knihovna sama (po přihlášení zaměstnance)
    res, err := api.Post(
    	ctx,
    	"/restaurants/123/housekeeping/rooms/104/done",
    	map[string]any{"task": "checkout", "date": "2026-11-05"},
    	nil,
    )
    var housekeepingTask model.HousekeepingRoom // 200
    if err == nil {
    	err = res.Decode(&housekeepingTask)
    }
    // the client: see /v2/docs/go
    // the library adds the employee's token itself (after the employee signs in)
    res, err := api.Post(
    	ctx,
    	"/restaurants/123/housekeeping/rooms/104/done",
    	map[string]any{"task": "checkout", "date": "2026-11-05"},
    	nil,
    )
    var housekeepingTask model.HousekeepingRoom // 200
    if err == nil {
    	err = res.Decode(&housekeepingTask)
    }
    Příklad odpovědi 200Example answer 200
    {
      "id": "104",
      "name": "104",
      "floor": "1",
      "type": "Dvoulůžkový",
      "status": "clean",
      "occupied": false,
      "arrival": {
        "persons": 3,
        "extra_beds": 1,
        "from": "14:00",
        "checked_in": false
      },
      "departure": {
        "left": true
      },
      "tasks": [
        {
          "key": "checkout",
          "name": "Úklid po odjezdu",
          "done": true,
          "done_at": "2026-11-05T10:15:02+01:00",
          "done_by_employee_id": "102",
          "waiting": false,
          "note": null,
          "manual": false
        },
        {
          "key": "extra_bed",
          "name": "Připravit přistýlku",
          "done": false,
          "done_at": null,
          "done_by_employee_id": null,
          "waiting": false,
          "note": null,
          "manual": false
        }
      ],
      "assigned_employee_id": "102",
      "issues": []
    }
  3. Závada

    A fault

    POST /restaurants/{restaurant_id}/room-issues · reportRoomIssue

    S blocks_room pokoj nejde prodat, dokud ho údržba neoznačí přes fixRoomIssue; warning řekne, že má pokoj pobyty, které recepce musí přesunout.

    With blocks_room the room cannot be sold until the maintenance marks it with fixRoomIssue; warning says the room has stays the reception must move.

    curl "https://api.mujprofirest.cz/v2/restaurants/123/room-issues" \
      -H "Authorization: Bearer $ACCESS_TOKEN" \
      -H "Profirest-Staff-Token: $STAFF_TOKEN" \
      -H "Idempotency-Key: 01a318f0-a0c0-741b-b510-e49d71d4ae33" \
      -H "Content-Type: application/json" \
      -d '{"room_id": "102", "text": "Kape kohoutek v koupelně", "blocks_room": false}'
    curl "https://api.mujprofirest.cz/v2/restaurants/123/room-issues" \
      -H "Authorization: Bearer $ACCESS_TOKEN" \
      -H "Profirest-Staff-Token: $STAFF_TOKEN" \
      -H "Idempotency-Key: 01a318f0-a0c0-741b-b510-e49d71d4ae33" \
      -H "Content-Type: application/json" \
      -d '{"room_id": "102", "text": "Kape kohoutek v koupelně", "blocks_room": false}'
    // klient: viz /v2/docs/js
    // token zaměstnance přidá knihovna sama (po přihlášení zaměstnance)
    const roomIssue = await api.post(
      '/restaurants/123/room-issues',
      { room_id: '102', text: 'Kape kohoutek v koupelně', blocks_room: false },
    ); // 201
    // the client: see /v2/docs/js
    // the library adds the employee's token itself (after the employee signs in)
    const roomIssue = await api.post(
      '/restaurants/123/room-issues',
      { room_id: '102', text: 'Kape kohoutek v koupelně', blocks_room: false },
    ); // 201
    // klient: viz /v2/docs/typescript
    // token zaměstnance přidá knihovna sama (po přihlášení zaměstnance)
    const roomIssue = await api.post(
      '/restaurants/123/room-issues',
      { room_id: '102', text: 'Kape kohoutek v koupelně', blocks_room: false },
    ); // 201 RoomIssueReported
    // the client: see /v2/docs/typescript
    // the library adds the employee's token itself (after the employee signs in)
    const roomIssue = await api.post(
      '/restaurants/123/room-issues',
      { room_id: '102', text: 'Kape kohoutek v koupelně', blocks_room: false },
    ); // 201 RoomIssueReported
    // klient: viz /v2/docs/php
    // token zaměstnance přidá knihovna sama (po přihlášení zaměstnance)
    $roomIssue = $api->post(
        '/restaurants/123/room-issues',
        ['room_id' => '102', 'text' => 'Kape kohoutek v koupelně', 'blocks_room' => false],
    ); // 201
    // the client: see /v2/docs/php
    // the library adds the employee's token itself (after the employee signs in)
    $roomIssue = $api->post(
        '/restaurants/123/room-issues',
        ['room_id' => '102', 'text' => 'Kape kohoutek v koupelně', 'blocks_room' => false],
    ); // 201
    // klient: viz /v2/docs/java
    // volání blokuje – na Androidu z pracovního vlákna (Dispatchers.IO)
    // token zaměstnance přidá knihovna sama (po přihlášení zaměstnance)
    RoomIssueReported roomIssue = api.post("/restaurants/123/room-issues", Json.parse("""
        {"room_id": "102", "text": "Kape kohoutek v koupelně", "blocks_room": false}
        """), RoomIssueReported::fromJson); // 201
    // the client: see /v2/docs/java
    // the call blocks – on Android from a worker thread (Dispatchers.IO)
    // the library adds the employee's token itself (after the employee signs in)
    RoomIssueReported roomIssue = api.post("/restaurants/123/room-issues", Json.parse("""
        {"room_id": "102", "text": "Kape kohoutek v koupelně", "blocks_room": false}
        """), RoomIssueReported::fromJson); // 201
    // klient: viz /v2/docs/java
    // volání blokuje – na Androidu z pracovního vlákna (Dispatchers.IO)
    // token zaměstnance přidá knihovna sama (po přihlášení zaměstnance)
    val roomIssue = api.post(
        "/restaurants/123/room-issues",
        mapOf("room_id" to "102", "text" to "Kape kohoutek v koupelně", "blocks_room" to false),
        RoomIssueReported::fromJson,
    ) // 201
    // the client: see /v2/docs/java
    // the call blocks – on Android from a worker thread (Dispatchers.IO)
    // the library adds the employee's token itself (after the employee signs in)
    val roomIssue = api.post(
        "/restaurants/123/room-issues",
        mapOf("room_id" to "102", "text" to "Kape kohoutek v koupelně", "blocks_room" to false),
        RoomIssueReported::fromJson,
    ) // 201
    // klient: viz /v2/docs/csharp
    // token zaměstnance přidá knihovna sama (po přihlášení zaměstnance)
    var roomIssue = await api.PostAsync<RoomIssueReported>(
        "/restaurants/123/room-issues",
        new { room_id = "102", text = "Kape kohoutek v koupelně", blocks_room = false }
    ); // 201
    // the client: see /v2/docs/csharp
    // the library adds the employee's token itself (after the employee signs in)
    var roomIssue = await api.PostAsync<RoomIssueReported>(
        "/restaurants/123/room-issues",
        new { room_id = "102", text = "Kape kohoutek v koupelně", blocks_room = false }
    ); // 201
    # klient: viz /v2/docs/python
    # token zaměstnance přidá knihovna sama (po přihlášení zaměstnance)
    room_issue = api.post(
        '/restaurants/123/room-issues',
        {'room_id': '102', 'text': 'Kape kohoutek v koupelně', 'blocks_room': False},
    )  # 201
    # the client: see /v2/docs/python
    # the library adds the employee's token itself (after the employee signs in)
    room_issue = api.post(
        '/restaurants/123/room-issues',
        {'room_id': '102', 'text': 'Kape kohoutek v koupelně', 'blocks_room': False},
    )  # 201
    // klient: viz /v2/docs/swift
    // token zaměstnance přidá knihovna sama (po přihlášení zaměstnance)
    let roomIssue: RoomIssueReported = try await api.post(
        "/restaurants/123/room-issues",
        body: ["room_id": "102", "text": "Kape kohoutek v koupelně", "blocks_room": false]
    ) // 201
    // the client: see /v2/docs/swift
    // the library adds the employee's token itself (after the employee signs in)
    let roomIssue: RoomIssueReported = try await api.post(
        "/restaurants/123/room-issues",
        body: ["room_id": "102", "text": "Kape kohoutek v koupelně", "blocks_room": false]
    ) // 201
    // klient: viz /v2/docs/dart
    // token zaměstnance přidá knihovna sama (po přihlášení zaměstnance)
    final roomIssue = pr.RoomIssueReported.fromJson(await api.post(
      '/restaurants/123/room-issues',
      {'room_id': '102', 'text': 'Kape kohoutek v koupelně', 'blocks_room': false},
    )); // 201
    // the client: see /v2/docs/dart
    // the library adds the employee's token itself (after the employee signs in)
    final roomIssue = pr.RoomIssueReported.fromJson(await api.post(
      '/restaurants/123/room-issues',
      {'room_id': '102', 'text': 'Kape kohoutek v koupelně', 'blocks_room': false},
    )); // 201
    // klient: viz /v2/docs/go
    // token zaměstnance přidá knihovna sama (po přihlášení zaměstnance)
    res, err := api.Post(ctx, "/restaurants/123/room-issues", map[string]any{
    	"room_id": "102",
    	"text": "Kape kohoutek v koupelně",
    	"blocks_room": false,
    }, nil)
    var roomIssue model.RoomIssueReported // 201
    if err == nil {
    	err = res.Decode(&roomIssue)
    }
    // the client: see /v2/docs/go
    // the library adds the employee's token itself (after the employee signs in)
    res, err := api.Post(ctx, "/restaurants/123/room-issues", map[string]any{
    	"room_id": "102",
    	"text": "Kape kohoutek v koupelně",
    	"blocks_room": false,
    }, nil)
    var roomIssue model.RoomIssueReported // 201
    if err == nil {
    	err = res.Decode(&roomIssue)
    }
    Příklad odpovědi 201Example answer 201
    {
      "issue": {
        "id": "57",
        "room_id": "102",
        "room": "102",
        "text": "Kape kohoutek v koupelně",
        "blocks_room": false,
        "status": "open",
        "created_at": "2026-11-05T09:12:40+01:00",
        "created_by_employee_id": "102",
        "fixed_at": null,
        "fix_note": null
      },
      "warning": null
    }

Scénář

Scenario

Účetnictví a přehledy

Accounting and reports

Partner s oprávněním reports:readA partner with reports:read

Účetní nebo BI systém stahuje uzávěrky a doklady ze všech pokladen, webu i kuchyně, bere si přehledy jako Statistiky administrace a nové doklady mu chodí jako události. Částky a DPH sedí s kopií účtenky.

A bookkeeping or BI system downloads shift closes and sales documents from all registers, the web and the kitchen, takes the reports the Statistics of the administration show, and new documents come to it as events. Amounts and VAT match the receipt copy.

  1. Uzávěrky

    Shift closes

    GET /restaurants/{restaurant_id}/shift-closes · listShiftCloses

    Od nejnovější, se součty jako detail uzávěrky v administraci: tržba po platbách, storna, dýška, slevy a tržba evidovaná v EET.

    Newest first, with the totals of the close detail in the administration: takings by payment, cancellations, tips, discounts and the takings recorded in EET.

    curl "https://api.mujprofirest.cz/v2/restaurants/123/shift-closes?date_from=2027-01-01&date_to=2027-01-15" \
      -H "Authorization: Bearer $ACCESS_TOKEN"
    curl "https://api.mujprofirest.cz/v2/restaurants/123/shift-closes?date_from=2027-01-01&date_to=2027-01-15" \
      -H "Authorization: Bearer $ACCESS_TOKEN"
    // klient: viz /v2/docs/js
    const { data, next_cursor } = await api.get(
      '/restaurants/123/shift-closes',
      { query: { date_from: '2027-01-01', date_to: '2027-01-15' } },
    ); // 200
    // the client: see /v2/docs/js
    const { data, next_cursor } = await api.get(
      '/restaurants/123/shift-closes',
      { query: { date_from: '2027-01-01', date_to: '2027-01-15' } },
    ); // 200
    // klient: viz /v2/docs/typescript
    const { data, next_cursor } = await api.get(
      '/restaurants/123/shift-closes',
      { query: { date_from: '2027-01-01', date_to: '2027-01-15' } },
    ); // 200 ShiftClosePage
    // the client: see /v2/docs/typescript
    const { data, next_cursor } = await api.get(
      '/restaurants/123/shift-closes',
      { query: { date_from: '2027-01-01', date_to: '2027-01-15' } },
    ); // 200 ShiftClosePage
    // klient: viz /v2/docs/php
    $page = $api->get(
        '/restaurants/123/shift-closes',
        ['query' => ['date_from' => '2027-01-01', 'date_to' => '2027-01-15']],
    ); // $page['data'], $page['next_cursor']
    // the client: see /v2/docs/php
    $page = $api->get(
        '/restaurants/123/shift-closes',
        ['query' => ['date_from' => '2027-01-01', 'date_to' => '2027-01-15']],
    ); // $page['data'], $page['next_cursor']
    // klient: viz /v2/docs/java
    // volání blokuje – na Androidu z pracovního vlákna (Dispatchers.IO)
    ShiftClosePage listShiftCloses = api.get(
        "/restaurants/123/shift-closes",
        RequestOptions.builder().query("date_from", "2027-01-01").query("date_to", "2027-01-15").build(),
        ShiftClosePage::fromJson
    ); // 200
    // the client: see /v2/docs/java
    // the call blocks – on Android from a worker thread (Dispatchers.IO)
    ShiftClosePage listShiftCloses = api.get(
        "/restaurants/123/shift-closes",
        RequestOptions.builder().query("date_from", "2027-01-01").query("date_to", "2027-01-15").build(),
        ShiftClosePage::fromJson
    ); // 200
    // klient: viz /v2/docs/java
    // volání blokuje – na Androidu z pracovního vlákna (Dispatchers.IO)
    val listShiftCloses = api.get(
        "/restaurants/123/shift-closes",
        RequestOptions.builder().query("date_from", "2027-01-01").query("date_to", "2027-01-15").build(),
        ShiftClosePage::fromJson,
    ) // 200
    // the client: see /v2/docs/java
    // the call blocks – on Android from a worker thread (Dispatchers.IO)
    val listShiftCloses = api.get(
        "/restaurants/123/shift-closes",
        RequestOptions.builder().query("date_from", "2027-01-01").query("date_to", "2027-01-15").build(),
        ShiftClosePage::fromJson,
    ) // 200
    // klient: viz /v2/docs/csharp
    var listShiftCloses = await api.GetAsync<ShiftClosePage>(
        "/restaurants/123/shift-closes",
        new RequestOptions { Query = new() { ["date_from"] = "2027-01-01", ["date_to"] = "2027-01-15" } }
    ); // 200
    // the client: see /v2/docs/csharp
    var listShiftCloses = await api.GetAsync<ShiftClosePage>(
        "/restaurants/123/shift-closes",
        new RequestOptions { Query = new() { ["date_from"] = "2027-01-01", ["date_to"] = "2027-01-15" } }
    ); // 200
    # klient: viz /v2/docs/python
    page = api.get('/restaurants/123/shift-closes', query={'date_from': '2027-01-01', 'date_to': '2027-01-15'})  # page['data'], page['next_cursor']
    # the client: see /v2/docs/python
    page = api.get('/restaurants/123/shift-closes', query={'date_from': '2027-01-01', 'date_to': '2027-01-15'})  # page['data'], page['next_cursor']
    // klient: viz /v2/docs/swift
    let listShiftCloses: ShiftClosePage = try await api.get(
        "/restaurants/123/shift-closes",
        options: .init(query: ["date_from": "2027-01-01", "date_to": "2027-01-15"])
    ) // 200
    // the client: see /v2/docs/swift
    let listShiftCloses: ShiftClosePage = try await api.get(
        "/restaurants/123/shift-closes",
        options: .init(query: ["date_from": "2027-01-01", "date_to": "2027-01-15"])
    ) // 200
    // klient: viz /v2/docs/dart
    final listShiftCloses = pr.ShiftClosePage.fromJson(await api.get(
      '/restaurants/123/shift-closes',
      query: {'date_from': '2027-01-01', 'date_to': '2027-01-15'},
    )); // 200
    // the client: see /v2/docs/dart
    final listShiftCloses = pr.ShiftClosePage.fromJson(await api.get(
      '/restaurants/123/shift-closes',
      query: {'date_from': '2027-01-01', 'date_to': '2027-01-15'},
    )); // 200
    // klient: viz /v2/docs/go
    res, err := api.Get(
    	ctx,
    	"/restaurants/123/shift-closes",
    	&profirest.RequestOptions{Query: map[string]any{"date_from": "2027-01-01", "date_to": "2027-01-15"}},
    )
    var listShiftCloses model.ShiftClosePage // 200
    if err == nil {
    	err = res.Decode(&listShiftCloses)
    }
    // the client: see /v2/docs/go
    res, err := api.Get(
    	ctx,
    	"/restaurants/123/shift-closes",
    	&profirest.RequestOptions{Query: map[string]any{"date_from": "2027-01-01", "date_to": "2027-01-15"}},
    )
    var listShiftCloses model.ShiftClosePage // 200
    if err == nil {
    	err = res.Decode(&listShiftCloses)
    }
    Příklad odpovědi 200Example answer 200
    {
      "data": [
        {
          "id": "5512",
          "restaurant_id": "123",
          "closed_at": "2027-01-15T23:05:12+01:00",
          "closed_by": {
            "id": "102",
            "name": "Jana Nováková"
          },
          "source": "mixed",
          "device_id": null,
          "orders": 87,
          "totals": {
            "completed": {
              "amount": 4573000,
              "currency": "CZK"
            },
            "by_payment": {
              "cash": {
                "amount": 1912000,
                "currency": "CZK"
              },
              "card": {
                "amount": 2511000,
                "currency": "CZK"
              },
              "meal_voucher": {
                "amount": 150000,
                "currency": "CZK"
              },
              "company_account": {
                "amount": 0,
                "currency": "CZK"
              },
              "invoice": {
                "amount": 0,
                "currency": "CZK"
              }
            },
            "not_completed": {
              "amount": 0,
              "currency": "CZK"
            },
            "cancelled_orders": {
              "amount": 39800,
              "currency": "CZK"
            },
            "cancelled_items": {
              "amount": 13800,
              "currency": "CZK"
            },
            "tips": {
              "total": {
                "amount": 52000,
                "currency": "CZK"
              },
              "cash": {
                "amount": 18000,
                "currency": "CZK"
              },
              "card": {
                "amount": 34000,
                "currency": "CZK"
              }
            },
            "discounts": {
              "order": {
                "amount": 12000,
                "currency": "CZK"
              },
              "items": {
                "amount": 4500,
                "currency": "CZK"
              }
            },
            "eet_registered": {
              "amount": 4573000,
              "currency": "CZK"
            },
            "by_ticket": {
              "kitchen": {
                "amount": 3120000,
                "currency": "CZK"
              },
              "bar": {
                "amount": 1453000,
                "currency": "CZK"
              }
            }
          }
        }
      ],
      "next_cursor": null
    }
  2. Doklady den po dni

    Documents day by day

    GET /restaurants/{restaurant_id}/sales · listSales

    Od nejstaršího podle uzavření, stránkovaně – položky, slevy, doprava, rozpis DPH, platby, EET a uzávěrka. Storno je samostatný doklad se zápornými částkami.

    Oldest first by the time they were closed, paged – lines, discounts, delivery, the VAT breakdown, payments, EET and the shift. A cancellation is its own document with negative amounts.

    curl "https://api.mujprofirest.cz/v2/restaurants/123/sales?date_from=2027-01-15&date_to=2027-01-15" \
      -H "Authorization: Bearer $ACCESS_TOKEN"
    curl "https://api.mujprofirest.cz/v2/restaurants/123/sales?date_from=2027-01-15&date_to=2027-01-15" \
      -H "Authorization: Bearer $ACCESS_TOKEN"
    // klient: viz /v2/docs/js
    const { data, next_cursor } = await api.get('/restaurants/123/sales', { query: { date_from: '2027-01-15', date_to: '2027-01-15' } }); // 200
    // the client: see /v2/docs/js
    const { data, next_cursor } = await api.get('/restaurants/123/sales', { query: { date_from: '2027-01-15', date_to: '2027-01-15' } }); // 200
    // klient: viz /v2/docs/typescript
    const { data, next_cursor } = await api.get('/restaurants/123/sales', { query: { date_from: '2027-01-15', date_to: '2027-01-15' } }); // 200 SalePage
    // the client: see /v2/docs/typescript
    const { data, next_cursor } = await api.get('/restaurants/123/sales', { query: { date_from: '2027-01-15', date_to: '2027-01-15' } }); // 200 SalePage
    // klient: viz /v2/docs/php
    $page = $api->get(
        '/restaurants/123/sales',
        ['query' => ['date_from' => '2027-01-15', 'date_to' => '2027-01-15']],
    ); // $page['data'], $page['next_cursor']
    // the client: see /v2/docs/php
    $page = $api->get(
        '/restaurants/123/sales',
        ['query' => ['date_from' => '2027-01-15', 'date_to' => '2027-01-15']],
    ); // $page['data'], $page['next_cursor']
    // klient: viz /v2/docs/java
    // volání blokuje – na Androidu z pracovního vlákna (Dispatchers.IO)
    SalePage listSales = api.get(
        "/restaurants/123/sales",
        RequestOptions.builder().query("date_from", "2027-01-15").query("date_to", "2027-01-15").build(),
        SalePage::fromJson
    ); // 200
    // the client: see /v2/docs/java
    // the call blocks – on Android from a worker thread (Dispatchers.IO)
    SalePage listSales = api.get(
        "/restaurants/123/sales",
        RequestOptions.builder().query("date_from", "2027-01-15").query("date_to", "2027-01-15").build(),
        SalePage::fromJson
    ); // 200
    // klient: viz /v2/docs/java
    // volání blokuje – na Androidu z pracovního vlákna (Dispatchers.IO)
    val listSales = api.get(
        "/restaurants/123/sales",
        RequestOptions.builder().query("date_from", "2027-01-15").query("date_to", "2027-01-15").build(),
        SalePage::fromJson,
    ) // 200
    // the client: see /v2/docs/java
    // the call blocks – on Android from a worker thread (Dispatchers.IO)
    val listSales = api.get(
        "/restaurants/123/sales",
        RequestOptions.builder().query("date_from", "2027-01-15").query("date_to", "2027-01-15").build(),
        SalePage::fromJson,
    ) // 200
    // klient: viz /v2/docs/csharp
    var listSales = await api.GetAsync<SalePage>(
        "/restaurants/123/sales",
        new RequestOptions { Query = new() { ["date_from"] = "2027-01-15", ["date_to"] = "2027-01-15" } }
    ); // 200
    // the client: see /v2/docs/csharp
    var listSales = await api.GetAsync<SalePage>(
        "/restaurants/123/sales",
        new RequestOptions { Query = new() { ["date_from"] = "2027-01-15", ["date_to"] = "2027-01-15" } }
    ); // 200
    # klient: viz /v2/docs/python
    page = api.get('/restaurants/123/sales', query={'date_from': '2027-01-15', 'date_to': '2027-01-15'})  # page['data'], page['next_cursor']
    # the client: see /v2/docs/python
    page = api.get('/restaurants/123/sales', query={'date_from': '2027-01-15', 'date_to': '2027-01-15'})  # page['data'], page['next_cursor']
    // klient: viz /v2/docs/swift
    let listSales: SalePage = try await api.get(
        "/restaurants/123/sales",
        options: .init(query: ["date_from": "2027-01-15", "date_to": "2027-01-15"])
    ) // 200
    // the client: see /v2/docs/swift
    let listSales: SalePage = try await api.get(
        "/restaurants/123/sales",
        options: .init(query: ["date_from": "2027-01-15", "date_to": "2027-01-15"])
    ) // 200
    // klient: viz /v2/docs/dart
    final listSales = pr.SalePage.fromJson(await api.get('/restaurants/123/sales', query: {'date_from': '2027-01-15', 'date_to': '2027-01-15'})); // 200
    // the client: see /v2/docs/dart
    final listSales = pr.SalePage.fromJson(await api.get('/restaurants/123/sales', query: {'date_from': '2027-01-15', 'date_to': '2027-01-15'})); // 200
    // klient: viz /v2/docs/go
    res, err := api.Get(
    	ctx,
    	"/restaurants/123/sales",
    	&profirest.RequestOptions{Query: map[string]any{"date_from": "2027-01-15", "date_to": "2027-01-15"}},
    )
    var listSales model.SalePage // 200
    if err == nil {
    	err = res.Decode(&listSales)
    }
    // the client: see /v2/docs/go
    res, err := api.Get(
    	ctx,
    	"/restaurants/123/sales",
    	&profirest.RequestOptions{Query: map[string]any{"date_from": "2027-01-15", "date_to": "2027-01-15"}},
    )
    var listSales model.SalePage // 200
    if err == nil {
    	err = res.Decode(&listSales)
    }
    Příklad odpovědi 200Example answer 200
    {
      "data": [
        {
          "id": "880417",
          "number": "1043",
          "kind": "sale",
          "source": "pos",
          "platform": null,
          "table_name": "Stůl 4",
          "created_at": "2027-01-15T11:48:02+01:00",
          "closed_at": "2027-01-15T12:31:40+01:00",
          "employee": {
            "id": "58",
            "name": "Jana Dvořáková"
          },
          "lines": [
            {
              "type": "product",
              "product_id": "4567",
              "name": "Svíčková na smetaně, houskový knedlík",
              "quantity": 1,
              "unit_price": {
                "amount": 19900,
                "currency": "CZK"
              },
              "packaging_unit_price": null,
              "discount_per_unit": {
                "amount": 0,
                "currency": "CZK"
              },
              "vat_rate": "12",
              "total": {
                "amount": 19900,
                "currency": "CZK"
              }
            },
            {
              "type": "product",
              "product_id": "4590",
              "name": "Pivo 12° 0,5 l",
              "quantity": 2,
              "unit_price": {
                "amount": 6900,
                "currency": "CZK"
              },
              "packaging_unit_price": null,
              "discount_per_unit": {
                "amount": 0,
                "currency": "CZK"
              },
              "vat_rate": "21",
              "total": {
                "amount": 13800,
                "currency": "CZK"
              }
            }
          ],
          "items_total": {
            "amount": 33700,
            "currency": "CZK"
          },
          "discounts": [],
          "delivery_fee": {
            "amount": 0,
            "currency": "CZK"
          },
          "price_adjustment": {
            "amount": 0,
            "currency": "CZK"
          },
          "rounding": {
            "amount": 0,
            "currency": "CZK"
          },
          "total": {
            "amount": 33700,
            "currency": "CZK"
          },
          "vat": [
            {
              "rate": "21",
              "base": {
                "amount": 11405,
                "currency": "CZK"
              },
              "vat": {
                "amount": 2395,
                "currency": "CZK"
              },
              "total": {
                "amount": 13800,
                "currency": "CZK"
              }
            },
            {
              "rate": "12",
              "base": {
                "amount": 17768,
                "currency": "CZK"
              },
              "vat": {
                "amount": 2132,
                "currency": "CZK"
              },
              "total": {
                "amount": 19900,
                "currency": "CZK"
              }
            }
          ],
          "voucher_payments": [],
          "amount_paid": {
            "amount": 33700,
            "currency": "CZK"
          },
          "payment_method": "card",
          "card_at_handover": false,
          "tip": {
            "amount": 3000,
            "currency": "CZK"
          },
          "eet": {
            "fik": null,
            "bkp": null,
            "status": "accepted",
            "pok": "ab12cd34-0000-4000-8000-000000000001-03"
          },
          "shift_id": "5512",
          "cancels": null,
          "cancelled_by": null
        }
      ],
      "next_cursor": null
    }
  3. Rozpis DPH

    VAT by rate

    GET /restaurants/{restaurant_id}/reports/vat · getVatReport

    DPH po sazbách za období, spočítané stejně jako kopie účtenky; prodané dárkové vouchery zvlášť.

    VAT by rate for a period, computed the same way as the receipt copy; sold gift vouchers separately.

    curl "https://api.mujprofirest.cz/v2/restaurants/123/reports/vat?date_from=2027-01-11&date_to=2027-01-15" \
      -H "Authorization: Bearer $ACCESS_TOKEN"
    curl "https://api.mujprofirest.cz/v2/restaurants/123/reports/vat?date_from=2027-01-11&date_to=2027-01-15" \
      -H "Authorization: Bearer $ACCESS_TOKEN"
    // klient: viz /v2/docs/js
    const vatReport = await api.get(
      '/restaurants/123/reports/vat',
      { query: { date_from: '2027-01-11', date_to: '2027-01-15' } },
    ); // 200
    // the client: see /v2/docs/js
    const vatReport = await api.get(
      '/restaurants/123/reports/vat',
      { query: { date_from: '2027-01-11', date_to: '2027-01-15' } },
    ); // 200
    // klient: viz /v2/docs/typescript
    const vatReport = await api.get(
      '/restaurants/123/reports/vat',
      { query: { date_from: '2027-01-11', date_to: '2027-01-15' } },
    ); // 200 VatReport
    // the client: see /v2/docs/typescript
    const vatReport = await api.get(
      '/restaurants/123/reports/vat',
      { query: { date_from: '2027-01-11', date_to: '2027-01-15' } },
    ); // 200 VatReport
    // klient: viz /v2/docs/php
    $vatReport = $api->get(
        '/restaurants/123/reports/vat',
        ['query' => ['date_from' => '2027-01-11', 'date_to' => '2027-01-15']],
    ); // 200
    // the client: see /v2/docs/php
    $vatReport = $api->get(
        '/restaurants/123/reports/vat',
        ['query' => ['date_from' => '2027-01-11', 'date_to' => '2027-01-15']],
    ); // 200
    // klient: viz /v2/docs/java
    // volání blokuje – na Androidu z pracovního vlákna (Dispatchers.IO)
    VatReport vatReport = api.get(
        "/restaurants/123/reports/vat",
        RequestOptions.builder().query("date_from", "2027-01-11").query("date_to", "2027-01-15").build(),
        VatReport::fromJson
    ); // 200
    // the client: see /v2/docs/java
    // the call blocks – on Android from a worker thread (Dispatchers.IO)
    VatReport vatReport = api.get(
        "/restaurants/123/reports/vat",
        RequestOptions.builder().query("date_from", "2027-01-11").query("date_to", "2027-01-15").build(),
        VatReport::fromJson
    ); // 200
    // klient: viz /v2/docs/java
    // volání blokuje – na Androidu z pracovního vlákna (Dispatchers.IO)
    val vatReport = api.get(
        "/restaurants/123/reports/vat",
        RequestOptions.builder().query("date_from", "2027-01-11").query("date_to", "2027-01-15").build(),
        VatReport::fromJson,
    ) // 200
    // the client: see /v2/docs/java
    // the call blocks – on Android from a worker thread (Dispatchers.IO)
    val vatReport = api.get(
        "/restaurants/123/reports/vat",
        RequestOptions.builder().query("date_from", "2027-01-11").query("date_to", "2027-01-15").build(),
        VatReport::fromJson,
    ) // 200
    // klient: viz /v2/docs/csharp
    var vatReport = await api.GetAsync<VatReport>(
        "/restaurants/123/reports/vat",
        new RequestOptions { Query = new() { ["date_from"] = "2027-01-11", ["date_to"] = "2027-01-15" } }
    ); // 200
    // the client: see /v2/docs/csharp
    var vatReport = await api.GetAsync<VatReport>(
        "/restaurants/123/reports/vat",
        new RequestOptions { Query = new() { ["date_from"] = "2027-01-11", ["date_to"] = "2027-01-15" } }
    ); // 200
    # klient: viz /v2/docs/python
    vat_report = api.get('/restaurants/123/reports/vat', query={'date_from': '2027-01-11', 'date_to': '2027-01-15'})  # 200
    # the client: see /v2/docs/python
    vat_report = api.get('/restaurants/123/reports/vat', query={'date_from': '2027-01-11', 'date_to': '2027-01-15'})  # 200
    // klient: viz /v2/docs/swift
    let vatReport: VatReport = try await api.get(
        "/restaurants/123/reports/vat",
        options: .init(query: ["date_from": "2027-01-11", "date_to": "2027-01-15"])
    ) // 200
    // the client: see /v2/docs/swift
    let vatReport: VatReport = try await api.get(
        "/restaurants/123/reports/vat",
        options: .init(query: ["date_from": "2027-01-11", "date_to": "2027-01-15"])
    ) // 200
    // klient: viz /v2/docs/dart
    final vatReport = pr.VatReport.fromJson(await api.get('/restaurants/123/reports/vat', query: {'date_from': '2027-01-11', 'date_to': '2027-01-15'})); // 200
    // the client: see /v2/docs/dart
    final vatReport = pr.VatReport.fromJson(await api.get('/restaurants/123/reports/vat', query: {'date_from': '2027-01-11', 'date_to': '2027-01-15'})); // 200
    // klient: viz /v2/docs/go
    res, err := api.Get(
    	ctx,
    	"/restaurants/123/reports/vat",
    	&profirest.RequestOptions{Query: map[string]any{"date_from": "2027-01-11", "date_to": "2027-01-15"}},
    )
    var vatReport model.VatReport // 200
    if err == nil {
    	err = res.Decode(&vatReport)
    }
    // the client: see /v2/docs/go
    res, err := api.Get(
    	ctx,
    	"/restaurants/123/reports/vat",
    	&profirest.RequestOptions{Query: map[string]any{"date_from": "2027-01-11", "date_to": "2027-01-15"}},
    )
    var vatReport model.VatReport // 200
    if err == nil {
    	err = res.Decode(&vatReport)
    }
    Příklad odpovědi 200Example answer 200
    {
      "date_from": "2027-01-11",
      "date_to": "2027-01-15",
      "rates": [
        {
          "rate": "21",
          "base": {
            "amount": 3962810,
            "currency": "CZK"
          },
          "vat": {
            "amount": 832190,
            "currency": "CZK"
          },
          "total": {
            "amount": 4795000,
            "currency": "CZK"
          }
        },
        {
          "rate": "12",
          "base": {
            "amount": 8263393,
            "currency": "CZK"
          },
          "vat": {
            "amount": 991607,
            "currency": "CZK"
          },
          "total": {
            "amount": 9255000,
            "currency": "CZK"
          }
        }
      ],
      "vouchers_sold": {
        "amount": 200000,
        "currency": "CZK"
      }
    }
  4. Přehled tržeb

    Revenue summary

    GET /restaurants/{restaurant_id}/reports/sales-summary · getSalesSummary

    Tržby po dnech, hodinách, platbách, zdrojích, obsluze nebo stolech – stejná čísla jako Statistiky v administraci. Prodej položek dává getProductSales, spropitné getTipsReport. Provozovna s ubytováním nebo vstupenkami: segment=food nechá jen gastro, group_by=segment rozdělí tržbu na gastro, ubytování a vstupenky.

    Revenue by day, hour, payment, source, staff or table – the same numbers as the Statistics in the administration. Product sales come from getProductSales, tips from getTipsReport. A restaurant with accommodation or tickets: segment=food keeps only food and drinks, group_by=segment splits the revenue into food, accommodation and tickets.

    curl "https://api.mujprofirest.cz/v2/restaurants/123/reports/sales-summary?date_from=2027-01-11&date_to=2027-01-15&group_by=payment" \
      -H "Authorization: Bearer $ACCESS_TOKEN"
    curl "https://api.mujprofirest.cz/v2/restaurants/123/reports/sales-summary?date_from=2027-01-11&date_to=2027-01-15&group_by=payment" \
      -H "Authorization: Bearer $ACCESS_TOKEN"
    // klient: viz /v2/docs/js
    const salesSummary = await api.get(
      '/restaurants/123/reports/sales-summary',
      { query: { date_from: '2027-01-11', date_to: '2027-01-15', group_by: 'payment' } },
    ); // 200
    // the client: see /v2/docs/js
    const salesSummary = await api.get(
      '/restaurants/123/reports/sales-summary',
      { query: { date_from: '2027-01-11', date_to: '2027-01-15', group_by: 'payment' } },
    ); // 200
    // klient: viz /v2/docs/typescript
    const salesSummary = await api.get(
      '/restaurants/123/reports/sales-summary',
      { query: { date_from: '2027-01-11', date_to: '2027-01-15', group_by: 'payment' } },
    ); // 200 SalesSummary
    // the client: see /v2/docs/typescript
    const salesSummary = await api.get(
      '/restaurants/123/reports/sales-summary',
      { query: { date_from: '2027-01-11', date_to: '2027-01-15', group_by: 'payment' } },
    ); // 200 SalesSummary
    // klient: viz /v2/docs/php
    $salesSummary = $api->get(
        '/restaurants/123/reports/sales-summary',
        ['query' => ['date_from' => '2027-01-11', 'date_to' => '2027-01-15', 'group_by' => 'payment']],
    ); // 200
    // the client: see /v2/docs/php
    $salesSummary = $api->get(
        '/restaurants/123/reports/sales-summary',
        ['query' => ['date_from' => '2027-01-11', 'date_to' => '2027-01-15', 'group_by' => 'payment']],
    ); // 200
    // klient: viz /v2/docs/java
    // volání blokuje – na Androidu z pracovního vlákna (Dispatchers.IO)
    SalesSummary salesSummary = api.get(
        "/restaurants/123/reports/sales-summary",
        RequestOptions.builder().query("date_from", "2027-01-11").query("date_to", "2027-01-15").query("group_by", "payment").build(),
        SalesSummary::fromJson
    ); // 200
    // the client: see /v2/docs/java
    // the call blocks – on Android from a worker thread (Dispatchers.IO)
    SalesSummary salesSummary = api.get(
        "/restaurants/123/reports/sales-summary",
        RequestOptions.builder().query("date_from", "2027-01-11").query("date_to", "2027-01-15").query("group_by", "payment").build(),
        SalesSummary::fromJson
    ); // 200
    // klient: viz /v2/docs/java
    // volání blokuje – na Androidu z pracovního vlákna (Dispatchers.IO)
    val salesSummary = api.get(
        "/restaurants/123/reports/sales-summary",
        RequestOptions.builder().query("date_from", "2027-01-11").query("date_to", "2027-01-15").query("group_by", "payment").build(),
        SalesSummary::fromJson,
    ) // 200
    // the client: see /v2/docs/java
    // the call blocks – on Android from a worker thread (Dispatchers.IO)
    val salesSummary = api.get(
        "/restaurants/123/reports/sales-summary",
        RequestOptions.builder().query("date_from", "2027-01-11").query("date_to", "2027-01-15").query("group_by", "payment").build(),
        SalesSummary::fromJson,
    ) // 200
    // klient: viz /v2/docs/csharp
    var salesSummary = await api.GetAsync<SalesSummary>(
        "/restaurants/123/reports/sales-summary",
        new RequestOptions { Query = new() { ["date_from"] = "2027-01-11", ["date_to"] = "2027-01-15", ["group_by"] = "payment" } }
    ); // 200
    // the client: see /v2/docs/csharp
    var salesSummary = await api.GetAsync<SalesSummary>(
        "/restaurants/123/reports/sales-summary",
        new RequestOptions { Query = new() { ["date_from"] = "2027-01-11", ["date_to"] = "2027-01-15", ["group_by"] = "payment" } }
    ); // 200
    # klient: viz /v2/docs/python
    sales_summary = api.get(
        '/restaurants/123/reports/sales-summary',
        query={'date_from': '2027-01-11', 'date_to': '2027-01-15', 'group_by': 'payment'},
    )  # 200
    # the client: see /v2/docs/python
    sales_summary = api.get(
        '/restaurants/123/reports/sales-summary',
        query={'date_from': '2027-01-11', 'date_to': '2027-01-15', 'group_by': 'payment'},
    )  # 200
    // klient: viz /v2/docs/swift
    let salesSummary: SalesSummary = try await api.get(
        "/restaurants/123/reports/sales-summary",
        options: .init(query: ["date_from": "2027-01-11", "date_to": "2027-01-15", "group_by": "payment"])
    ) // 200
    // the client: see /v2/docs/swift
    let salesSummary: SalesSummary = try await api.get(
        "/restaurants/123/reports/sales-summary",
        options: .init(query: ["date_from": "2027-01-11", "date_to": "2027-01-15", "group_by": "payment"])
    ) // 200
    // klient: viz /v2/docs/dart
    final salesSummary = pr.SalesSummary.fromJson(await api.get(
      '/restaurants/123/reports/sales-summary',
      query: {'date_from': '2027-01-11', 'date_to': '2027-01-15', 'group_by': 'payment'},
    )); // 200
    // the client: see /v2/docs/dart
    final salesSummary = pr.SalesSummary.fromJson(await api.get(
      '/restaurants/123/reports/sales-summary',
      query: {'date_from': '2027-01-11', 'date_to': '2027-01-15', 'group_by': 'payment'},
    )); // 200
    // klient: viz /v2/docs/go
    res, err := api.Get(
    	ctx,
    	"/restaurants/123/reports/sales-summary",
    	&profirest.RequestOptions{Query: map[string]any{"date_from": "2027-01-11", "date_to": "2027-01-15", "group_by": "payment"}},
    )
    var salesSummary model.SalesSummary // 200
    if err == nil {
    	err = res.Decode(&salesSummary)
    }
    // the client: see /v2/docs/go
    res, err := api.Get(
    	ctx,
    	"/restaurants/123/reports/sales-summary",
    	&profirest.RequestOptions{Query: map[string]any{"date_from": "2027-01-11", "date_to": "2027-01-15", "group_by": "payment"}},
    )
    var salesSummary model.SalesSummary // 200
    if err == nil {
    	err = res.Decode(&salesSummary)
    }
    Příklad odpovědi 200Example answer 200
    {
      "date_from": "2027-01-11",
      "date_to": "2027-01-15",
      "group_by": "payment",
      "segment": null,
      "totals": {
        "revenue": {
          "amount": 14250000,
          "currency": "CZK"
        },
        "orders": 512,
        "average_order": {
          "amount": 27832,
          "currency": "CZK"
        },
        "tips": {
          "amount": 318000,
          "currency": "CZK"
        }
      },
      "rows": [
        {
          "key": "card",
          "name": null,
          "revenue": {
            "amount": 8915000,
            "currency": "CZK"
          },
          "orders": 301
        },
        {
          "key": "cash",
          "name": null,
          "revenue": {
            "amount": 4830000,
            "currency": "CZK"
          },
          "orders": 196
        },
        {
          "key": "meal_voucher",
          "name": null,
          "revenue": {
            "amount": 505000,
            "currency": "CZK"
          },
          "orders": 15
        }
      ]
    }
  5. Export do účetnictví

    Export to accounting

    GET /restaurants/{restaurant_id}/accounting-export · getAccountingExport

    Soubor pro Pohodu nebo Money za období; potřebuje i oprávnění accounting:read.

    A file for Pohoda or Money for a period; it needs the accounting:read scope too.

    curl "https://api.mujprofirest.cz/v2/restaurants/123/accounting-export?format=pohoda&type=receipts&date_from=2027-01-01&date_to=2027-01-15" \
      -H "Authorization: Bearer $ACCESS_TOKEN" \
      -o zaloha.zip
    curl "https://api.mujprofirest.cz/v2/restaurants/123/accounting-export?format=pohoda&type=receipts&date_from=2027-01-01&date_to=2027-01-15" \
      -H "Authorization: Bearer $ACCESS_TOKEN" \
      -o zaloha.zip
    // klient: viz /v2/docs/js
    const zip = await api.get('/restaurants/123/accounting-export', { accept: 'application/xml' });
    // the client: see /v2/docs/js
    const zip = await api.get('/restaurants/123/accounting-export', { accept: 'application/xml' });
    // klient: viz /v2/docs/typescript
    const zip = await api.get('/restaurants/123/accounting-export', { accept: 'application/xml' });
    // the client: see /v2/docs/typescript
    const zip = await api.get('/restaurants/123/accounting-export', { accept: 'application/xml' });
    // klient: viz /v2/docs/php
    file_put_contents('zaloha.zip', $api->get('/restaurants/123/accounting-export', ['accept' => 'application/xml']));
    // the client: see /v2/docs/php
    file_put_contents('zaloha.zip', $api->get('/restaurants/123/accounting-export', ['accept' => 'application/xml']));
    // klient: viz /v2/docs/java
    // volání blokuje – na Androidu z pracovního vlákna (Dispatchers.IO)
    byte[] zip = (byte[]) api.get("/restaurants/123/accounting-export", RequestOptions.builder().accept("application/xml").build());
    Files.write(Path.of("zaloha.zip"), zip);
    // the client: see /v2/docs/java
    // the call blocks – on Android from a worker thread (Dispatchers.IO)
    byte[] zip = (byte[]) api.get("/restaurants/123/accounting-export", RequestOptions.builder().accept("application/xml").build());
    Files.write(Path.of("zaloha.zip"), zip);
    // klient: viz /v2/docs/java
    // volání blokuje – na Androidu z pracovního vlákna (Dispatchers.IO)
    val zip = api.get("/restaurants/123/accounting-export", RequestOptions.builder().accept("application/xml").build()) as ByteArray
    File("zaloha.zip").writeBytes(zip)
    // the client: see /v2/docs/java
    // the call blocks – on Android from a worker thread (Dispatchers.IO)
    val zip = api.get("/restaurants/123/accounting-export", RequestOptions.builder().accept("application/xml").build()) as ByteArray
    File("zaloha.zip").writeBytes(zip)
    // klient: viz /v2/docs/csharp
    byte[]? zip = await api.GetAsync<byte[]>("/restaurants/123/accounting-export", new RequestOptions { Accept = "application/xml" });
    await File.WriteAllBytesAsync("zaloha.zip", zip!);
    // the client: see /v2/docs/csharp
    byte[]? zip = await api.GetAsync<byte[]>("/restaurants/123/accounting-export", new RequestOptions { Accept = "application/xml" });
    await File.WriteAllBytesAsync("zaloha.zip", zip!);
    # klient: viz /v2/docs/python
    zip_bytes = api.get('/restaurants/123/accounting-export', accept='application/xml')
    with open('zaloha.zip', 'wb') as fh:
        fh.write(zip_bytes)
    # the client: see /v2/docs/python
    zip_bytes = api.get('/restaurants/123/accounting-export', accept='application/xml')
    with open('zaloha.zip', 'wb') as fh:
        fh.write(zip_bytes)
    // klient: viz /v2/docs/swift
    let zip: Data = try await api.get("/restaurants/123/accounting-export", options: .init(accept: "application/xml"))
    try zip.write(to: zipURL)
    // the client: see /v2/docs/swift
    let zip: Data = try await api.get("/restaurants/123/accounting-export", options: .init(accept: "application/xml"))
    try zip.write(to: zipURL)
    // klient: viz /v2/docs/dart
    final zip = await api.get('/restaurants/123/accounting-export', accept: 'application/xml') as List<int>;
    await File('zaloha.zip').writeAsBytes(zip);
    // the client: see /v2/docs/dart
    final zip = await api.get('/restaurants/123/accounting-export', accept: 'application/xml') as List<int>;
    await File('zaloha.zip').writeAsBytes(zip);
    // klient: viz /v2/docs/go
    res, err := api.Get(ctx, "/restaurants/123/accounting-export", &profirest.RequestOptions{Accept: "application/xml"})
    if err == nil {
    	err = os.WriteFile("zaloha.zip", res.Body, 0o600)
    }
    // the client: see /v2/docs/go
    res, err := api.Get(ctx, "/restaurants/123/accounting-export", &profirest.RequestOptions{Accept: "application/xml"})
    if err == nil {
    	err = os.WriteFile("zaloha.zip", res.Body, 0o600)
    }
  6. Nové doklady průběžně

    New documents as they come

    GET /events · listEvents

    Nový doklad přijde jako sale.created, stornovaný jako sale.cancelled a uzávěrka jako shift.closed – ze všech zdrojů do zhruba tří minut, v datech je celý doklad nebo uzávěrka. Seznamy pak stačí na dohnání po výpadku.

    A new document comes as sale.created, a cancelled one as sale.cancelled and a close as shift.closed – from all sources within about three minutes, the data is the whole document or close. The lists are then needed only to catch up after an outage.

    curl "https://api.mujprofirest.cz/v2/events?cursor=eyJzZXEiOjkxMDU1MH0&restaurant_id=123&limit=100" \
      -H "Authorization: Bearer $ACCESS_TOKEN"
    curl "https://api.mujprofirest.cz/v2/events?cursor=eyJzZXEiOjkxMDU1MH0&restaurant_id=123&limit=100" \
      -H "Authorization: Bearer $ACCESS_TOKEN"
    // klient: viz /v2/docs/js
    const feed = api.watchEvents({
      restaurantId: '123',
      onEvents: async (events) => {
        for (const event of events) handle(event); // kurzor se posune až potom
      },
      onReset: () => reloadEverything(), // 410 cursor_expired: načtěte stav znovu
    });
    // the client: see /v2/docs/js
    const feed = api.watchEvents({
      restaurantId: '123',
      onEvents: async (events) => {
        for (const event of events) handle(event); // the cursor moves only afterwards
      },
      onReset: () => reloadEverything(), // 410 cursor_expired: reload the state
    });
    // klient: viz /v2/docs/typescript
    const feed = api.watchEvents({
      restaurantId: '123',
      onEvents: async (events) => {
        for (const event of events) handle(event); // kurzor se posune až potom
      },
      onReset: () => reloadEverything(), // 410 cursor_expired: načtěte stav znovu
    });
    // the client: see /v2/docs/typescript
    const feed = api.watchEvents({
      restaurantId: '123',
      onEvents: async (events) => {
        for (const event of events) handle(event); // the cursor moves only afterwards
      },
      onReset: () => reloadEverything(), // 410 cursor_expired: reload the state
    });
    // klient: viz /v2/docs/php
    $api->watchEvents([
        'restaurantId' => '123',
        'onEvents' => function (array $events): void {
            foreach ($events as $event) { handle($event); } // kurzor se posune až potom
        },
        'onReset' => fn() => reloadEverything(), // 410 cursor_expired: načtěte stav znovu
    ])->run();
    // the client: see /v2/docs/php
    $api->watchEvents([
        'restaurantId' => '123',
        'onEvents' => function (array $events): void {
            foreach ($events as $event) { handle($event); } // the cursor moves only afterwards
        },
        'onReset' => fn() => reloadEverything(), // 410 cursor_expired: reload the state
    ])->run();
    // klient: viz /v2/docs/java
    // volání blokuje – na Androidu z pracovního vlákna (Dispatchers.IO)
    EventWatcher feed = api.watchEvents(WatchOptions.builder()
            .restaurantId("123")
            .onEvents(events -> events.forEach(this::handle)) // kurzor se posune až potom
            .onReset(error -> reloadEverything()) // 410 cursor_expired: načtěte stav znovu
            .build());
    feed.start();
    // the client: see /v2/docs/java
    // the call blocks – on Android from a worker thread (Dispatchers.IO)
    EventWatcher feed = api.watchEvents(WatchOptions.builder()
            .restaurantId("123")
            .onEvents(events -> events.forEach(this::handle)) // the cursor moves only afterwards
            .onReset(error -> reloadEverything()) // 410 cursor_expired: reload the state
            .build());
    feed.start();
    // klient: viz /v2/docs/java
    // volání blokuje – na Androidu z pracovního vlákna (Dispatchers.IO)
    val feed = api.watchEvents(WatchOptions.builder()
        .restaurantId("123")
        .onEvents { events -> events.forEach { handle(it) } } // kurzor se posune až potom
        .onReset { reloadEverything() } // 410 cursor_expired: načtěte stav znovu
        .build())
    feed.start()
    // the client: see /v2/docs/java
    // the call blocks – on Android from a worker thread (Dispatchers.IO)
    val feed = api.watchEvents(WatchOptions.builder()
        .restaurantId("123")
        .onEvents { events -> events.forEach { handle(it) } } // the cursor moves only afterwards
        .onReset { reloadEverything() } // 410 cursor_expired: reload the state
        .build())
    feed.start()
    // klient: viz /v2/docs/csharp
    await api.WatchEventsAsync(new WatchOptions
    {
        RestaurantId = "123",
        OnEvents = async (events, ct) => { foreach (var e in events) await HandleAsync(e, ct); }, // kurzor se posune až potom
        OnReset = _ => ReloadEverythingAsync(), // 410 cursor_expired: načtěte stav znovu
    }, stoppingToken);
    // the client: see /v2/docs/csharp
    await api.WatchEventsAsync(new WatchOptions
    {
        RestaurantId = "123",
        OnEvents = async (events, ct) => { foreach (var e in events) await HandleAsync(e, ct); }, // the cursor moves only afterwards
        OnReset = _ => ReloadEverythingAsync(), // 410 cursor_expired: reload the state
    }, stoppingToken);
    # klient: viz /v2/docs/python
    feed = api.watch_events(
        lambda events: [handle(event) for event in events],  # kurzor se posune až potom
        restaurant_id='123',
        on_reset=lambda error: reload_everything(),  # 410 cursor_expired: načtěte stav znovu
    )
    feed.start()
    # the client: see /v2/docs/python
    feed = api.watch_events(
        lambda events: [handle(event) for event in events],  # the cursor moves only afterwards
        restaurant_id='123',
        on_reset=lambda error: reload_everything(),  # 410 cursor_expired: reload the state
    )
    feed.start()
    // klient: viz /v2/docs/swift
    let feed = api.watchEvents(.init(
        restaurantID: "123",
        onEvents: { events in for event in events { handle(event) } }, // kurzor se posune až potom
        onReset: { _ in reloadEverything() } // 410 cursor_expired: načtěte stav znovu
    ))
    // feed.cancel() čtení ukončí
    // the client: see /v2/docs/swift
    let feed = api.watchEvents(.init(
        restaurantID: "123",
        onEvents: { events in for event in events { handle(event) } }, // the cursor moves only afterwards
        onReset: { _ in reloadEverything() } // 410 cursor_expired: reload the state
    ))
    // feed.cancel() čtení ukončí
    // klient: viz /v2/docs/dart
    final feed = api.watchEvents(
      restaurantId: '123',
      onEvents: (events) async { for (final event in events) handle(event); }, // kurzor se posune až potom
      onReset: (error) => reloadEverything(), // 410 cursor_expired: načtěte stav znovu
    )..start();
    // the client: see /v2/docs/dart
    final feed = api.watchEvents(
      restaurantId: '123',
      onEvents: (events) async { for (final event in events) handle(event); }, // the cursor moves only afterwards
      onReset: (error) => reloadEverything(), // 410 cursor_expired: reload the state
    )..start();
    // klient: viz /v2/docs/go
    err := api.WatchEvents(ctx, profirest.WatchOptions{
    	RestaurantID: "123",
    	OnEvents: func(ctx context.Context, events []model.Event) error {
    		for _, event := range events {
    			handle(event) // kurzor se posune až potom
    		}
    		return nil
    	},
    	OnReset: func(*profirest.APIError) { reloadEverything() }, // 410 cursor_expired: načtěte stav znovu
    })
    // the client: see /v2/docs/go
    err := api.WatchEvents(ctx, profirest.WatchOptions{
    	RestaurantID: "123",
    	OnEvents: func(ctx context.Context, events []model.Event) error {
    		for _, event := range events {
    			handle(event) // the cursor moves only afterwards
    		}
    		return nil
    	},
    	OnReset: func(*profirest.APIError) { reloadEverything() }, // 410 cursor_expired: reload the state
    })
    Příklad odpovědi 200Example answer 200
    {
      "data": [
        {
          "id": "910551",
          "api_version": "2",
          "sequence": 910551,
          "type": "order.created",
          "occurred_at": "2027-01-15T11:42:31+01:00",
          "connection_id": "2208",
          "account_id": "7",
          "restaurant_id": "123",
          "data": {
            "id": "184223",
            "restaurant_id": "123",
            "kitchen_number": "027",
            "status": "received",
            "status_changed_at": "2027-01-15T11:42:31+01:00",
            "created_at": "2027-01-15T11:42:31+01:00",
            "payment_deadline": null,
            "fulfillment": {
              "type": "pickup",
              "speed": "standard",
              "asap": true,
              "time": null,
              "estimated_at": "2027-01-15T12:05:00+01:00"
            },
            "customer": {
              "customer_id": null,
              "name": "Jana Nováková",
              "phone": "+420777123456",
              "email": "jana.novakova@example.cz"
            },
            "delivery": null,
            "lines": [
              {
                "id": "1",
                "type": "product",
                "product_id": "4567",
                "name": "Svíčková na smetaně, houskový knedlík",
                "quantity": 2,
                "base_unit_price": {
                  "amount": 19900,
                  "currency": "CZK"
                },
                "unit_price": {
                  "amount": 19900,
                  "currency": "CZK"
                },
                "packaging_unit_price": null,
                "vat_rate": "12",
                "add_ons": [],
                "options": [],
                "parts": null,
                "removed_ingredients": [],
                "note": null,
                "total": {
                  "amount": 39800,
                  "currency": "CZK"
                },
                "gift_of": null
              }
            ],
            "charges": [],
            "discounts": [],
            "totals": {
              "items": {
                "amount": 39800,
                "currency": "CZK"
              },
              "charges": {
                "amount": 0,
                "currency": "CZK"
              },
              "discounts": {
                "amount": 0,
                "currency": "CZK"
              },
              "rounding": {
                "amount": 0,
                "currency": "CZK"
              },
              "total": {
                "amount": 39800,
                "currency": "CZK"
              },
              "vat": [
                {
                  "rate": "12",
                  "base": {
                    "amount": 35536,
                    "currency": "CZK"
                  },
                  "vat": {
                    "amount": 4264,
                    "currency": "CZK"
                  },
                  "total": {
                    "amount": 39800,
                    "currency": "CZK"
                  }
                }
              ]
            },
            "payments": [
              {
                "id": "301877",
                "method": "cash",
                "status": "unpaid",
                "amount": {
                  "amount": 39800,
                  "currency": "CZK"
                },
                "provider": null,
                "reference": null,
                "voucher_code": null,
                "forfeited": null
              }
            ],
            "amount_to_collect": {
              "amount": 39800,
              "currency": "CZK"
            },
            "loyalty_points_earned": null,
            "note": null,
            "cancellation": null,
            "external_id": "A-2027-000123",
            "metadata": {
              "branch": "praha-3"
            }
          }
        },
        {
          "id": "910563",
          "api_version": "2",
          "sequence": 910563,
          "type": "order.status_changed",
          "occurred_at": "2027-01-15T11:44:02+01:00",
          "connection_id": "2208",
          "account_id": "7",
          "restaurant_id": "123",
          "data": {
            "id": "184223",
            "restaurant_id": "123",
            "kitchen_number": "027",
            "status": "preparing",
            "status_changed_at": "2027-01-15T11:44:02+01:00",
            "created_at": "2027-01-15T11:42:31+01:00",
            "payment_deadline": null,
            "fulfillment": {
              "type": "pickup",
              "speed": "standard",
              "asap": true,
              "time": null,
              "estimated_at": "2027-01-15T12:05:00+01:00"
            },
            "customer": {
              "customer_id": null,
              "name": "Jana Nováková",
              "phone": "+420777123456",
              "email": "jana.novakova@example.cz"
            },
            "delivery": null,
            "lines": [
              {
                "id": "1",
                "type": "product",
                "product_id": "4567",
                "name": "Svíčková na smetaně, houskový knedlík",
                "quantity": 2,
                "base_unit_price": {
                  "amount": 19900,
                  "currency": "CZK"
                },
                "unit_price": {
                  "amount": 19900,
                  "currency": "CZK"
                },
                "packaging_unit_price": null,
                "vat_rate": "12",
                "add_ons": [],
                "options": [],
                "parts": null,
                "removed_ingredients": [],
                "note": null,
                "total": {
                  "amount": 39800,
                  "currency": "CZK"
                },
                "gift_of": null
              }
            ],
            "charges": [],
            "discounts": [],
            "totals": {
              "items": {
                "amount": 39800,
                "currency": "CZK"
              },
              "charges": {
                "amount": 0,
                "currency": "CZK"
              },
              "discounts": {
                "amount": 0,
                "currency": "CZK"
              },
              "rounding": {
                "amount": 0,
                "currency": "CZK"
              },
              "total": {
                "amount": 39800,
                "currency": "CZK"
              },
              "vat": [
                {
                  "rate": "12",
                  "base": {
                    "amount": 35536,
                    "currency": "CZK"
                  },
                  "vat": {
                    "amount": 4264,
                    "currency": "CZK"
                  },
                  "total": {
                    "amount": 39800,
                    "currency": "CZK"
                  }
                }
              ]
            },
            "payments": [
              {
                "id": "301877",
                "method": "cash",
                "status": "unpaid",
                "amount": {
                  "amount": 39800,
                  "currency": "CZK"
                },
                "provider": null,
                "reference": null,
                "voucher_code": null,
                "forfeited": null
              }
            ],
            "amount_to_collect": {
              "amount": 39800,
              "currency": "CZK"
            },
            "loyalty_points_earned": null,
            "note": null,
            "cancellation": null,
            "external_id": "A-2027-000123",
            "metadata": {
              "branch": "praha-3"
            }
          }
        },
        {
          "id": "910570",
          "api_version": "2",
          "sequence": 910570,
          "type": "availability.changed",
          "occurred_at": "2027-01-15T11:45:10+01:00",
          "connection_id": "2208",
          "account_id": "7",
          "restaurant_id": "123",
          "data": {
            "restaurant_id": "123"
          }
        }
      ],
      "next_cursor": "eyJzZXEiOjkxMDU3MH0"
    }