Přeskočit na obsah

API dokumentace

Napojte Docházka.net na své systémy přes REST API

API v1 REST JSON

Úvod

API Docházka.net umožňuje programový přístup k docházkovým datům vaší firmy.

Poznámka: API je součástí jednotného tarifu, ve zkušební verzi dostupné není. Klíč vám na vyžádání připraví podpora (podpora@dochazka.net).

Base URL

https://dochazka.net/api/v1

Cesty endpointů níže uvádíme relativně k této adrese (např. GET /users = https://dochazka.net/api/v1/users).

Formát dat

Odpovědi jsou ve formátu JSON (výjimky u některých chyb viz Chyby → Jiný formát chyb). Požadavek s tělem (POST) musí mít hlavičku:

Content-Type: application/json

Datum a čas

  • Data v parametrech zadávejte ve formátu YYYY-MM-DD.
  • Časy docházky a směn (timestamp, arrival_time, start_time apod.) jsou v místním čase (Česká republika) ve formátu ISO 8601 bez časové zóny, např. 2026-09-01T08:00:00. Stejně je i posílejte; čas se zónou (Z, +02:00) API převede na místní čas.
  • Pole created_at u uživatelů, processed_at u docházkových záznamů a pole timestamp v chybových odpovědích a u veřejných endpointů jsou v UTC (bez označení zóny).

Autentizace

API používá autentizaci pomocí API klíčů. Klíč je vázaný na vaši firmu a vrací jen její data. Klíče vydává podpora — napište nám na podpora@dochazka.net.

  • Klíč začíná atc_. Předáme vám ho jednou; my ukládáme jen jeho otisk, takže ho později znovu zobrazit nejde — uložte si ho bezpečně. Ztracený klíč nahradíme novým.
  • Firma může mít víc klíčů (např. pro různé systémy). Klíč, který už nepotřebujete nebo mohl uniknout, na vaši žádost zrušíme — přestane fungovat okamžitě.
  • Klíč se předává jen v hlavičce X-API-Key; jiný způsob (parametr v URL, Authorization: Bearer) API nepřijímá. API nepoužívá cookies ani CSRF tokeny.

Použití API klíče

API klíč předávejte v hlavičce každého požadavku (kromě veřejných endpointů):

X-API-Key: VÁŠ_API_KLÍČ

Příklad požadavku

curl https://dochazka.net/api/v1/users \
  -H "X-API-Key: VÁŠ_API_KLÍČ"

Kdy požadavek neprojde

  • 401 — chybí hlavička X-API-Key, klíč je neplatný, zrušený nebo mu vypršela platnost, případně je účet firmy neaktivní (detail: Tenant inactive) — to platí i pro čtení po uplynutí 14denní ochranné lhůty po konci předplatného nebo u pozastaveného účtu.
  • 403 — váš tarif API nezahrnuje (např. zkušební verze).
  • 403 u zápisu (POST) — předplatné skončilo nebo je platba po splatnosti a účet je jen pro čtení. Čtení (GET) během 14denní ochranné lhůty funguje dál; zápis se obnoví po zaplacení předplatného. Stejně tak 403 vrátí zápis do ukázkové (demo) firmy.

Endpointy

Všechny endpointy v této části vyžadují hlavičku X-API-Key. U endpointů GET /users a GET /attendance vede neznámý parametr v URL k chybě 400, ostatní endpointy neznámé parametry ignorují.

Číselné parametry v URL (user_id, limit, offset, days) musí být celá čísla: user_id od 1, limit od 1 (vyšší než 1000 se sníží na 1000), offset od 0, days 1–90. Jiná hodnota (např. ?user_id=abc) vrátí 400 — filtr se nikdy tiše nevynechá. Nečíselné ID přímo v cestě (např. /analytics/productivity/abc) vrátí 404. user_id, který nepatří vaší firmě, vrátí prázdný seznam.

Uživatelé

GET /users - Seznam uživatelů

Vrací uživatele vaší firmy (ve výchozím stavu jen aktivní) seřazené podle id vzestupně, takže stránkování přes limit/offset je stabilní.

Parametry:
  • active_only (volitelné) - true = jen aktivní uživatelé, jiná hodnota = všichni (výchozí: true)
  • limit (volitelné) - Počet záznamů (výchozí: 100, max: 1000; vyšší hodnota se omezí na 1000)
  • offset (volitelné) - Kolik záznamů přeskočit (výchozí: 0)
Odpověď 200:
{
  "users": [
    {
      "id": 123,
      "username": "jnovak",
      "full_name": "Jan Novák",
      "email_caption": "Jan Novák",
      "work_hours_per_day": 8.0,
      "is_admin": false,
      "created_at": "2026-01-05T09:12:44.123456"
    }
  ]
}
  • email_caption - jméno, pod kterým zaměstnanec vystupuje v e-mailech z Jablotronu
  • work_hours_per_day - denní úvazek v hodinách
Zakládání a úpravu uživatelů zatím provádíte ve webové aplikaci (Správa → Uživatelé); přes API je nyní dostupné čtení seznamu uživatelů.

Docházka

GET /attendance - Seznam záznamů

Vrací docházkové záznamy (příchody a odchody) seřazené od nejnovějšího.

Parametry:
  • user_id (volitelné) - ID uživatele
  • start_date (volitelné) - Datum od včetně (YYYY-MM-DD)
  • end_date (volitelné) - Datum do včetně (YYYY-MM-DD)
  • limit (volitelné) - Počet záznamů (výchozí: 100, max: 1000; vyšší hodnota se omezí na 1000)
  • offset (volitelné) - Kolik záznamů přeskočit (výchozí: 0)
Odpověď 200:
{
  "records": [
    {
      "id": 456,
      "user_id": 123,
      "username": "jnovak",
      "timestamp": "2026-09-01T08:00:00",
      "type": "arrival",
      "is_manual": false,
      "processed_at": "2026-09-01T06:02:13.512834"
    }
  ],
  "count": 1
}
  • type - arrival (příchod) nebo departure (odchod)
  • is_manual - true u záznamů vzniklých v aplikaci (včetně tlačítek Přijít/Odejít na webu a ručních úprav) nebo přes API; false u záznamů načtených z e-mailu (Jablotron)
  • count - počet záznamů v této odpovědi (ne celkový počet)
  • processed_at - kdy záznam vznikl v systému (UTC); čas docházky je v timestamp
POST /attendance - Přidání záznamu

Vytvoří nový docházkový záznam a přepočítá směny daného dne.

Tělo požadavku:
{
  "user_id": 123,
  "timestamp": "2026-09-01T08:00:00",
  "type": "arrival"
}
  • user_id (povinné) - ID uživatele vaší firmy
  • timestamp (povinné) - čas YYYY-MM-DDTHH:MM:SS. Bez časové zóny se bere jako místní čas (Europe/Prague). S časovou zónou (2026-09-01T06:00:00Z, 2026-09-01T08:00:00+02:00) se převede na místní čas, v kterém se záznam uloží i vrátí. Když pošlete jen datum YYYY-MM-DD, použije se toto datum s aktuálním místním časem dne.
  • type (povinné) - arrival nebo departure
  • exit_reason (volitelné, jen u departure) - důvod odchodu: break, doctor, vacation nebo unpaid_leave; null nebo normal = běžný odchod

Jiná pole než tato čtyři API odmítne chybou 400 (stejně jako důvod odchodu break/doctor/vacation/unpaid_leave u příchodu). Záznam nelze vložit do období, které je uzavřené uzávěrkou pro mzdy (také 400). Když je účet jen pro čtení (skončené předplatné), vrátí se 403.

Odpověď 201 (záznam vytvořen):
{
  "status": "success",
  "message": "Attendance record created successfully",
  "record": {
    "id": 457,
    "user_id": 123,
    "username": "jnovak",
    "timestamp": "2026-09-01T08:00:00",
    "type": "arrival",
    "exit_reason": null,
    "is_manual": true
  },
  "shifts_updated": 1,
  "created": true
}
Odpověď 200 (duplicita):

Pokud má uživatel ve stejný den záznam stejného typu v intervalu pro detekci duplicit (výchozí 5 minut), nový záznam se nevytvoří:

{
  "status": "duplicate",
  "message": "Použit existující záznam z 08:00 (rozdíl: 1min)",
  "created": false,
  "timestamp": "2026-09-01T08:01:00"
}

Směny

GET /shifts - Seznam směn

Vrací směny vypočítané z docházkových záznamů, seřazené od nejnovějšího dne. Odpověď obsahuje nejvýše 500 směn; stránkování tento endpoint nemá, starší data získáte zúžením období.

Parametry:
  • user_id (volitelné) - ID uživatele
  • start_date (volitelné) - Datum od včetně (YYYY-MM-DD)
  • end_date (volitelné) - Datum do včetně (YYYY-MM-DD)
  • complete_only (volitelné) - true = jen uzavřené směny (s příchodem i odchodem)
Odpověď 200:
{
  "shifts": [
    {
      "id": 789,
      "user_id": 123,
      "username": "jnovak",
      "date": "2026-09-01",
      "arrival_time": "2026-09-01T08:00:00",
      "departure_time": "2026-09-01T16:30:00",
      "hours_worked": 8.5,
      "is_complete": true,
      "notes": null,
      "shift_type": "work",
      "is_paid": true,
      "approval_status": "approved"
    }
  ],
  "count": 1
}
  • Seznam obsahuje všechny úseky dne — práci, přestávky i absence. Rozliší je shift_type: work (práce), break (přestávka), doctor (lékař), vacation (dovolená), unpaid_leave (neplacené volno), sick_leave (nemoc), sick_day, comp_time (náhradní volno) a případně další druhy absencí. Pro odpracovaný čas filtrujte shift_type == "work".
  • is_paid - zda se úsek počítá jako placený; approval_status - u žádostí o absenci pending, approved nebo rejected (úseky z docházky jsou approved).
  • U neuzavřené směny je departure_time null a hours_worked 0.0.

Pracovní dny

GET /workdays - Seznam pracovních dnů

Vrací pracovní dny s agregovanými daty a jednotlivými úseky (práce, přestávky, absence), seřazené od nejnovějšího. Odpověď obsahuje nejvýše 500 dnů a souhrn summary se počítá jen z vrácených dnů.

Parametry:
  • user_id (volitelné) - ID uživatele
  • start_date (volitelné) - Datum od včetně (YYYY-MM-DD)
  • end_date (volitelné) - Datum do včetně (YYYY-MM-DD)
Odpověď 200:
{
  "workdays": [
    {
      "id": 456,
      "user_id": 123,
      "username": "jnovak",
      "date": "2026-09-01",
      "total_hours_worked": 8.0,
      "work_time_minutes": 480,
      "total_break_minutes": 30,
      "paid_absence_minutes": 0,
      "unpaid_absence_minutes": 0,
      "is_complete": true,
      "shifts": [
        {
          "id": 789,
          "start_time": "2026-09-01T08:00:00",
          "end_time": "2026-09-01T12:00:00",
          "duration_minutes": 240,
          "shift_type": "work",
          "sequence_number": 1
        },
        {
          "id": 790,
          "start_time": "2026-09-01T12:00:00",
          "end_time": "2026-09-01T12:30:00",
          "duration_minutes": 30,
          "shift_type": "break",
          "sequence_number": 2
        },
        {
          "id": 791,
          "start_time": "2026-09-01T12:30:00",
          "end_time": "2026-09-01T16:30:00",
          "duration_minutes": 240,
          "shift_type": "work",
          "sequence_number": 3
        }
      ]
    }
  ],
  "summary": {
    "total_hours": 8.0,
    "total_days": 1,
    "average_hours_per_day": 8.0,
    "total_work_time_hours": 8.0,
    "total_break_hours": 0.5,
    "total_paid_absence_hours": 0.0,
    "total_unpaid_absence_hours": 0.0
  },
  "count": 1
}
  • shift_type - druh úseku, např. work (práce), break (přestávka), doctor (lékař), vacation (dovolená), unpaid_leave (neplacené volno)
  • total_days - počet vrácených dnů s odpracovanými hodinami; count - počet vrácených dnů celkem

Analytika

GET /analytics/productivity/<user_id> - Přehled produktivity uživatele

Vyhodnotí uzavřené pracovní dny uživatele za posledních N dní: období je od data „dnes minus N dní" do dneška včetně (tedy N+1 kalendářních dní), „dnes" je dnešní datum podle českého času (Europe/Prague).

Parametry:
  • user_id (v cestě) - ID uživatele vaší firmy
  • days (volitelné) - Počet dní zpět (výchozí: 30, max: 90)
Odpověď 200:
{
  "period_days": 30,
  "total_shifts": 20,
  "avg_hours_per_day": 8.2,
  "patterns": {
    "weekday_stats": {
      "0": {
        "avg_hours": 8.3,
        "avg_start": "07:55",
        "count": 4,
        "work_time": 8.3,
        "paid_absence": 0.0
      }
    },
    "most_productive_day": 0,
    "consistency": "high",
    "hours_variance": 0.4,
    "trend": "stable",
    "total_break_hours": 10.0,
    "total_paid_absence_hours": 0.0,
    "total_unpaid_absence_hours": 0.0
  },
  "recommendations": ["…"],
  "productivity_score": 85
}
  • Dny v týdnu jsou čísla 0 (pondělí) až 6 (neděle).
  • consistency - high, medium nebo low; trend - improving, stable nebo declining.
  • total_shifts - počet uzavřených pracovních dnů v období; productivity_score - skóre 0–100.
  • Když v období žádný uzavřený den není, vrátí se 404 (detail vysvětlí, že chybí data k analýze).
  • Neexistující uživatel vrací 404, days mimo 1–90 vrací 400 (standardní formát chyby, viz Chyby).
GET /analytics/team-comparison - Porovnání týmu

Porovná aktivní uživatele za aktuální kalendářní měsíc (od 1. dne do dneška podle českého času). Započítávají se uzavřené pracovní dny; uživatelé bez nich v přehledu nejsou. Endpoint nemá parametry.

Odpověď 200:
{
  "user_stats": [
    {
      "user_id": 123,
      "username": "jnovak",
      "full_name": "Jan Novák",
      "total_hours": 150.5,
      "avg_hours": 8.36,
      "completion": 94.1,
      "shifts_count": 18,
      "target_hours": 160.0
    }
  ],
  "team_averages": {
    "completion": 94.1,
    "avg_hours": 8.36
  },
  "top_performer": {
    "user_id": 123,
    "username": "jnovak",
    "completion": 94.1
  },
  "period": "01.09. - 29.09.2026"
}
  • target_hours - pracovní dny období (bez víkendů a svátků) × denní úvazek
  • completion - odpracované hodiny v procentech z target_hours
  • top_performer - uživatel s nejvyšším completion, nebo null

Veřejné endpointy

Tyto endpointy nevyžadují API klíč.

GET /health - Stav API
{
  "status": "ok",
  "timestamp": "2026-09-01T06:00:00.000000",
  "version": "1.0.0"
}
GET /pricing - Aktuální ceník

Vrací ceny nabízeného tarifu v Kč. Konkrétní tarif lze načíst přes GET /pricing/<tarif> (např. /pricing/starter); tarif mimo nabídku vrací 400.

{
  "status": "success",
  "pricing": {
    "starter": {
      "base_fee": 0,
      "included_users": 0,
      "min_monthly": 290,
      "per_user": 39
    }
  },
  "annual_months_charged": 10,
  "larger_installations": "Individuální nabídka — kontaktujte podpora@dochazka.net",
  "timestamp": "2026-09-01T06:00:00.000000"
}

Chyby

Kód Význam Popis
200 OK Požadavek byl úspěšně zpracován (u POST /attendance i nalezená duplicita)
201 Created Záznam byl vytvořen
400 Bad Request Neplatný požadavek: neznámý nebo chybný parametr, chybné datum, chybějící či nepovolené pole v těle, uzavřené období
401 Unauthorized Chybí nebo je neplatný API klíč, případně je účet firmy neaktivní
403 Forbidden Tarif nezahrnuje přístup k API, nebo zápis do účtu, který je jen pro čtení (skončené předplatné, platba po splatnosti, ukázková firma)
404 Not Found Neexistující endpoint nebo uživatel, případně chybějící data pro analytiku (u POST /attendance vrací neexistující uživatel 400)
429 Too Many Requests Překročen limit požadavků (viz Limity)
500 Server Error Interní chyba serveru

Formát chybové odpovědi

Většina chyb vrací objekt s těmito poli:

{
  "type": "https://dochazka.net/errors/validation",
  "title": "Validation Error",
  "status": 400,
  "detail": "Unexpected query parameters: page",
  "instance": "/api/v1/users",
  "timestamp": "2026-09-01T06:00:00.000000",
  "api_version": "v1",
  "validation_details": {
    "unexpected_parameters": ["page"]
  }
}
  • status odpovídá HTTP kódu, detail popisuje konkrétní problém.
  • validation_details je jen u některých chyb 400 (klíče unexpected_parameters, missing_fields nebo unexpected_fields). U chybného pole v těle POST může být navíc klíč field (např. "timestamp" nebo "exit_reason").
  • Chyby, které nevznikají v samotném endpointu (neexistující adresa, překročený limit), mají stejná pole type, title, status, detail, instance a timestamp, title je česky a místo api_version obsahují error_id.
  • Neočekávané chyby serveru (500) většinou obsahují error_id — ten nám prosím uveďte (případně čas požadavku), když řešíte chybu s podporou na podpora@dochazka.net.

Jiný formát chyb

Endpointy s API klíčem vracejí chyby ve formátu výše. Výjimkou jsou veřejné endpointy ceníku, které při chybě vracejí {"status": "error", "message": "…", "timestamp": "…"}, a chyby 405 (nepodporovaná metoda) a 413 (požadavek větší než 16 MB), které vracejí HTML stránku serveru místo JSON.

Limity

Důležité: API má nastavené limity pro ochranu před přetížením.

Rate limiting

  • 1000 požadavků za hodinu z jedné IP adresy, počítáno zvlášť pro každý endpoint.
  • Po překročení limitu API vrací 429.
  • Odpověď neobsahuje hlavičky se stavem limitu (X-RateLimit-*) ani Retry-After.

Další omezení

  • Maximální velikost požadavku: 16 MB
  • GET /users a GET /attendance: nejvýše 1000 záznamů na požadavek (parametr limit)
  • GET /shifts a GET /workdays: nejvýše 500 nejnovějších položek, bez stránkování
  • GET /analytics/productivity/<user_id>: nejvýše 90 dní zpět

Potřebujete API přístup?

API je součástí jednotného tarifu — pro vydání klíče napište na podpora@dochazka.net

Zobrazit plány