Autentizace
API klíč
Každý požadavek na /api/v1/* musí nést hlavičku:
Authorization: Bearer sk_live_...Klíče jsou GLOBÁLNÍ (spravuje je centrála pro celou síť, ne jednotlivý subjekt) a zakládají se výhradně v portálu (sekce API) - žádný veřejný endpoint klíč nevytváří. Neplatný nebo chybějící klíč vrátí 401 s { error: "invalid-key" }.
"Globální" znamená globální v rámci VAŠÍ franšízy (licence), ne napříč celým onDuty - každá franšíza má vlastní izolovaný prostor dat. Klíč tak vidí a mutuje výhradně zaměstnance, prodejny, směny a další záznamy VLASTNÍ franšízy; cizí ID (i platné, jen patřící jiné franšíze) se chová stejně jako neexistující - { error: "not-found" } (404), nikdy 403, aby se existence cizích záznamů nijak neprozradila.
Scopes
Klíč má jeden nebo oba scopy:
read- GET endpointy.write- POST/PATCH/DELETE.
Chybějící scope vrátí 403 s { error: "missing-scope" }.
Klíč se autorizuje NEZÁVISLE na portálové matici rolí a oprávnění (sekce Oprávnění) - v1 API se chová jako centrála se VŠEMI oprávněními katalogu, omezenou jen scopem klíče (read/write) výš. Vlastní role a jejich matice ovlivňují jen portál a mobilní appku, nikdy volání s API klíčem.
Rate limit
300 požadavků za minutu na klíč. Nad limitem přijde 429 s hlavičkou Retry-After.
Idempotence mutací
POST/PATCH/DELETE volání podpoř hlavičkou Idempotency-Key (libovolný unikátní řetězec, např. UUID). Zopakuješ-li stejný požadavek se stejným klíčem do 24 hodin, dostaneš zpátky ULOŽENOU odpověď z prvního pokusu - žádná duplicitní směna, pípnutí ani žádost o volno, i když síť odpověď prvního volání ztratí a klient volání zopakuje. Výjimka: POST /api/v1/webhooks a POST /api/v1/employees hlavičku vědomě ignorují (odpověď nese jednorázové tajemství - webhook secret, resp. pozvánkový odkaz - a nesmí se ukládat do cache); opakované volání tam založí nový záznam.
curl -X POST https://www.onduty.cz/api/v1/punches \
-H "Authorization: Bearer sk_live_..." \
-H "Idempotency-Key: 5f1e2a3b-9c4d-4e2a-8f1b-1234567890ab" \
-H "Content-Type: application/json" \
-d '{"employee_id":"us_...","store_id":"st_...","direction":"in"}'Stránkování
Seznamové endpointy podporují ?cursor=&limit= (výchozí 50, max 200). Odpověď nese next_cursor - pošli ho jako cursor v dalším volání, dokud nevrátí null (poslední stránka).