Werzeick API

Reference API

Každé volání na https://werzeick-dev.isc.hm/api/, generované z kódu serveru: co které bere, čím odpovídá a proč odpovídá tak, jak odpovídá. Popisy jsou převzaté z kódu a jsou anglicky.

Každý požadavek kromě veřejných nese klíč v hlavičce, jak ukazuje průvodce: Authorization: Bearer wzk_…

Stáhnout jako OpenAPI 3.1 (JSON) · tatáž reference, pro generátory klientů a jiné nástroje.

Zůstává v tomto poli a jde jen na https://werzeick-dev.isc.hm/api/, v hlavičce, nikdy s vaším přihlášením: požadavek odeslaný odsud je klíče a nikoho jiného. Požadavek, který zapisuje, se ptá dvakrát.

Přihlášení a relace

Signing in and the session: a code by email, the session it buys, and the entry that session is in.

A session is one membership in one role. Switching company, or role at the same company, is a new session; the old token is revoked. An API key is made in one entry too, and acts as it unless a request names another of the same person's in the X-Werzeick-Company header, as a membership_id or membership_id:role from memberships below; the server proves it is theirs on every request. No request carries a company's id: the server reads the company from the session or the named membership, which is what keeps one firm's data from another's.

POST /api/auth/request-code

Emails a sign-in code.

Veřejné: není potřeba klíč ani relace.

It answers 202 whether or not the address has an account. Anything else would make this endpoint a way to discover who is on the platform, and since onboarding is invite-only that would also reveal which companies have invited whom.

Another code for the same address may be asked for 30 seconds after the last, and not sooner: a request within that wait is answered 429, with a Retry-After header giving the seconds left. Any address is answered so, whether or not it has an account. Too many codes in a quarter of an hour is a 429 with no Retry-After.

Tělo požadavku

PoleTypCo to je
email řetězec

Odpověď

Request code response

Příklad
{
  "status": "sent if an account exists",
  "resend_after_seconds": 30
}

Stavové kódy

KódZpráva
202
400email is required · invalid JSON body
429a code was sent moments ago; wait {seconds} seconds before asking for another · too many codes requested; wait a few minutes
500internal server error
Vyzkoušet

POST /api/auth/verify

Exchanges a code for a session.

Veřejné: není potřeba klíč ani relace.

Tělo požadavku

PoleTypCo to je
email řetězec
code řetězec

Odpověď

Session

Příklad
{
  "membership": {
    "membership_id": 12,
    "org_name": "Alpha Stavby",
    "role": "worker",
    "first_name": "Petra",
    "last_name": "Nováková",
    "emergency_responses_enabled": true,
    "cancellation_emails_enabled": true
  },
  "memberships": [
    {
      "membership_id": 12,
      "org_name": "Alpha Stavby",
      "role": "worker",
      "first_name": "Petra",
      "last_name": "Nováková",
      "emergency_responses_enabled": true,
      "cancellation_emails_enabled": true
    },
    {
      "membership_id": 27,
      "org_name": "Beta Montáže",
      "role": "manager",
      "first_name": "Petra",
      "last_name": "Nováková",
      "emergency_responses_enabled": false,
      "cancellation_emails_enabled": false
    },
    {
      "membership_id": 27,
      "org_name": "Beta Montáže",
      "role": "worker",
      "first_name": "Petra",
      "last_name": "Nováková",
      "emergency_responses_enabled": false,
      "cancellation_emails_enabled": false
    }
  ],
  "language": "cs"
}

Stavové kódy

KódZpráva
200
400email and code are required · invalid JSON body
401that code is not valid
403this account is not a member of any organization
500internal server error
Vyzkoušet

POST /api/auth/sign-out

Revokes the session.

Jen relace: API klíč je odmítnut s 403.

It succeeds even for a token that was already invalid: signing out must never fail.

Odpověď

Bez těla.

Stavové kódy

KódZpráva
204
500internal server error

GET /api/auth/me

Describes the caller: their identity, the company they are acting as, and the other companies they could switch to, or that a key could name in X-Werzeick-Company.

API klíč nebo relace.

Odpověď

Session

Příklad
{
  "membership": {
    "membership_id": 12,
    "org_name": "Alpha Stavby",
    "role": "worker",
    "first_name": "Petra",
    "last_name": "Nováková",
    "emergency_responses_enabled": true,
    "cancellation_emails_enabled": true
  },
  "memberships": [
    {
      "membership_id": 12,
      "org_name": "Alpha Stavby",
      "role": "worker",
      "first_name": "Petra",
      "last_name": "Nováková",
      "emergency_responses_enabled": true,
      "cancellation_emails_enabled": true
    },
    {
      "membership_id": 27,
      "org_name": "Beta Montáže",
      "role": "manager",
      "first_name": "Petra",
      "last_name": "Nováková",
      "emergency_responses_enabled": false,
      "cancellation_emails_enabled": false
    },
    {
      "membership_id": 27,
      "org_name": "Beta Montáže",
      "role": "worker",
      "first_name": "Petra",
      "last_name": "Nováková",
      "emergency_responses_enabled": false,
      "cancellation_emails_enabled": false
    }
  ],
  "language": "cs"
}

Stavové kódy

KódZpráva
200
401authentication required
500internal server error
Vyzkoušet

POST /api/auth/switch

Moves the caller to another of their entries — another company, or the other role at the same one — rotating the session.

Jen relace: API klíč je odmítnut s 403.

The old token stops working immediately, so nothing cached against the previous organization or role can outlive the switch.

A role the membership does not hold answers 403, exactly like a membership that is not the caller's: neither says which of the two it was.

Tělo požadavku

Names the entry to move to: a membership and the role to act in there. Both are required, and both are proved by the service.

PoleTypCo to je
membership_id celé číslo
role řetězec

Odpověď

Session

Příklad
{
  "membership": {
    "membership_id": 12,
    "org_name": "Alpha Stavby",
    "role": "worker",
    "first_name": "Petra",
    "last_name": "Nováková",
    "emergency_responses_enabled": true,
    "cancellation_emails_enabled": true
  },
  "memberships": [
    {
      "membership_id": 12,
      "org_name": "Alpha Stavby",
      "role": "worker",
      "first_name": "Petra",
      "last_name": "Nováková",
      "emergency_responses_enabled": true,
      "cancellation_emails_enabled": true
    },
    {
      "membership_id": 27,
      "org_name": "Beta Montáže",
      "role": "manager",
      "first_name": "Petra",
      "last_name": "Nováková",
      "emergency_responses_enabled": false,
      "cancellation_emails_enabled": false
    },
    {
      "membership_id": 27,
      "org_name": "Beta Montáže",
      "role": "worker",
      "first_name": "Petra",
      "last_name": "Nováková",
      "emergency_responses_enabled": false,
      "cancellation_emails_enabled": false
    }
  ],
  "language": "cs"
}

Stavové kódy

KódZpráva
200
400invalid JSON body · role must be worker or manager
401authentication required
403not permitted
500internal server error

PUT /api/auth/me/emergency-responses

Records whether this worker wants to hear about emergency cover at the company they are acting as.

API klíč nebo relace.

It names no membership: the acting one comes from the session, which is what stops this being a way to opt somebody else in or read whether they have.

Tělo požadavku

PoleTypCo to je
enabled boolean, nebo null

Odpověď

Session

Příklad
{
  "membership": {
    "membership_id": 12,
    "org_name": "Alpha Stavby",
    "role": "worker",
    "first_name": "Petra",
    "last_name": "Nováková",
    "emergency_responses_enabled": true,
    "cancellation_emails_enabled": true
  },
  "memberships": [
    {
      "membership_id": 12,
      "org_name": "Alpha Stavby",
      "role": "worker",
      "first_name": "Petra",
      "last_name": "Nováková",
      "emergency_responses_enabled": true,
      "cancellation_emails_enabled": true
    },
    {
      "membership_id": 27,
      "org_name": "Beta Montáže",
      "role": "manager",
      "first_name": "Petra",
      "last_name": "Nováková",
      "emergency_responses_enabled": false,
      "cancellation_emails_enabled": false
    },
    {
      "membership_id": 27,
      "org_name": "Beta Montáže",
      "role": "worker",
      "first_name": "Petra",
      "last_name": "Nováková",
      "emergency_responses_enabled": false,
      "cancellation_emails_enabled": false
    }
  ],
  "language": "cs"
}

Stavové kódy

KódZpráva
200
400enabled is required · invalid JSON body
401authentication required
403only a worker can take emergency shifts
500internal server error
Vyzkoušet

PUT /api/auth/me/cancellation-emails

Records whether this worker wants a cancelled shift emailed as well as pushed, at the company they are acting as.

API klíč nebo relace.

Its own endpoint rather than a second field on the emergency one: each takes {"enabled": …} and a missing key is refused, which only works when the key names one setting.

Tělo požadavku

PoleTypCo to je
enabled boolean, nebo null

Odpověď

Session

Příklad
{
  "membership": {
    "membership_id": 12,
    "org_name": "Alpha Stavby",
    "role": "worker",
    "first_name": "Petra",
    "last_name": "Nováková",
    "emergency_responses_enabled": true,
    "cancellation_emails_enabled": true
  },
  "memberships": [
    {
      "membership_id": 12,
      "org_name": "Alpha Stavby",
      "role": "worker",
      "first_name": "Petra",
      "last_name": "Nováková",
      "emergency_responses_enabled": true,
      "cancellation_emails_enabled": true
    },
    {
      "membership_id": 27,
      "org_name": "Beta Montáže",
      "role": "manager",
      "first_name": "Petra",
      "last_name": "Nováková",
      "emergency_responses_enabled": false,
      "cancellation_emails_enabled": false
    },
    {
      "membership_id": 27,
      "org_name": "Beta Montáže",
      "role": "worker",
      "first_name": "Petra",
      "last_name": "Nováková",
      "emergency_responses_enabled": false,
      "cancellation_emails_enabled": false
    }
  ],
  "language": "cs"
}

Stavové kódy

KódZpráva
200
400enabled is required · invalid JSON body
401authentication required
403only a worker is sent cancellations
500internal server error
Vyzkoušet

PUT /api/auth/me/language

Records the account's choice of language: PUT /api/auth/me/language, {"language": "cs"}.

Jen relace: API klíč je odmítnut s 403.

The app sends it from its own picker, which it has only on a phone with no per-app language setting (Android 12 and older); elsewhere the phone decides. The web client's menu records the same choice.

It names no user: the account is the session's. Answered with the whole session, like the other settings here.

Tělo požadavku

PoleTypCo to je
language řetězec

Odpověď

Session

Příklad
{
  "membership": {
    "membership_id": 12,
    "org_name": "Alpha Stavby",
    "role": "worker",
    "first_name": "Petra",
    "last_name": "Nováková",
    "emergency_responses_enabled": true,
    "cancellation_emails_enabled": true
  },
  "memberships": [
    {
      "membership_id": 12,
      "org_name": "Alpha Stavby",
      "role": "worker",
      "first_name": "Petra",
      "last_name": "Nováková",
      "emergency_responses_enabled": true,
      "cancellation_emails_enabled": true
    },
    {
      "membership_id": 27,
      "org_name": "Beta Montáže",
      "role": "manager",
      "first_name": "Petra",
      "last_name": "Nováková",
      "emergency_responses_enabled": false,
      "cancellation_emails_enabled": false
    },
    {
      "membership_id": 27,
      "org_name": "Beta Montáže",
      "role": "worker",
      "first_name": "Petra",
      "last_name": "Nováková",
      "emergency_responses_enabled": false,
      "cancellation_emails_enabled": false
    }
  ],
  "language": "cs"
}

Stavové kódy

KódZpráva
200
400invalid JSON body · language must be cs or en
401authentication required
500internal server error

Váš účet

Lets somebody delete their own account from the app.

GET /api/auth/me/deletion

Says what deleting the caller's account would do, and changes nothing.

Jen relace: API klíč je odmítnut s 403.

The app asks this before it asks the person, so the numbers are in the question.

Odpověď

Deletion

Příklad
{
  "can_delete": false,
  "companies": [
    {
      "org_name": "Alpha Stavby",
      "upcoming_shifts": 2,
      "invitations": 1,
      "clocked_in": true,
      "last_manager": false
    },
    {
      "org_name": "Beta Montáže",
      "upcoming_shifts": 0,
      "invitations": 0,
      "clocked_in": false,
      "last_manager": true
    }
  ]
}

Stavové kódy

KódZpráva
200
401authentication required
500internal server error

DELETE /api/auth/me

Erases the caller's account.

Jen relace: API klíč je odmítnut s 403.

204 when it is gone; every token the person held stops working with it, this one included.

The request has no body and names nobody. A refusal is 409 with the same shape the preview answers with, so the app can say which company would be left without a manager.

Odpověď

Bez těla.

Stavové kódy

KódZpráva
204
401authentication required
409
500internal server error

Pozvánky do firmy

How people join a company. There is no sign-up: a manager invites somebody by email, and the link in that email is accepted here. An address that already has an account gains a membership; one that does not becomes an account.

POST /api/invitations/preview

Describes an invitation to whoever holds its link: which company, what they are invited to do, and the rate offered.

Veřejné: není potřeba klíč ani relace.

Nothing is accepted.

Tělo požadavku

Carries the invitation's token, for Preview and Accept.

Public by necessity: the invitee has no account yet. The token is read from the body rather than a query string, because a query string reaches proxy logs, browser history and Referer headers — and this token is a credential.

PoleTypCo to je
token řetězec

Odpověď

Preview invitation

S hodinovou sazbou
{
  "org_name": "Alpha Stavby",
  "is_manager": false,
  "is_worker": true,
  "first_name": "Petra",
  "email": "petra@example.test",
  "rate_amount": 4200000,
  "rate_currency": "CZK"
}
Bez sazby, do obou rolí
{
  "org_name": "Beta Montáže",
  "is_manager": true,
  "is_worker": true,
  "first_name": "Petra",
  "email": "petra@example.test",
  "rate_amount": null,
  "rate_currency": null
}

Stavové kódy

KódZpráva
200
400invalid JSON body
404this invitation is invalid, expired, or already used
500internal server error
Vyzkoušet

POST /api/invitations/accept

Turns an invitation into a membership, and says how the person gets in: the same three answers the web page gives, from the same place.

Veřejné: není potřeba klíč ani relace.

Public, like Preview: somebody invited has no account yet. It still looks at the request's own session when there is one, because somebody accepting from an app they are already signed in to has nothing left to prove. That identity comes from the bearer token and never from the body.

Tělo požadavku

Carries the invitation's token, for Preview and Accept.

Public by necessity: the invitee has no account yet. The token is read from the body rather than a query string, because a query string reaches proxy logs, browser history and Referer headers — and this token is a credential.

PoleTypCo to je
token řetězec

Odpověď

Acceptance

Přijetí vytvořilo účet: přihlášeno
{
  "outcome": "signed_in",
  "email": "petra@example.test",
  "code_sent": false,
  "session": {
    "token": "not-a-real-token-only-this-fixture-has-it",
    "expires_at": "2026-11-06T07:30:00Z",
    "membership": {
      "membership_id": 12,
      "org_name": "Alpha Stavby",
      "role": "worker",
      "first_name": "Petra",
      "last_name": "Nováková",
      "emergency_responses_enabled": false,
      "cancellation_emails_enabled": true
    },
    "memberships": [
      {
        "membership_id": 12,
        "org_name": "Alpha Stavby",
        "role": "worker",
        "first_name": "Petra",
        "last_name": "Nováková",
        "emergency_responses_enabled": false,
        "cancellation_emails_enabled": true
      }
    ],
    "language": null
  },
  "membership": null
}
Účet už existoval: kód je na cestě
{
  "outcome": "needs_code",
  "email": "petra@example.test",
  "code_sent": true,
  "session": null,
  "membership": null
}
Už přihlášeno jako tento účet: připojeno
{
  "outcome": "joined",
  "email": "petra@example.test",
  "code_sent": false,
  "session": null,
  "membership": {
    "membership_id": 27,
    "org_name": "Beta Montáže",
    "role": "manager",
    "first_name": "Petra",
    "last_name": "Nováková",
    "emergency_responses_enabled": false,
    "cancellation_emails_enabled": true
  }
}

Stavové kódy

KódZpráva
200
400invalid JSON body
404this invitation is invalid, expired, or already used
500internal server error
Vyzkoušet

POST /api/invitations

Offers someone a job at the acting manager's company.

API klíč nebo relace.

There is no org field: the company comes from the session, so a manager cannot invite into a firm they do not belong to.

Tělo požadavku

PoleTypCo to je
email řetězec
first_name řetězec
last_name řetězec
is_manager boolean

What they are invited to do: either, or both. At least one must be true.

is_worker boolean
rate_amount celé číslo, nebo null

Money crosses the wire as a raw int64 with 4 implied decimals plus its currency, never pre-formatted and never a float.

Peníze: celé číslo se čtyřmi skrytými desetinnými místy, takže 4200000 je 420,00, a vedle něj měna.

rate_currency řetězec, nebo null

Odpověď

Invitation

Stavové kódy

KódZpráva
201
400a rate needs both an amount and a currency · email, first_name and last_name are required · invalid JSON body · is_manager or is_worker must be true
401authentication required
403not permitted
409that person is already in your organization
500internal server error
Vyzkoušet

GET /api/invitations

Shows who has been invited but has not yet accepted.

API klíč nebo relace.

Odpověď

seznam: Invitation

Stavové kódy

KódZpráva
200
401authentication required
403not permitted
500internal server error
Vyzkoušet

Váš týden

The worker's schedule lives here now, and so does taking an open shift, because that is where the app shows them.

GET /api/dashboard

Returns the caller's dashboard at the active company.

API klíč nebo relace.

A value that is not a number is a 400 rather than quietly the default: the app sent something it did not mean.

Parametry dotazu

  • weeks

Odpověď

Dashboard

Pracovníka
{
  "days": [
    "2026-09-07",
    "2026-09-08",
    "2026-09-09",
    "2026-09-10",
    "2026-09-11",
    "2026-09-12",
    "2026-09-13"
  ],
  "role": "worker",
  "today": "2026-09-09",
  "worker": {
    "awaiting_you": [
      {
        "can_take_from": "2026-09-10T11:00:00Z",
        "can_take_until": "2026-09-10T15:00:00Z",
        "collides_from": "2026-09-10T05:00:00Z",
        "collides_until": "2026-09-10T11:00:00Z",
        "collides_with_company": null,
        "collides_with_title": "Depot fit-out",
        "created_at": "2026-10-28T13:33:30.733171Z",
        "expires_at": "2026-09-10T07:00:00Z",
        "full": false,
        "gig_id": 1,
        "gig_title": "Warehouse roof",
        "id": 1,
        "invited_at": "2026-09-09T08:00:00Z",
        "membership_id": 2,
        "origin": "staffed",
        "rate_amount": 4200000,
        "rate_currency": "CZK",
        "responded_at": null,
        "role_id": 1,
        "role_label": "crane op",
        "status": "pending",
        "takes_from": null,
        "takes_until": null,
        "timeslot": {
          "accepted": 0,
          "created_at": "2026-10-28T13:33:30.731584Z",
          "day_id": 1,
          "ends_at": "2026-09-10T15:00:00Z",
          "gig_id": 1,
          "id": 1,
          "pending": 0,
          "required_workers": 1,
          "role_label": "crane op",
          "starts_at": "2026-09-10T07:00:00Z"
        },
        "timeslot_id": 1
      },
      {
        "can_take_from": null,
        "can_take_until": null,
        "collides_from": null,
        "collides_until": null,
        "collides_with_company": null,
        "collides_with_title": null,
        "created_at": "2026-10-28T13:33:30.781699Z",
        "expires_at": "2026-09-14T07:00:00Z",
        "full": false,
        "gig_id": 1,
        "gig_title": "Warehouse roof",
        "id": 9,
        "invited_at": "2026-09-09T08:00:00Z",
        "membership_id": 2,
        "origin": "staffed",
        "rate_amount": null,
        "rate_currency": null,
        "responded_at": null,
        "role_id": 11,
        "role_label": null,
        "status": "pending",
        "takes_from": null,
        "takes_until": null,
        "timeslot": {
          "accepted": 0,
          "created_at": "2026-10-28T13:33:30.78101Z",
          "day_id": 11,
          "ends_at": "2026-09-14T15:00:00Z",
          "gig_id": 1,
          "id": 11,
          "pending": 0,
          "required_workers": 1,
          "role_label": null,
          "starts_at": "2026-09-14T07:00:00Z"
        },
        "timeslot_id": 11
      },
      {
        "can_take_from": null,
        "can_take_until": null,
        "collides_from": null,
        "collides_until": null,
        "collides_with_company": null,
        "collides_with_title": null,
        "created_at": "2026-10-28T13:33:30.783787Z",
        "expires_at": "2026-09-15T07:00:00Z",
        "full": true,
        "gig_id": 1,
        "gig_title": "Warehouse roof",
        "id": 10,
        "invited_at": "2026-09-09T08:00:00Z",
        "membership_id": 2,
        "origin": "staffed",
        "rate_amount": null,
        "rate_currency": null,
        "responded_at": null,
        "role_id": 12,
        "role_label": null,
        "status": "pending",
        "takes_from": null,
        "takes_until": null,
        "timeslot": {
          "accepted": 1,
          "created_at": "2026-10-28T13:33:30.783093Z",
          "day_id": 12,
          "ends_at": "2026-09-15T15:00:00Z",
          "gig_id": 1,
          "id": 12,
          "pending": 0,
          "required_workers": 1,
          "role_label": null,
          "starts_at": "2026-09-15T07:00:00Z"
        },
        "timeslot_id": 12
      }
    ],
    "expiring_certificates": [
      {
        "days_left": 12,
        "expired": false,
        "expires_on": "2026-09-21",
        "id": 1,
        "kind": "weld_iso9606",
        "label": null,
        "name": "Welder qualification test (EN ISO 9606)"
      }
    ],
    "invitation_summaries": [
      {
        "count": 3,
        "first_day": "2026-09-10",
        "full_count": 1,
        "gig_id": 1,
        "gig_title": "Warehouse roof",
        "last_day": "2026-09-15",
        "minutes": 1440,
        "shift_summary": "Shifts Mon - Tue, Thu, 07:00 - 15:00",
        "unrated_minutes": 960,
        "would_earn": [
          {
            "amount": 33600000,
            "currency": "CZK"
          }
        ]
      }
    ],
    "later": [
      {
        "can_take_from": null,
        "can_take_until": null,
        "collides_from": null,
        "collides_until": null,
        "collides_with_company": null,
        "collides_with_title": null,
        "created_at": "2026-10-28T13:33:30.751859Z",
        "expires_at": "2026-09-16T07:00:00Z",
        "full": true,
        "gig_id": 1,
        "gig_title": "Warehouse roof",
        "id": 5,
        "invited_at": "2026-09-09T08:00:00Z",
        "membership_id": 2,
        "origin": "staffed",
        "rate_amount": 4200000,
        "rate_currency": "CZK",
        "responded_at": "2026-09-09T08:00:00Z",
        "role_id": 5,
        "role_label": null,
        "status": "accepted",
        "takes_from": null,
        "takes_until": null,
        "timeslot": {
          "accepted": 1,
          "created_at": "2026-10-28T13:33:30.751116Z",
          "day_id": 5,
          "ends_at": "2026-09-16T15:00:00Z",
          "gig_id": 1,
          "id": 5,
          "pending": 0,
          "required_workers": 1,
          "role_label": null,
          "starts_at": "2026-09-16T07:00:00Z"
        },
        "timeslot_id": 5
      }
    ],
    "open_shifts": [
      {
        "accepted": 0,
        "can_take_from": "2026-09-13T09:00:00Z",
        "can_take_until": "2026-09-13T15:00:00Z",
        "collides_from": "2026-09-13T05:00:00Z",
        "collides_until": "2026-09-13T09:00:00Z",
        "collides_with_company": "Beta Construction",
        "collides_with_title": "Beta depot",
        "created_at": "2026-10-28T13:33:30.755612Z",
        "day_id": 6,
        "ends_at": "2026-09-13T15:00:00Z",
        "gig_id": 1,
        "gig_title": "Warehouse roof",
        "id": 6,
        "mine_status": "",
        "pending": 0,
        "rate_amount": 5000000,
        "rate_currency": "CZK",
        "required_workers": 1,
        "role_id": 6,
        "role_label": "crane op",
        "starts_at": "2026-09-13T07:00:00Z",
        "taking_confirms": true
      },
      {
        "accepted": 0,
        "can_take_from": "2026-09-13T09:00:00Z",
        "can_take_until": "2026-09-13T15:00:00Z",
        "collides_from": "2026-09-13T05:00:00Z",
        "collides_until": "2026-09-13T09:00:00Z",
        "collides_with_company": "Beta Construction",
        "collides_with_title": "Beta depot",
        "created_at": "2026-10-28T13:33:30.757429Z",
        "day_id": 6,
        "ends_at": "2026-09-13T15:00:00Z",
        "gig_id": 1,
        "gig_title": "Warehouse roof",
        "id": 7,
        "mine_status": "",
        "pending": 0,
        "rate_amount": null,
        "rate_currency": null,
        "required_workers": 1,
        "role_id": 7,
        "role_label": "crane op",
        "starts_at": "2026-09-13T07:00:00Z",
        "taking_confirms": false
      }
    ],
    "still_to_earn": [
      {
        "amount": 92400000,
        "currency": "CZK"
      }
    ],
    "still_to_earn_unrated_minutes": 0,
    "this_week": [
      {
        "can_take_from": null,
        "can_take_until": null,
        "collides_from": null,
        "collides_until": null,
        "collides_with_company": null,
        "collides_with_title": null,
        "created_at": "2026-10-28T13:33:30.736907Z",
        "expires_at": "2026-09-10T05:00:00Z",
        "full": true,
        "gig_id": 2,
        "gig_title": "Depot fit-out",
        "id": 2,
        "invited_at": "2026-09-09T08:00:00Z",
        "membership_id": 2,
        "origin": "staffed",
        "rate_amount": 4200000,
        "rate_currency": "CZK",
        "responded_at": "2026-09-09T08:00:00Z",
        "role_id": 2,
        "role_label": null,
        "status": "accepted",
        "takes_from": null,
        "takes_until": null,
        "timeslot": {
          "accepted": 1,
          "created_at": "2026-10-28T13:33:30.736124Z",
          "day_id": 2,
          "ends_at": "2026-09-10T11:00:00Z",
          "gig_id": 2,
          "id": 2,
          "pending": 0,
          "required_workers": 1,
          "role_label": null,
          "starts_at": "2026-09-10T05:00:00Z"
        },
        "timeslot_id": 2
      },
      {
        "can_take_from": null,
        "can_take_until": null,
        "collides_from": null,
        "collides_until": null,
        "collides_with_company": null,
        "collides_with_title": null,
        "created_at": "2026-10-28T13:33:30.741932Z",
        "expires_at": "2026-09-11T07:00:00Z",
        "full": true,
        "gig_id": 1,
        "gig_title": "Warehouse roof",
        "id": 3,
        "invited_at": "2026-09-09T08:00:00Z",
        "membership_id": 2,
        "origin": "staffed",
        "rate_amount": 4200000,
        "rate_currency": "CZK",
        "responded_at": "2026-09-09T08:00:00Z",
        "role_id": 3,
        "role_label": null,
        "status": "accepted",
        "takes_from": null,
        "takes_until": null,
        "timeslot": {
          "accepted": 1,
          "created_at": "2026-10-28T13:33:30.741178Z",
          "day_id": 3,
          "ends_at": "2026-09-11T15:00:00Z",
          "gig_id": 1,
          "id": 3,
          "pending": 0,
          "required_workers": 1,
          "role_label": null,
          "starts_at": "2026-09-11T07:00:00Z"
        },
        "timeslot_id": 3
      },
      {
        "can_take_from": null,
        "can_take_until": null,
        "collides_from": null,
        "collides_until": null,
        "collides_with_company": null,
        "collides_with_title": null,
        "created_at": "2026-10-28T13:33:30.746586Z",
        "expires_at": "2026-09-12T07:00:00Z",
        "full": false,
        "gig_id": 1,
        "gig_title": "Warehouse roof",
        "id": 4,
        "invited_at": "2026-09-09T08:00:00Z",
        "membership_id": 2,
        "origin": "staffed",
        "rate_amount": 4200000,
        "rate_currency": "CZK",
        "responded_at": "2026-09-09T08:00:00Z",
        "role_id": 4,
        "role_label": null,
        "status": "cancelled",
        "takes_from": null,
        "takes_until": null,
        "timeslot": {
          "accepted": 0,
          "created_at": "2026-10-28T13:33:30.745806Z",
          "day_id": 4,
          "ends_at": "2026-09-12T15:00:00Z",
          "gig_id": 1,
          "id": 4,
          "pending": 0,
          "required_workers": 1,
          "role_label": null,
          "starts_at": "2026-09-12T07:00:00Z"
        },
        "timeslot_id": 4
      }
    ],
    "worked_this_month": {
      "earned": [
        {
          "amount": 16800000,
          "currency": "CZK"
        }
      ],
      "minutes": 240,
      "unrated_minutes": 0
    },
    "worked_this_week": {
      "earned": [
        {
          "amount": 16800000,
          "currency": "CZK"
        }
      ],
      "minutes": 240,
      "unrated_minutes": 0
    }
  }
}
Manažera
{
  "days": [
    "2026-09-07",
    "2026-09-08",
    "2026-09-09",
    "2026-09-10",
    "2026-09-11",
    "2026-09-12",
    "2026-09-13"
  ],
  "manager": {
    "attention": [
      {
        "accepted": 0,
        "created_at": "2026-10-28T13:33:30.731584Z",
        "day_id": 1,
        "ends_at": "2026-09-10T15:00:00Z",
        "gig_id": 1,
        "gig_title": "Warehouse roof",
        "id": 1,
        "pending": 1,
        "required_workers": 1,
        "role_label": "crane op",
        "starts_at": "2026-09-10T07:00:00Z"
      },
      {
        "accepted": 0,
        "created_at": "2026-10-28T13:33:30.76944Z",
        "day_id": 1,
        "ends_at": "2026-09-10T22:00:00Z",
        "gig_id": 1,
        "gig_title": "Warehouse roof",
        "id": 9,
        "pending": 0,
        "required_workers": 2,
        "role_label": null,
        "starts_at": "2026-09-10T14:00:00Z"
      },
      {
        "accepted": 0,
        "created_at": "2026-10-28T13:33:30.745806Z",
        "day_id": 4,
        "ends_at": "2026-09-12T15:00:00Z",
        "gig_id": 1,
        "gig_title": "Warehouse roof",
        "id": 4,
        "pending": 0,
        "required_workers": 1,
        "role_label": null,
        "starts_at": "2026-09-12T07:00:00Z"
      },
      {
        "accepted": 0,
        "created_at": "2026-10-28T13:33:30.755612Z",
        "day_id": 6,
        "ends_at": "2026-09-13T15:00:00Z",
        "gig_id": 1,
        "gig_title": "Warehouse roof",
        "id": 6,
        "pending": 0,
        "required_workers": 1,
        "role_label": "crane op",
        "starts_at": "2026-09-13T07:00:00Z"
      },
      {
        "accepted": 0,
        "created_at": "2026-10-28T13:33:30.757429Z",
        "day_id": 6,
        "ends_at": "2026-09-13T15:00:00Z",
        "gig_id": 1,
        "gig_title": "Warehouse roof",
        "id": 7,
        "pending": 0,
        "required_workers": 1,
        "role_label": "crane op",
        "starts_at": "2026-09-13T07:00:00Z"
      },
      {
        "accepted": 0,
        "created_at": "2026-10-28T13:33:30.78101Z",
        "day_id": 11,
        "ends_at": "2026-09-14T15:00:00Z",
        "gig_id": 1,
        "gig_title": "Warehouse roof",
        "id": 11,
        "pending": 1,
        "required_workers": 1,
        "role_label": null,
        "starts_at": "2026-09-14T07:00:00Z"
      },
      {
        "accepted": 1,
        "created_at": "2026-10-28T13:33:30.783093Z",
        "day_id": 12,
        "ends_at": "2026-09-15T15:00:00Z",
        "gig_id": 1,
        "gig_title": "Warehouse roof",
        "id": 12,
        "pending": 1,
        "required_workers": 1,
        "role_label": null,
        "starts_at": "2026-09-15T07:00:00Z"
      }
    ],
    "attention_summaries": [
      {
        "accepted": 1,
        "count": 7,
        "first_day": "2026-09-10",
        "gig_id": 1,
        "gig_title": "Warehouse roof",
        "imminent": true,
        "last_day": "2026-09-15",
        "pending": 3,
        "required": 8,
        "shift_summary": "Shifts Mon - Tue, Sat, 07:00 - 15:00, Thu 07:00 - 15:00, 14:00 - 22:00, Sun 07:00 - 15:00, 07:00 - 15:00",
        "short": 7
      }
    ],
    "hours_to_check": [
      {
        "entry": {
          "clock_in_at": "2026-09-02T07:00:00Z",
          "clock_out_at": "2026-09-02T22:00:00Z",
          "corrected_at": null,
          "created_at": "2026-10-28T13:33:30.768583Z",
          "earned_amount": 57000000,
          "gig_id": 1,
          "id": 3,
          "membership_id": 5,
          "rate_amount": 3800000,
          "rate_currency": "CZK",
          "source": "manual",
          "timeslot_id": 8
        },
        "gig_title": "Warehouse roof",
        "missing_clock_out": false,
        "outside_shift": true,
        "slot_ends_at": "2026-09-02T15:00:00Z",
        "slot_starts_at": "2026-09-02T07:00:00Z",
        "worker_name": "Second Alpha Stavby"
      },
      {
        "entry": {
          "clock_in_at": "2026-09-03T07:00:00Z",
          "clock_out_at": "2026-09-03T22:00:00Z",
          "corrected_at": null,
          "created_at": "2026-10-28T13:33:30.779978Z",
          "earned_amount": null,
          "gig_id": 1,
          "id": 4,
          "membership_id": 6,
          "rate_amount": null,
          "rate_currency": null,
          "source": "manual",
          "timeslot_id": 10
        },
        "gig_title": "Warehouse roof",
        "missing_clock_out": false,
        "outside_shift": true,
        "slot_ends_at": "2026-09-03T15:00:00Z",
        "slot_starts_at": "2026-09-03T07:00:00Z",
        "worker_name": "Unrated Alpha Stavby"
      },
      {
        "entry": {
          "clock_in_at": "2026-09-08T06:00:00Z",
          "clock_out_at": null,
          "corrected_at": null,
          "created_at": "2026-10-28T13:33:30.763173Z",
          "earned_amount": 0,
          "gig_id": 1,
          "id": 2,
          "membership_id": 2,
          "rate_amount": 4200000,
          "rate_currency": "CZK",
          "source": "manual",
          "timeslot_id": null
        },
        "gig_title": "Warehouse roof",
        "missing_clock_out": true,
        "outside_shift": false,
        "slot_ends_at": null,
        "slot_starts_at": null,
        "worker_name": "Worker Alpha Stavby"
      }
    ],
    "turned_down": [
      {
        "created_at": "2026-10-28T13:33:30.770123Z",
        "expires_at": "2026-09-10T14:00:00Z",
        "gig_title": "Warehouse roof",
        "id": 7,
        "invited_at": "2026-09-09T08:00:00Z",
        "membership_id": 5,
        "origin": "staffed",
        "rate_amount": 3800000,
        "rate_currency": "CZK",
        "responded_at": "2026-09-09T08:00:00Z",
        "role_id": 9,
        "role_label": null,
        "status": "withdrawn",
        "takes_from": null,
        "takes_until": null,
        "timeslot": {
          "accepted": 0,
          "created_at": "2026-10-28T13:33:30.76944Z",
          "day_id": 1,
          "ends_at": "2026-09-10T22:00:00Z",
          "gig_id": 1,
          "id": 9,
          "pending": 0,
          "required_workers": 2,
          "role_label": null,
          "starts_at": "2026-09-10T14:00:00Z"
        },
        "timeslot_id": 9,
        "worker_name": "Second Alpha Stavby"
      }
    ],
    "week": [
      {
        "accepted": 0,
        "day": "2026-09-07",
        "pending": 0,
        "required": 0,
        "short": 0,
        "slots": 0
      },
      {
        "accepted": 0,
        "day": "2026-09-08",
        "pending": 0,
        "required": 0,
        "short": 0,
        "slots": 0
      },
      {
        "accepted": 0,
        "day": "2026-09-09",
        "pending": 0,
        "required": 0,
        "short": 0,
        "slots": 0
      },
      {
        "accepted": 1,
        "day": "2026-09-10",
        "pending": 1,
        "required": 4,
        "short": 3,
        "slots": 3
      },
      {
        "accepted": 1,
        "day": "2026-09-11",
        "pending": 0,
        "required": 1,
        "short": 0,
        "slots": 1
      },
      {
        "accepted": 0,
        "day": "2026-09-12",
        "pending": 0,
        "required": 1,
        "short": 1,
        "slots": 1
      },
      {
        "accepted": 0,
        "day": "2026-09-13",
        "pending": 0,
        "required": 2,
        "short": 2,
        "slots": 2
      }
    ],
    "worked_this_week": {
      "earned": [
        {
          "amount": 16800000,
          "currency": "CZK"
        }
      ],
      "minutes": 240,
      "unrated_minutes": 0
    }
  },
  "role": "manager",
  "today": "2026-09-09"
}

Stavové kódy

KódZpráva
200
400weeks must be a whole number
401authentication required
403not permitted
500internal server error
Vyzkoušet

POST /api/timeslots/{id}/take

Puts the caller on a shift a PM opened to the company.

API klíč nebo relace.

The body names the role being taken, role_id, as the dashboard's open shift row carried it: an open shift is listed once per role, each with its own places and figure. It may be left out for a shift with one role. The request carries no rate: the figure is resolved on the server at signup and snapshotted, exactly as the dashboard quoted it; a client never sends the number it believes it was offered. partial is consent to take only the free remainder of a shift that collides with accepted work.

What comes back is the assignment: accepted on a shift that confirms takers, pending on one where the manager picks. The app re-reads the dashboard either way.

V cestě

ParametrCo to je
idId směny.

Tělo požadavku

PoleTypCo to je
partial boolean
role_id celé číslo

Odpověď

Assignment

Příklad
{
  "id": 2,
  "timeslot_id": 2,
  "membership_id": 2,
  "origin": "sos",
  "status": "accepted",
  "rate_amount": 6300000,
  "rate_currency": "CZK",
  "invited_at": "2026-09-07T09:00:00Z",
  "responded_at": "2026-09-07T09:05:00Z",
  "expires_at": "2026-09-10T05:00:00Z",
  "created_at": "2026-09-07T09:00:00Z",
  "takes_from": "2026-09-10T09:00:00Z",
  "takes_until": "2026-09-10T13:00:00Z",
  "role_id": 2,
  "role_label": "crane op"
}

Stavové kódy

KódZpráva
201
400invalid timeslot id · this shift has several roles; send role_id
401authentication required
403not permitted · this shift raises an hourly rate, and you have none here to raise
404shift not found
409
500internal server error
Vyzkoušet

Směny a odpovědi

The worker's side of staffing: what am I being asked to do, and my answer.

A PM's staffing screens live in the web client for now; the same services back both, so a manager overview in the app is rendering work, not new logic.

GET /api/schedule

Returns the caller's own assignments at the active company.

API klíč nebo relace.

Odpověď

seznam: Schedule entry

Příklad
[
  {
    "id": 1,
    "timeslot_id": 1,
    "membership_id": 2,
    "origin": "staffed",
    "status": "pending",
    "rate_amount": 4200000,
    "rate_currency": "CZK",
    "invited_at": "2026-09-07T08:00:00Z",
    "responded_at": null,
    "expires_at": "2026-09-09T07:00:00Z",
    "created_at": "2026-09-07T08:00:00Z",
    "takes_from": null,
    "takes_until": null,
    "role_id": 1,
    "role_label": null,
    "timeslot": {
      "id": 1,
      "gig_id": 1,
      "day_id": 1,
      "starts_at": "2026-09-09T07:00:00Z",
      "ends_at": "2026-09-09T15:00:00Z",
      "required_workers": 2,
      "role_label": null,
      "created_at": "2026-09-07T08:00:00Z",
      "accepted": 0,
      "pending": 1
    },
    "gig_id": 1,
    "gig_title": "Warehouse roof",
    "full": false,
    "collides_with_title": "Depot fit-out",
    "collides_with_company": null,
    "collides_from": "2026-09-09T05:00:00Z",
    "collides_until": "2026-09-09T11:00:00Z",
    "can_take_from": "2026-09-09T11:00:00Z",
    "can_take_until": "2026-09-09T15:00:00Z"
  },
  {
    "id": 2,
    "timeslot_id": 2,
    "membership_id": 2,
    "origin": "sos",
    "status": "accepted",
    "rate_amount": 6300000,
    "rate_currency": "CZK",
    "invited_at": "2026-09-07T09:00:00Z",
    "responded_at": "2026-09-07T09:05:00Z",
    "expires_at": "2026-09-10T05:00:00Z",
    "created_at": "2026-09-07T09:00:00Z",
    "takes_from": "2026-09-10T09:00:00Z",
    "takes_until": "2026-09-10T13:00:00Z",
    "role_id": 2,
    "role_label": "crane op",
    "timeslot": {
      "id": 2,
      "gig_id": 2,
      "day_id": 2,
      "starts_at": "2026-09-10T05:00:00Z",
      "ends_at": "2026-09-10T13:00:00Z",
      "required_workers": 1,
      "role_label": "crane op",
      "created_at": "2026-09-07T09:00:00Z",
      "accepted": 1,
      "pending": 0
    },
    "gig_id": 2,
    "gig_title": "Depot fit-out",
    "full": false,
    "collides_with_title": null,
    "collides_with_company": null,
    "collides_from": null,
    "collides_until": null,
    "can_take_from": null,
    "can_take_until": null
  },
  {
    "id": 3,
    "timeslot_id": 3,
    "membership_id": 2,
    "origin": "open",
    "status": "pending",
    "rate_amount": 6300000,
    "rate_currency": "CZK",
    "invited_at": "2026-09-07T10:00:00Z",
    "responded_at": null,
    "expires_at": "2026-09-11T05:00:00Z",
    "created_at": "2026-09-07T10:00:00Z",
    "takes_from": null,
    "takes_until": null,
    "role_id": 3,
    "role_label": null,
    "timeslot": {
      "id": 3,
      "gig_id": 1,
      "day_id": 3,
      "starts_at": "2026-09-11T05:00:00Z",
      "ends_at": "2026-09-11T13:00:00Z",
      "required_workers": 2,
      "role_label": null,
      "created_at": "2026-09-07T10:00:00Z",
      "accepted": 1,
      "pending": 1
    },
    "gig_id": 1,
    "gig_title": "Warehouse roof",
    "full": false,
    "collides_with_title": null,
    "collides_with_company": null,
    "collides_from": null,
    "collides_until": null,
    "can_take_from": null,
    "can_take_until": null
  },
  {
    "id": 4,
    "timeslot_id": 4,
    "membership_id": 2,
    "origin": "staffed",
    "status": "pending",
    "rate_amount": null,
    "rate_currency": null,
    "invited_at": "2026-09-07T11:00:00Z",
    "responded_at": null,
    "expires_at": "2026-09-14T05:00:00Z",
    "created_at": "2026-09-07T11:00:00Z",
    "takes_from": null,
    "takes_until": null,
    "role_id": 4,
    "role_label": null,
    "timeslot": {
      "id": 4,
      "gig_id": 1,
      "day_id": 4,
      "starts_at": "2026-09-14T05:00:00Z",
      "ends_at": "2026-09-14T13:00:00Z",
      "required_workers": 2,
      "role_label": null,
      "created_at": "2026-09-07T11:00:00Z",
      "accepted": 2,
      "pending": 1
    },
    "gig_id": 1,
    "gig_title": "Warehouse roof",
    "full": true,
    "collides_with_title": null,
    "collides_with_company": null,
    "collides_from": null,
    "collides_until": null,
    "can_take_from": null,
    "can_take_until": null
  }
]

Stavové kódy

KódZpráva
200
401authentication required
403not permitted
500internal server error
Vyzkoušet

POST /api/assignments/{id}/respond

Records a worker's answer to one assignment.

API klíč nebo relace.

Accept, decline and withdraw share a route because they share a lifecycle; the action is in the body rather than the path so a client cannot invent one.

V cestě

ParametrCo to je
idId přiřazení: vašeho místa na směně.

Tělo požadavku

PoleTypCo to je
action řetězec
partial boolean

partial is consent to take only the free remainder of a shift that collides with accepted work. The span itself is the server's to compute under its locks; a client never sends one.

Odpověď

Assignment

Příklad
{
  "id": 2,
  "timeslot_id": 2,
  "membership_id": 2,
  "origin": "sos",
  "status": "accepted",
  "rate_amount": 6300000,
  "rate_currency": "CZK",
  "invited_at": "2026-09-07T09:00:00Z",
  "responded_at": "2026-09-07T09:05:00Z",
  "expires_at": "2026-09-10T05:00:00Z",
  "created_at": "2026-09-07T09:00:00Z",
  "takes_from": "2026-09-10T09:00:00Z",
  "takes_until": "2026-09-10T13:00:00Z",
  "role_id": 2,
  "role_label": "crane op"
}

Stavové kódy

KódZpráva
200
400action must be "accept", "decline" or "withdraw" · invalid JSON body · invalid assignment id
401authentication required
403not permitted · that application is the manager's to approve
404assignment not found
409that invitation is no longer open · that is an invitation, and only the worker can accept it · that shift collides with work you have accepted · that shift is already full
500internal server error
Vyzkoušet

POST /api/gigs/{id}/invitations/respond

Answers every invitation the caller has not answered on one project: "Accept all" and "Decline all" beside a project's invitations.

API klíč nebo relace.

It names a project and an action and nothing else. Which invitations those are is decided here, at the moment of the tap, from the caller's own membership — a client never sends a list of ids it believes are its own. Another company's project, or one with nothing waiting, answers 200 with zeros: there was nothing to do, and that is all anybody is told.

V cestě

ParametrCo to je
idId zakázky.

Tělo požadavku

PoleTypCo to je
action řetězec

Odpověď

Answered invitations

Příklad
{
  "answered": 2,
  "full": 1,
  "colliding": 0
}

Stavové kódy

KódZpráva
200
400action must be "accept" or "decline" · invalid JSON body · invalid project id
401authentication required
403not permitted · that application is the manager's to approve
404assignment not found
409that invitation is no longer open · that is an invitation, and only the worker can accept it · that shift collides with work you have accepted · that shift is already full
500internal server error
Vyzkoušet

POST /api/devices

Records an FCM token so this phone can be reached.

Jen relace: API klíč je odmítnut s 403.

Tělo požadavku

PoleTypCo to je
token řetězec
platform řetězec
language řetězec

Odpověď

Bez těla.

Stavové kódy

KódZpráva
204
400invalid JSON body
401authentication required

DELETE /api/devices

Drops this phone's token, on sign-out.

Jen relace: API klíč je odmítnut s 403.

Without it, a worker who signs out — or hands the phone on — keeps receiving shift notifications for a session they no longer have.

Tělo požadavku

PoleTypCo to je
token řetězec

Odpověď

Bez těla.

Stavové kódy

KódZpráva
204
400a device token is required · invalid JSON body
401authentication required
403not permitted
500internal server error

Příchod a odchod

Clocking in and out, from the app.

This is the endpoint a worker uses standing on a building site, often with one bar of signal, sometimes with none. Two consequences run through it:

  • The device supplies the timestamp, and the server takes it. Stamping an entry with the moment it happened to sync would be wrong by hours for exactly the worker who most needs the record to be right.
  • Every write is idempotent on the device's own event id, so a retry after a dropped connection is harmless.

What is NOT here, and must never be: any coordinate. Geofence auto-clocking computes distance on the phone against the one site it was given and posts the same clock event a thumb would. source is the whole of the difference.

POST /api/time/clock-in

Starts a stretch of work.

API klíč nebo relace.

Tělo požadavku

The entire wire shape of a clock event. Keep it that way.

PoleTypCo to je
gig_id celé číslo
at řetězec

at is the device's clock, RFC 3339 with an offset. Omitted means now.

source řetězec

source is "manual" or "geofence"; empty means manual.

client_event_id řetězec

client_event_id is the device's id for this event, and the reason a replayed push creates one row rather than two.

Odpověď

Time entry

Příklad
{
  "id": 2,
  "membership_id": 2,
  "gig_id": 1,
  "timeslot_id": null,
  "clock_in_at": "2026-09-09T06:20:00Z",
  "clock_out_at": null,
  "source": "geofence",
  "rate_amount": 4200000,
  "rate_currency": "CZK",
  "earned_amount": 0,
  "corrected_at": null,
  "created_at": "2026-09-09T06:20:00Z"
}

Stavové kódy

KódZpráva
200
400at must be an RFC 3339 timestamp · invalid JSON body
401authentication required
403not permitted
404time entry not found
409
500internal server error
Vyzkoušet

POST /api/time/clock-out

Ends one, naming it by the device's event id when the phone has been offline and by project otherwise.

API klíč nebo relace.

Tělo požadavku

The entire wire shape of a clock event. Keep it that way.

PoleTypCo to je
gig_id celé číslo
at řetězec

at is the device's clock, RFC 3339 with an offset. Omitted means now.

source řetězec

source is "manual" or "geofence"; empty means manual.

client_event_id řetězec

client_event_id is the device's id for this event, and the reason a replayed push creates one row rather than two.

Odpověď

Time entry

Příklad
{
  "id": 1,
  "membership_id": 2,
  "gig_id": 1,
  "timeslot_id": 1,
  "clock_in_at": "2026-09-08T07:45:00Z",
  "clock_out_at": "2026-09-08T17:10:00Z",
  "source": "manual",
  "rate_amount": 4200000,
  "rate_currency": "CZK",
  "earned_amount": 39550000,
  "client_event_id": "9f8c1a2b3d4e5f60718293a4b5c6d7e8",
  "corrected_at": null,
  "created_at": "2026-09-08T07:45:00Z"
}

Stavové kódy

KódZpráva
200
400at must be an RFC 3339 timestamp · clock-out needs a gig_id or a client_event_id · invalid JSON body
401authentication required
403not permitted
404time entry not found
409
500internal server error
Vyzkoušet

GET /api/time/entries

The worker's own record of their hours.

API klíč nebo relace.

since defaults to four weeks back: enough to check a pay period, little enough that a phone on a slow connection is not downloading a year.

Parametry dotazu

  • since

Odpověď

seznam: Time entry

Příklad
[
  {
    "id": 1,
    "membership_id": 2,
    "gig_id": 1,
    "timeslot_id": 1,
    "clock_in_at": "2026-09-08T07:45:00Z",
    "clock_out_at": "2026-09-08T17:10:00Z",
    "source": "manual",
    "rate_amount": 4200000,
    "rate_currency": "CZK",
    "earned_amount": 39550000,
    "client_event_id": "9f8c1a2b3d4e5f60718293a4b5c6d7e8",
    "corrected_at": null,
    "created_at": "2026-09-08T07:45:00Z"
  },
  {
    "id": 2,
    "membership_id": 2,
    "gig_id": 1,
    "timeslot_id": null,
    "clock_in_at": "2026-09-09T06:20:00Z",
    "clock_out_at": null,
    "source": "geofence",
    "rate_amount": 4200000,
    "rate_currency": "CZK",
    "earned_amount": 0,
    "corrected_at": null,
    "created_at": "2026-09-09T06:20:00Z"
  },
  {
    "id": 3,
    "membership_id": 2,
    "gig_id": 1,
    "timeslot_id": null,
    "clock_in_at": "2026-09-10T06:00:00Z",
    "clock_out_at": "2026-09-10T14:30:00Z",
    "source": "manual",
    "rate_amount": null,
    "rate_currency": null,
    "earned_amount": null,
    "corrected_at": null,
    "created_at": "2026-09-10T06:00:00Z"
  }
]

Stavové kódy

KódZpráva
200
400since must be an RFC 3339 timestamp
401authentication required
403not permitted
404time entry not found
409
500internal server error
Vyzkoušet

POST /api/time/entries/{id}/correct

Fixes an entry's times.

API klíč nebo relace.

A worker owns their own hours; a manager may resolve anyone's, which is how discrepancies get settled.

V cestě

ParametrCo to je
idId záznamu času.

Tělo požadavku

PoleTypCo to je
clock_in_at řetězec
clock_out_at řetězec, nebo null

Odpověď

Time entry

Příklad
{
  "id": 1,
  "membership_id": 2,
  "gig_id": 1,
  "timeslot_id": 1,
  "clock_in_at": "2026-09-08T07:45:00Z",
  "clock_out_at": "2026-09-08T17:10:00Z",
  "source": "manual",
  "rate_amount": 4200000,
  "rate_currency": "CZK",
  "earned_amount": 39550000,
  "client_event_id": "9f8c1a2b3d4e5f60718293a4b5c6d7e8",
  "corrected_at": null,
  "created_at": "2026-09-08T07:45:00Z"
}

Stavové kódy

KódZpráva
200
400clock_in_at must be an RFC 3339 timestamp · clock_out_at must be an RFC 3339 timestamp or null · invalid JSON body · invalid time entry id
401authentication required
403not permitted
404time entry not found
409
500internal server error
Vyzkoušet

Zakázky a výdaje

Projects, which the API calls gigs: the unit of work a company plans, from one shift to months, with a site, a client and the expenses booked against it. A manager sees every project at the company; a worker sees the ones they have a part in and the ones with a shift they could take.

GET /api/gigs

Lists the caller's projects at the company they are acting in.

API klíč nebo relace.

A manager gets every live project. A worker gets the ones they have a part in, newest first, and after those the ones with an open shift they could take; each row says which with is_assigned, is_invited and shifts_to_take. Archived projects are not listed, though each still answers at its own address.

all=1 lists them at every company and role the caller holds, each entry's projects as that entry would list them, with company on each row naming the entry: send its entry as X-Werzeick-Company to act on the project. Somebody who both manages and works at one company sees such a project once for each. It cannot be combined with X-Werzeick-Company.

Parametry dotazu

  • all

Odpověď

seznam: Project

Příklad
{
  "id": 3,
  "title": "Foundation pour",
  "owner_id": 4,
  "project_manager": {
    "name": "Martin Dvořák",
    "phone": "+420603456789",
    "email": null
  },
  "client_id": 7,
  "client_name": "Kaufland Česká republika",
  "client_contact_name": "Petra Marková",
  "client_contact_phone": "+420602123456",
  "client_contact_email": "petra.markova@kaufland.cz",
  "job_contact": {
    "company": null,
    "name": "Jana Horáková, has the keys",
    "phone": "+420777111222"
  },
  "latitude": 49.8209,
  "longitude": 18.2625,
  "geofence_radius_m": 150,
  "site_address": "Gate 3, Průmyslová 1472/12, 702 00 Ostrava",
  "expected_minutes": 480,
  "is_assigned": true,
  "is_invited": false,
  "shifts_to_take": 2,
  "archived_at": null,
  "expenses": [],
  "created_at": "2026-09-07T16:06:11.113221+02:00",
  "site_outline": [
    {
      "lat": 49.8205,
      "lon": 18.2615
    },
    {
      "lat": 49.8205,
      "lon": 18.2636
    },
    {
      "lat": 49.82131,
      "lon": 18.2636
    },
    {
      "lat": 49.82131,
      "lon": 18.2615
    }
  ]
}

Stavové kódy

KódZpráva
200
400all=1 reads every company: leave out X-Werzeick-Company
401authentication required
403not permitted
500internal server error
Vyzkoušet

GET /api/gigs/{id}

One project, in the same shape the list gives it.

API klíč nebo relace.

A project the caller cannot list, another company's included, answers 404: it does not exist for them.

V cestě

ParametrCo to je
idId zakázky.

Odpověď

Project

Příklad
{
  "id": 3,
  "title": "Foundation pour",
  "owner_id": 4,
  "project_manager": {
    "name": "Martin Dvořák",
    "phone": "+420603456789",
    "email": null
  },
  "client_id": 7,
  "client_name": "Kaufland Česká republika",
  "client_contact_name": "Petra Marková",
  "client_contact_phone": "+420602123456",
  "client_contact_email": "petra.markova@kaufland.cz",
  "job_contact": {
    "company": null,
    "name": "Jana Horáková, has the keys",
    "phone": "+420777111222"
  },
  "latitude": 49.8209,
  "longitude": 18.2625,
  "geofence_radius_m": 150,
  "site_address": "Gate 3, Průmyslová 1472/12, 702 00 Ostrava",
  "expected_minutes": 480,
  "is_assigned": true,
  "is_invited": false,
  "shifts_to_take": 2,
  "archived_at": null,
  "expenses": [],
  "created_at": "2026-09-07T16:06:11.113221+02:00",
  "site_outline": [
    {
      "lat": 49.8205,
      "lon": 18.2615
    },
    {
      "lat": 49.8205,
      "lon": 18.2636
    },
    {
      "lat": 49.82131,
      "lon": 18.2636
    },
    {
      "lat": 49.82131,
      "lon": 18.2615
    }
  ]
}

Stavové kódy

KódZpráva
200
400invalid gig id
401authentication required
403not permitted
404gig not found
500internal server error
Vyzkoušet

GET /api/gigs/{id}/earnings

Answers "what has this project paid me, and what will it".

API klíč nebo relace.

Its own endpoint rather than a field on the gig, for two reasons. The list screen has no use for it and should not pay for it on every row; and a tool attached or an hour corrected changes this without changing the project, so the app can re-read one without the other.

The two figures come from two different tables, each carrying its own rate snapshot, and neither is ever rebuilt from the membership rate.

V cestě

ParametrCo to je
idId zakázky.

Odpověď

Earnings

Příklad
{
  "earned": [
    {
      "amount": 33600000,
      "currency": "CZK"
    }
  ],
  "upcoming": [
    {
      "amount": 50400000,
      "currency": "CZK"
    }
  ],
  "earned_unrated_minutes": 0,
  "upcoming_unrated_minutes": 360,
  "running": null
}

Stavové kódy

KódZpráva
200
400invalid {thing} id
401authentication required
403not permitted
404gig not found
500internal server error
Vyzkoušet

POST /api/gigs

Makes a project at the caller's company, with the caller as its manager.

API klíč nebo relace.

Managers only.

Tělo požadavku

The JSON body of POST /api/gigs.

There is deliberately no owner_id or org_id here: the owner is the acting manager's own membership and the organization comes from the session. A client that could name either could create work in someone else's company.

PoleTypCo to je
title řetězec
client_id celé číslo, nebo null
latitude číslo, nebo null
longitude číslo, nebo null
geofence_radius_m celé číslo, nebo null
site_outline seznam: Point

Odpověď

Project

Příklad
{
  "id": 2,
  "title": "Roof replacement",
  "owner_id": 1,
  "project_manager": {
    "name": "Tereza Nováková",
    "phone": null,
    "email": "tereza.novakova@example.com"
  },
  "client_id": null,
  "client_name": null,
  "client_contact_name": null,
  "client_contact_phone": null,
  "client_contact_email": null,
  "job_contact": null,
  "latitude": null,
  "longitude": null,
  "geofence_radius_m": null,
  "site_address": null,
  "expected_minutes": null,
  "is_assigned": false,
  "is_invited": true,
  "shifts_to_take": 0,
  "archived_at": null,
  "expenses": [
    {
      "id": 4,
      "gig_id": 2,
      "created_by_membership_id": 1,
      "created_by_name": "Tereza Nováková",
      "description": "Tiles",
      "cost_amount": 1250000,
      "cost_currency": "CZK",
      "created_at": "2026-09-07T12:52:03.941837+02:00"
    }
  ],
  "created_at": "2026-09-07T16:05:07.353539+02:00",
  "site_outline": null
}

Stavové kódy

KódZpráva
201
400invalid JSON body · title is required
401authentication required
403not permitted
500internal server error
Vyzkoušet

POST /api/gigs/{id}/expenses

Books a cost against a project.

API klíč nebo relace.

Workers may call this, not only managers: the app is where somebody standing in a builders' merchant records what they just bought. The service decides who may do what.

V cestě

ParametrCo to je
idId zakázky.

Tělo požadavku

The JSON body of a create or an update.

Money crosses the wire as the raw int64 with its currency, never pre-formatted and never a float. There is no author field: the acting membership books it, and a client that could name the author could book a cost against somebody else.

PoleTypCo to je
description řetězec
cost_amount celé číslo

Peníze: celé číslo se čtyřmi skrytými desetinnými místy, takže 4200000 je 420,00, a vedle něj měna.

cost_currency řetězec

Odpověď

Expense

Příklad
{
  "id": 4,
  "gig_id": 2,
  "created_by_membership_id": 1,
  "created_by_name": "Tereza Nováková",
  "description": "Tiles",
  "cost_amount": 1250000,
  "cost_currency": "CZK",
  "created_at": "2026-09-07T12:52:03.941837+02:00"
}

Stavové kódy

KódZpráva
201
400invalid JSON body · invalid {thing} id
401authentication required
403not permitted
404expense not found · gig not found
500internal server error
Vyzkoušet

PATCH /api/gigs/{id}/expenses/{expenseID}

Corrects a cost already booked.

API klíč nebo relace.

V cestě

ParametrCo to je
idId zakázky.
expenseIDId výdaje.

Tělo požadavku

The JSON body of a create or an update.

Money crosses the wire as the raw int64 with its currency, never pre-formatted and never a float. There is no author field: the acting membership books it, and a client that could name the author could book a cost against somebody else.

PoleTypCo to je
description řetězec
cost_amount celé číslo

Peníze: celé číslo se čtyřmi skrytými desetinnými místy, takže 4200000 je 420,00, a vedle něj měna.

cost_currency řetězec

Odpověď

Expense

Příklad
{
  "id": 4,
  "gig_id": 2,
  "created_by_membership_id": 1,
  "created_by_name": "Tereza Nováková",
  "description": "Tiles",
  "cost_amount": 1250000,
  "cost_currency": "CZK",
  "created_at": "2026-09-07T12:52:03.941837+02:00"
}

Stavové kódy

KódZpráva
200
400invalid JSON body · invalid {thing} id
401authentication required
403not permitted
404expense not found · gig not found
500internal server error
Vyzkoušet

DELETE /api/gigs/{id}/expenses/{expenseID}

Deletes a cost.

API klíč nebo relace.

V cestě

ParametrCo to je
idId zakázky.
expenseIDId výdaje.

Odpověď

Bez těla.

Stavové kódy

KódZpráva
204
400invalid {thing} id
401authentication required
403not permitted
404expense not found · gig not found
500internal server error
Vyzkoušet

Nářadí

Serves a worker's own kit list.

Every route here answers for the ACTING MEMBERSHIP and nobody else. There is no endpoint that lists another person's tools, or everybody's tools on a project, and there is no role that would change that — a PM view of who owns what is precisely what this feature does not have.

GET /api/tool-icons

Returns the fixed set of icons the product ships.

Veřejné: není potřeba klíč ani relace.

It is the one definition both clients read, so a picker cannot offer a name the server would refuse. Deliberately not behind the session: it is a constant, discloses nothing, and an app that could not draw its own picker until sign-in would be worse for no gain.

Odpověď

seznam: Tool icon

Příklad
[
  {
    "name": "hammer",
    "label": "Hammer"
  },
  {
    "name": "wrench",
    "label": "Spanner"
  },
  {
    "name": "screwdriver",
    "label": "Screwdriver"
  },
  {
    "name": "pliers",
    "label": "Pliers"
  },
  {
    "name": "saw",
    "label": "Saw"
  },
  {
    "name": "trowel",
    "label": "Trowel"
  },
  {
    "name": "shovel",
    "label": "Shovel"
  },
  {
    "name": "drill",
    "label": "Drill"
  },
  {
    "name": "grinder",
    "label": "Angle grinder"
  },
  {
    "name": "breaker",
    "label": "Breaker"
  },
  {
    "name": "mixer",
    "label": "Mixer"
  },
  {
    "name": "measure",
    "label": "Tape measure"
  },
  {
    "name": "level",
    "label": "Spirit level"
  },
  {
    "name": "ladder",
    "label": "Ladder"
  },
  {
    "name": "paint",
    "label": "Paint roller"
  },
  {
    "name": "cable",
    "label": "Power lead"
  },
  {
    "name": "light",
    "label": "Work light"
  },
  {
    "name": "toolbox",
    "label": "Toolbox"
  },
  {
    "name": "safety",
    "label": "Safety gear"
  },
  {
    "name": "other",
    "label": "Other"
  }
]

Stavové kódy

KódZpráva
200
Vyzkoušet

GET /api/tools

The caller's own kit list at this company, with the ids of the projects each tool is attached to.

API klíč nebo relace.

Odpověď

seznam: Tool

Příklad
[
  {
    "id": 12,
    "name": "SDS drill",
    "icon": "drill",
    "quantity": null,
    "created_at": "2026-09-08T14:22:41.117204+02:00",
    "gig_ids": [
      3,
      7
    ]
  },
  {
    "id": 11,
    "name": "Clamps",
    "icon": "other",
    "quantity": 6,
    "created_at": "2026-09-08T14:21:02.884113+02:00",
    "gig_ids": []
  }
]

Stavové kódy

KódZpráva
200
400
401authentication required
403not permitted
404tool not found
500internal server error
Vyzkoušet

POST /api/tools

Adds a tool to the caller's kit list.

API klíč nebo relace.

The icon is a name from GET /api/tool-icons; the quantity is optional.

Tělo požadavku

The JSON body of a create or an update.

No membership or org field: both come from the session. A client that could name either could write somebody else's kit list.

PoleTypCo to je
name řetězec
icon řetězec
quantity celé číslo, nebo null

Odpověď

Tool

Příklad
{
  "id": 12,
  "name": "SDS drill",
  "icon": "drill",
  "quantity": null,
  "created_at": "2026-09-08T14:22:41.117204+02:00",
  "gig_ids": [
    3,
    7
  ]
}

Stavové kódy

KódZpráva
201
400invalid JSON body
401authentication required
403not permitted
404tool not found
500internal server error
Vyzkoušet

PATCH /api/tools/{id}

Renames a tool, or changes its icon or quantity.

API klíč nebo relace.

V cestě

ParametrCo to je
idId nářadí.

Tělo požadavku

The JSON body of a create or an update.

No membership or org field: both come from the session. A client that could name either could write somebody else's kit list.

PoleTypCo to je
name řetězec
icon řetězec
quantity celé číslo, nebo null

Odpověď

Tool

Příklad
{
  "id": 11,
  "name": "Clamps",
  "icon": "other",
  "quantity": 6,
  "created_at": "2026-09-08T14:21:02.884113+02:00",
  "gig_ids": []
}

Stavové kódy

KódZpráva
200
400invalid JSON body · invalid {thing} id
401authentication required
403not permitted
404tool not found
500internal server error
Vyzkoušet

DELETE /api/tools/{id}

Deletes a tool from the kit list, and detaches it from every project it was taken to.

API klíč nebo relace.

V cestě

ParametrCo to je
idId nářadí.

Odpověď

Bez těla.

Stavové kódy

KódZpráva
204
400invalid {thing} id
401authentication required
403not permitted
404tool not found
500internal server error
Vyzkoušet

GET /api/gigs/{id}/tools

Returns the caller's own tools attached to one project — what they have to load into the van for this job.

API klíč nebo relace.

V cestě

ParametrCo to je
idId zakázky.

Odpověď

seznam: Tool

Příklad
[
  {
    "id": 12,
    "name": "SDS drill",
    "icon": "drill",
    "quantity": null,
    "created_at": "2026-09-08T14:22:41.117204+02:00",
    "gig_ids": [
      3,
      7
    ]
  },
  {
    "id": 11,
    "name": "Clamps",
    "icon": "other",
    "quantity": 6,
    "created_at": "2026-09-08T14:21:02.884113+02:00",
    "gig_ids": []
  }
]

Stavové kódy

KódZpráva
200
400invalid {thing} id
401authentication required
403not permitted
404tool not found
500internal server error
Vyzkoušet

POST /api/gigs/{id}/tools

Says "I am taking this to that job".

API klíč nebo relace.

Idempotent: attaching a tool that is already attached answers 204 rather than a conflict. Two taps on a building site is a bad radio, not a disagreement, and the second one meant the same as the first.

V cestě

ParametrCo to je
idId zakázky.

Tělo požadavku

Names the tool being taken to a project.

PoleTypCo to je
tool_id celé číslo

Odpověď

Bez těla.

Stavové kódy

KódZpráva
204
400invalid JSON body · invalid {thing} id
401authentication required
403not permitted
404tool not found
500internal server error
Vyzkoušet

DELETE /api/gigs/{id}/tools/{toolID}

Removes the link and NOT the tool.

API klíč nebo relace.

Coming off one job must not cost the worker the entry.

V cestě

ParametrCo to je
idId zakázky.
toolIDId nářadí.

Odpověď

Bez těla.

Stavové kódy

KódZpráva
204
400invalid {thing} id
401authentication required
403not permitted
404tool not found
500internal server error
Vyzkoušet

Plánování kalendáře zakázky

A project's calendar, for its managers: which days it runs, the shifts on each, and laying shifts on days or taking them off again. Removing work people have accepted asks first: without confirm nothing changes and the answer says how many people would be told. A worker sees none of this; the project's days reach a worker as their shifts.

GET /api/gigs/{id}/calendar

A project's days in a range, each with its shifts, roles and staffing counts.

API klíč nebo relace.

from and to are calendar days, "2026-10-27", both inclusive; without them the four weeks from today on site. A range may be up to a year. A day is listed only if the project runs on it, so the gaps in a project that pauses are simply absent days. Who is on each shift is the shift's own endpoint. Managers only; a worker's week is the dashboard.

V cestě

ParametrCo to je
idId zakázky.

Parametry dotazu

  • from
  • to

Odpověď

seznam: Calendar day

Příklad
[
  {
    "day": "2026-09-10",
    "day_id": 1,
    "shifts": [
      {
        "id": 1,
        "gig_id": 1,
        "day_id": 1,
        "starts_at": "2026-09-10T05:00:00Z",
        "ends_at": "2026-09-10T13:00:00Z",
        "required_workers": 3,
        "role_label": "1× crane op, 2× labourer",
        "created_at": "2026-09-07T09:00:00Z",
        "accepted": 1,
        "pending": 1,
        "short": 2,
        "is_open": false,
        "open_auto_accept": false,
        "offered_rate_multiplier": null,
        "roles": [
          {
            "id": 1,
            "label": "crane op",
            "headcount": 1,
            "rate_amount": 5200000,
            "rate_currency": "CZK",
            "accepted": 1,
            "pending": 0
          },
          {
            "id": 2,
            "label": "labourer",
            "headcount": 2,
            "rate_amount": null,
            "rate_currency": null,
            "accepted": 0,
            "pending": 1
          }
        ]
      }
    ]
  },
  {
    "day": "2026-09-11",
    "day_id": 2,
    "shifts": []
  }
]

Stavové kódy

KódZpráva
200
400from must be a calendar day, YYYY-MM-DD · invalid {thing} id · the range must run forwards and be at most a year · to must be a calendar day, YYYY-MM-DD
401authentication required
403not permitted · that application is the manager's to approve
404assignment not found · certificate not found · certification not found · client not found · gig not found · shift not found
409that invitation is no longer open · that is an invitation, and only the worker can accept it · that shift collides with work you have accepted · that shift is already full
500internal server error
Vyzkoušet

POST /api/gigs/{id}/days

Puts days on a project's calendar.

API klíč nebo relace.

Days already on it are left as they are, so sending a range twice is harmless. Laying a shift on a day schedules the day too, so this is only needed for a day that runs with no shift planned yet. Up to a year of days in one request. The answer is the project's whole calendar. Managers only.

V cestě

ParametrCo to je
idId zakázky.

Tělo požadavku

Names calendar days, "2026-10-27".

PoleTypCo to je
days seznam: řetězec
confirm boolean

confirm is read by the removal only: without it nothing is removed and the answer says what would be.

Odpověď

seznam: Scheduled day

Stavové kódy

KódZpráva
200
400invalid JSON body · invalid {thing} id · name at least one day
401authentication required
403not permitted · that application is the manager's to approve
404assignment not found · certificate not found · certification not found · client not found · gig not found · shift not found
409that invitation is no longer open · that is an invitation, and only the worker can accept it · that shift collides with work you have accepted · that shift is already full
500internal server error
Vyzkoušet

POST /api/gigs/{id}/days/remove

Takes days off a project's calendar, with their shifts.

API klíč nebo relace.

Anybody with a live place on them — accepted, or invited and not yet answered — is taken off and told once, however many of their shifts went; anybody who had accepted is emailed as well. So it asks first: without confirm nothing changes and the answer says how many people that is. A shift that has started is a record and its day cannot be removed. Managers only.

V cestě

ParametrCo to je
idId zakázky.

Tělo požadavku

Names calendar days, "2026-10-27".

PoleTypCo to je
days seznam: řetězec
confirm boolean

confirm is read by the removal only: without it nothing is removed and the answer says what would be.

Odpověď

Removed days

Stavové kódy

KódZpráva
200
400invalid JSON body · invalid {thing} id · name at least one day
401authentication required
403not permitted · that application is the manager's to approve
404assignment not found · certificate not found · certification not found · client not found · gig not found · shift not found
409that invitation is no longer open · that is an invitation, and only the worker can accept it · that shift collides with work you have accepted · that shift is already full
500internal server error
Vyzkoušet

POST /api/gigs/{id}/shifts

Lays one shift on each of the days named, with its roles.

API klíč nebo relace.

The same clock times on each day, worked out day by day on site, so a week that crosses a change of the clocks is right on every day. The answer is each shift made, with its roles' ids, which an invitation names. Managers only; an archived project takes no new shifts.

V cestě

ParametrCo to je
idId zakázky.

Tělo požadavku

One shift laid on each of several days.

PoleTypCo to je
days seznam: řetězec

days are calendar days, "2026-10-27". Each gets a shift; a day not yet on the calendar is scheduled by it.

starts_at řetězec

starts_at and ends_at are clock times on site, "07:00" and "15:30". A shift that ends at or before it starts runs into the next day. The clock is kept on site whichever side of a change of the clocks a day falls.

ends_at řetězec
roles seznam: Role to add

roles are the shift's roles; the headcount is their sum. One role with no label is a plain shift. Leave empty and send headcount for a plain shift instead.

headcount celé číslo

headcount is the places on a plain shift, read only when roles is empty.

open boolean

open advertises every shift to the company at once; open_auto_accept confirms a taker outright rather than as an applicant.

open_auto_accept boolean
offered_rate_multiplier celé číslo, nebo null

offered_rate_multiplier raises each taker's usual rate on an open shift, with four implied decimals: 15000 is 1.5×. Null offers the rates as they stand.

Násobek se čtyřmi skrytými desetinnými místy: 15000 je 1,5×.

Odpověď

Added shifts

Příklad
{
  "id": 1,
  "gig_id": 1,
  "day_id": 1,
  "starts_at": "2026-09-10T05:00:00Z",
  "ends_at": "2026-09-10T13:00:00Z",
  "required_workers": 3,
  "role_label": "1× crane op, 2× labourer",
  "created_at": "2026-09-07T09:00:00Z",
  "accepted": 1,
  "pending": 1,
  "short": 2,
  "is_open": false,
  "open_auto_accept": false,
  "offered_rate_multiplier": null,
  "roles": [
    {
      "id": 1,
      "label": "crane op",
      "headcount": 1,
      "rate_amount": 5200000,
      "rate_currency": "CZK",
      "accepted": 1,
      "pending": 0
    },
    {
      "id": 2,
      "label": "labourer",
      "headcount": 2,
      "rate_amount": null,
      "rate_currency": null,
      "accepted": 0,
      "pending": 1
    }
  ]
}

Stavové kódy

KódZpráva
201
400ends_at must be a time of day, as 15:00 · invalid JSON body · invalid {thing} id · name at least one day · starts_at must be a time of day, as 07:00, on a day written YYYY-MM-DD
401authentication required
403not permitted · that application is the manager's to approve
404assignment not found · certificate not found · certification not found · client not found · gig not found · shift not found
409that invitation is no longer open · that is an invitation, and only the worker can accept it · that shift collides with work you have accepted · that shift is already full
500internal server error
Vyzkoušet

POST /api/gigs/{id}/shifts/move

Moves shifts to new dates, by a number of whole days.

API klíč nebo relace.

Clock times are kept on site. Everyone with an accepted place is asked again: their place goes back to pending with the new date as its deadline, they are told once, and anyone who had accepted is emailed. A shift that has started, or has an SOS running, stays where it is and is counted as skipped; a move that would land a shift in the past is refused whole. It asks first: without confirm nothing changes and the answer has the counts. Managers only.

V cestě

ParametrCo to je
idId zakázky.

Tělo požadavku

Moves shifts by whole days.

PoleTypCo to je
timeslot_ids seznam: celé číslo

timeslot_ids are the shifts to move, all of this project.

days celé číslo

days is the offset in whole days, forwards or back; never zero.

confirm boolean

confirm says to go ahead. Without it nothing changes and the answer says what would.

Odpověď

Moved shifts

Stavové kódy

KódZpráva
200
400invalid JSON body · invalid {thing} id
401authentication required
403not permitted · that application is the manager's to approve
404assignment not found · certificate not found · certification not found · client not found · gig not found · shift not found
409that invitation is no longer open · that is an invitation, and only the worker can accept it · that shift collides with work you have accepted · that shift is already full
500internal server error
Vyzkoušet

POST /api/timeslots/{id}/remove

Takes a shift off its day.

API klíč nebo relace.

Everybody with a live place on it is taken off and told, as removing a day tells them. It asks first: without confirm nothing changes and the answer counts the accepted and pending places. Managers only.

V cestě

ParametrCo to je
idId směny.

Tělo požadavku

A removal's consent.

PoleTypCo to je
confirm boolean

confirm says to go ahead. Without it nothing changes and the answer says what would.

Odpověď

Removed shift

Stavové kódy

KódZpráva
200
400invalid JSON body · invalid {thing} id
401authentication required
403not permitted · that application is the manager's to approve
404assignment not found · certificate not found · certification not found · client not found · gig not found · shift not found
409that invitation is no longer open · that is an invitation, and only the worker can accept it · that shift collides with work you have accepted · that shift is already full
500internal server error
Vyzkoušet

Obsazování zakázky

Staffing as a manager does it: who is on a shift, inviting people to one shift or to many, approving an applicant, taking somebody off a shift or off the whole project, opening a shift to the company, raising an SOS, and the shifts short of people. An invitation is a question — nobody counts as staffed until they accept — and every removal tells the person once. The worker's side, answering and taking shifts, is elsewhere.

GET /api/timeslots/{id}

One shift, with its roles and everyone on it.

API klíč nebo relace.

Each person's status is as it stands now: an unanswered invitation past the shift's start reads expired. Another company's shift is not found. Managers only.

V cestě

ParametrCo to je
idId směny.

Odpověď

Shift with its people

Příklad
{
  "id": 1,
  "gig_id": 1,
  "day_id": 1,
  "starts_at": "2026-09-10T05:00:00Z",
  "ends_at": "2026-09-10T13:00:00Z",
  "required_workers": 3,
  "role_label": "1× crane op, 2× labourer",
  "created_at": "2026-09-07T09:00:00Z",
  "accepted": 1,
  "pending": 1,
  "short": 2,
  "is_open": true,
  "open_auto_accept": false,
  "offered_rate_multiplier": 15000,
  "roles": [
    {
      "id": 1,
      "label": "crane op",
      "headcount": 1,
      "rate_amount": 5200000,
      "rate_currency": "CZK",
      "accepted": 1,
      "pending": 0
    },
    {
      "id": 2,
      "label": "labourer",
      "headcount": 2,
      "rate_amount": null,
      "rate_currency": null,
      "accepted": 0,
      "pending": 1
    }
  ],
  "people": [
    {
      "id": 1,
      "timeslot_id": 1,
      "membership_id": 2,
      "origin": "staffed",
      "status": "accepted",
      "rate_amount": 5200000,
      "rate_currency": "CZK",
      "role_id": 1,
      "role_label": "crane op",
      "invited_at": "2026-09-07T09:00:00Z",
      "responded_at": "2026-09-07T09:05:00Z",
      "expires_at": "2026-09-10T05:00:00Z",
      "created_at": "2026-09-07T09:00:00Z",
      "takes_from": null,
      "takes_until": null,
      "worker_name": "Jana Horáková"
    },
    {
      "id": 2,
      "timeslot_id": 1,
      "membership_id": 3,
      "origin": "sos",
      "status": "pending",
      "rate_amount": null,
      "rate_currency": null,
      "role_id": 2,
      "role_label": "labourer",
      "invited_at": "2026-09-08T14:00:00Z",
      "responded_at": null,
      "expires_at": "2026-09-10T13:00:00Z",
      "created_at": "2026-09-08T14:00:00Z",
      "takes_from": null,
      "takes_until": null,
      "worker_name": "Petr Dvořák"
    }
  ]
}

Stavové kódy

KódZpráva
200
400invalid {thing} id
401authentication required
403not permitted · that application is the manager's to approve
404assignment not found · certificate not found · certification not found · client not found · gig not found · shift not found
409that invitation is no longer open · that is an invitation, and only the worker can accept it · that shift collides with work you have accepted · that shift is already full
500internal server error
Vyzkoušet

POST /api/timeslots/{id}/invitations

Asks one person to one shift.

API klíč nebo relace.

The answer is the invitation, pending: it fills nothing until they accept, and it lapses at the shift's start if they never do. The rate on it is settled now — the role's, else the project's pay rate, else their own — and does not move afterwards. A person already live on the shift, a shift that has started, and somebody who does not work shifts here are each refused. The person is told once. Managers only.

V cestě

ParametrCo to je
idId směny.

Tělo požadavku

Names who to invite to a shift, and for which role.

PoleTypCo to je
membership_id celé číslo

membership_id is the person, as the roster lists them.

role_id celé číslo

role_id is the role on the shift they are invited for. It may be left out for a shift with one role.

Odpověď

Assignment

Příklad
{
  "id": 2,
  "timeslot_id": 1,
  "membership_id": 3,
  "origin": "sos",
  "status": "pending",
  "rate_amount": null,
  "rate_currency": null,
  "role_id": 2,
  "role_label": "labourer",
  "invited_at": "2026-09-08T14:00:00Z",
  "responded_at": null,
  "expires_at": "2026-09-10T13:00:00Z",
  "created_at": "2026-09-08T14:00:00Z",
  "takes_from": null,
  "takes_until": null,
  "worker_name": "Petr Dvořák"
}

Stavové kódy

KódZpráva
201
400invalid JSON body · invalid {thing} id · membership_id is required
401authentication required
403not permitted · that application is the manager's to approve
404assignment not found · certificate not found · certification not found · client not found · gig not found · shift not found
409that invitation is no longer open · that is an invitation, and only the worker can accept it · that shift collides with work you have accepted · that shift is already full
500internal server error
Vyzkoušet

POST /api/gigs/{id}/invitations/batch

Asks several people to several shifts of one project at once.

API klíč nebo relace.

Each pair becomes an ordinary invitation with its own rate and its own deadline; nothing records that they were made together. Somebody already live on a shift is skipped, not refused. More people than a shift has places, and a shift overlapping other work of theirs at this company, are allowed and said. Another project's shift, somebody who does not work shifts here, or a shift that has started refuses the whole batch and says which. Each person is told once. Send preview to see all of that without sending anything. Managers only.

V cestě

ParametrCo to je
idId zakázky.

Tělo požadavku

Asks several people to several shifts at once.

PoleTypCo to je
membership_ids seznam: celé číslo

membership_ids are the people, from the roster.

timeslot_ids seznam: celé číslo

timeslot_ids are the shifts, all of this project.

role řetězec, nebo null

role names the role, by label, on a shift that has several; a shift with one role takes the batch as that role whatever the name. Null where every shift has one role.

preview boolean

preview says to work out what the batch would do and send nothing.

Odpověď

Invitation batch

Příklad
{
  "preview": false,
  "people": 2,
  "shifts": 2,
  "invitations": 3,
  "skipped": [
    {
      "membership_id": 2,
      "worker_name": "Jana Horáková",
      "shift": {
        "timeslot_id": 1,
        "starts_at": "2026-09-10T05:00:00Z",
        "ends_at": "2026-09-10T13:00:00Z"
      }
    }
  ],
  "over_filled": [
    {
      "shift": {
        "timeslot_id": 2,
        "starts_at": "2026-09-11T05:00:00Z",
        "ends_at": "2026-09-11T13:00:00Z"
      },
      "invited": 2,
      "places": 1
    }
  ],
  "clashes": [
    {
      "membership_id": 3,
      "worker_name": "Petr Dvořák",
      "shift": {
        "timeslot_id": 2,
        "starts_at": "2026-09-11T05:00:00Z",
        "ends_at": "2026-09-11T13:00:00Z"
      },
      "with": {
        "timeslot_id": 7,
        "starts_at": "2026-09-11T10:00:00Z",
        "ends_at": "2026-09-11T14:00:00Z"
      },
      "in_batch": false
    }
  ],
  "sent": [
    {
      "id": 3,
      "timeslot_id": 2,
      "membership_id": 2,
      "origin": "staffed",
      "status": "pending",
      "rate_amount": 4200000,
      "rate_currency": "CZK",
      "role_id": 3,
      "role_label": null,
      "invited_at": "2026-09-08T14:00:00Z",
      "responded_at": null,
      "expires_at": "2026-09-11T05:00:00Z",
      "created_at": "2026-09-08T14:00:00Z",
      "takes_from": null,
      "takes_until": null,
      "worker_name": "Jana Horáková"
    }
  ]
}

Stavové kódy

KódZpráva
200
400invalid JSON body · invalid {thing} id
401authentication required
403not permitted · that application is the manager's to approve
404assignment not found · certificate not found · certification not found · client not found · gig not found · shift not found
409that invitation is no longer open · that is an invitation, and only the worker can accept it · that shift collides with work you have accepted · that shift is already full
500internal server error
Vyzkoušet

POST /api/assignments/{id}/approve

Confirms an applicant on a shift the manager reviews takers for: an open shift or an SOS.

API klíč nebo relace.

The answer is the assignment, accepted, at the rate it was offered. A full role, an application that has lapsed, an invitation (which only the worker can accept), and an applicant who has since accepted colliding work are each refused. The person is told. Managers only.

V cestě

ParametrCo to je
idId přiřazení: vašeho místa na směně.

Odpověď

Assignment

Příklad
{
  "id": 1,
  "timeslot_id": 1,
  "membership_id": 2,
  "origin": "staffed",
  "status": "accepted",
  "rate_amount": 5200000,
  "rate_currency": "CZK",
  "role_id": 1,
  "role_label": "crane op",
  "invited_at": "2026-09-07T09:00:00Z",
  "responded_at": "2026-09-07T09:05:00Z",
  "expires_at": "2026-09-10T05:00:00Z",
  "created_at": "2026-09-07T09:00:00Z",
  "takes_from": null,
  "takes_until": null,
  "worker_name": "Jana Horáková"
}

Stavové kódy

KódZpráva
200
400invalid {thing} id
401authentication required
403not permitted · that application is the manager's to approve
404assignment not found · certificate not found · certification not found · client not found · gig not found · shift not found
409that invitation is no longer open · that is an invitation, and only the worker can accept it · that shift collides with work you have accepted · that shift is already full
500internal server error
Vyzkoušet

POST /api/assignments/{id}/cancel

Takes one person off one shift.

API klíč nebo relace.

Their place is cancelled and reopens, and they are told once; if they had accepted they are emailed too, unless they turned that off. confirm is required: without it nothing changes and this answers 400, because the act is what tells a person not to come. A place already settled — declined, lapsed, withdrawn, cancelled — is refused. To take somebody off every upcoming shift of the project at once, use the project's people endpoint. Managers only.

V cestě

ParametrCo to je
idId přiřazení: vašeho místa na směně.

Tělo požadavku

A removal's consent.

PoleTypCo to je
confirm boolean

confirm says to go ahead. Without it nothing changes and the answer says what would.

Odpověď

Assignment

Stavové kódy

KódZpráva
200
400invalid JSON body · invalid {thing} id · send confirm: this cancels their place and tells them
401authentication required
403not permitted · that application is the manager's to approve
404assignment not found · certificate not found · certification not found · client not found · gig not found · shift not found
409that invitation is no longer open · that is an invitation, and only the worker can accept it · that shift collides with work you have accepted · that shift is already full
500internal server error
Vyzkoušet

GET /api/gigs/{id}/people

Lists everyone with a live place on a project's shifts still to come: accepted, or asked and not yet answered, each once.

API klíč nebo relace.

A shift that has started is a record and is not counted; somebody whose only shifts are over is on the project's hours, not here. Managers only.

V cestě

ParametrCo to je
idId zakázky.

Odpověď

seznam: Person on a project

Stavové kódy

KódZpráva
200
400invalid {thing} id
401authentication required
403not permitted · that application is the manager's to approve
404assignment not found · certificate not found · certification not found · client not found · gig not found · shift not found
409that invitation is no longer open · that is an invitation, and only the worker can accept it · that shift collides with work you have accepted · that shift is already full
500internal server error
Vyzkoušet

POST /api/gigs/{id}/people/{membershipID}/remove

Takes one person off every upcoming shift of a project at once.

API klíč nebo relace.

Every live place of theirs on a shift of the project still to come is cancelled in one go, and they are told once: one push, and one email listing the accepted shifts. Their places on other projects, and on a shift of this project that has started, are not touched. It asks first: without confirm nothing changes and the answer counts the places. Managers only.

V cestě

ParametrCo to je
idId zakázky.
membershipIDId členství člověka, jak je uvádí seznam lidí.

Tělo požadavku

A removal's consent.

PoleTypCo to je
confirm boolean

confirm says to go ahead. Without it nothing changes and the answer says what would.

Odpověď

Taken off a project

Stavové kódy

KódZpráva
200
400invalid JSON body · invalid {thing} id
401authentication required
403not permitted · that application is the manager's to approve
404assignment not found · certificate not found · certification not found · client not found · gig not found · shift not found
409that invitation is no longer open · that is an invitation, and only the worker can accept it · that shift collides with work you have accepted · that shift is already full
500internal server error
Vyzkoušet

POST /api/timeslots/{id}/open

Advertises a shift to the company: any worker there may take a place on it without being invited.

API klíč nebo relace.

A shift is open only because a manager said so; it is never open merely for being short. The manager chooses whether a taker is confirmed outright or reviewed, and may raise the rate. The answer is the shift as it now stands. Managers only.

V cestě

ParametrCo to je
idId směny.

Tělo požadavku

The terms a shift is opened on.

PoleTypCo to je
auto_accept boolean

auto_accept confirms a taker outright, up to each role's headcount. Without it a taker lands as an applicant for the manager to approve.

offered_rate_multiplier celé číslo, nebo null

offered_rate_multiplier raises each taker's usual rate, with four implied decimals: 15000 is 1.5×. Null offers each role's rate as it stands.

Násobek se čtyřmi skrytými desetinnými místy: 15000 je 1,5×.

Odpověď

Shift as a manager sees it

Příklad
{
  "id": 1,
  "gig_id": 1,
  "day_id": 1,
  "starts_at": "2026-09-10T05:00:00Z",
  "ends_at": "2026-09-10T13:00:00Z",
  "required_workers": 3,
  "role_label": "1× crane op, 2× labourer",
  "created_at": "2026-09-07T09:00:00Z",
  "accepted": 1,
  "pending": 1,
  "short": 2,
  "is_open": true,
  "open_auto_accept": false,
  "offered_rate_multiplier": 15000,
  "roles": [
    {
      "id": 1,
      "label": "crane op",
      "headcount": 1,
      "rate_amount": 5200000,
      "rate_currency": "CZK",
      "accepted": 1,
      "pending": 0
    },
    {
      "id": 2,
      "label": "labourer",
      "headcount": 2,
      "rate_amount": null,
      "rate_currency": null,
      "accepted": 0,
      "pending": 1
    }
  ]
}

Stavové kódy

KódZpráva
200
400a multiplier must be more than nothing · invalid JSON body · invalid {thing} id
401authentication required
403not permitted · that application is the manager's to approve
404assignment not found · certificate not found · certification not found · client not found · gig not found · shift not found
409that invitation is no longer open · that is an invitation, and only the worker can accept it · that shift collides with work you have accepted · that shift is already full
500internal server error
Vyzkoušet

POST /api/timeslots/{id}/close

Stops advertising a shift.

API klíč nebo relace.

The people already on it stay on it. Managers only.

V cestě

ParametrCo to je
idId směny.

Odpověď

Shift as a manager sees it

Příklad
{
  "id": 1,
  "gig_id": 1,
  "day_id": 1,
  "starts_at": "2026-09-10T05:00:00Z",
  "ends_at": "2026-09-10T13:00:00Z",
  "required_workers": 3,
  "role_label": "1× crane op, 2× labourer",
  "created_at": "2026-09-07T09:00:00Z",
  "accepted": 1,
  "pending": 1,
  "short": 2,
  "is_open": false,
  "open_auto_accept": false,
  "offered_rate_multiplier": null,
  "roles": [
    {
      "id": 1,
      "label": "crane op",
      "headcount": 1,
      "rate_amount": 5200000,
      "rate_currency": "CZK",
      "accepted": 1,
      "pending": 0
    },
    {
      "id": 2,
      "label": "labourer",
      "headcount": 2,
      "rate_amount": null,
      "rate_currency": null,
      "accepted": 0,
      "pending": 1
    }
  ]
}

Stavové kódy

KódZpráva
200
400invalid {thing} id
401authentication required
403not permitted · that application is the manager's to approve
404assignment not found · certificate not found · certification not found · client not found · gig not found · shift not found
409that invitation is no longer open · that is an invitation, and only the worker can accept it · that shift collides with work you have accepted · that shift is already full
500internal server error
Vyzkoušet

POST /api/timeslots/{id}/sos

Raises an emergency on one short shift.

API klíč nebo relace.

An SOS is an open shift with the rate raised and a notification sent: every worker at the company who opted into emergency cover is told, and each may take a place at the raised rate until the shift ends. It is refused on a shift that is not short, that is over, or that has an SOS running; somebody who called in sick is taken off first, which is what makes the shift short. Managers only.

V cestě

ParametrCo to je
idId směny.

Tělo požadavku

The terms an SOS is raised on.

PoleTypCo to je
offered_rate_multiplier celé číslo, nebo null

offered_rate_multiplier raises each taker's usual rate, with four implied decimals. Null is the default, 15000: half as much again. The project's maximum hourly rate caps what comes out.

Násobek se čtyřmi skrytými desetinnými místy: 15000 je 1,5×.

auto_accept boolean

auto_accept confirms a responder outright, up to the role's headcount; without it responders are applicants for the manager to approve.

Odpověď

SOS raised

Příklad
{
  "id": 1,
  "timeslot_id": 1,
  "offered_rate_multiplier": 15000,
  "opened_at": "2026-09-09T16:00:00Z",
  "told": 0
}

Stavové kódy

KódZpráva
201
400a multiplier must be more than nothing · invalid JSON body · invalid {thing} id
401authentication required
403not permitted · that application is the manager's to approve
404assignment not found · certificate not found · certification not found · client not found · gig not found · shift not found
409that invitation is no longer open · that is an invitation, and only the worker can accept it · that shift collides with work you have accepted · that shift is already full
500internal server error
Vyzkoušet

POST /api/gigs/{id}/sos

Raises one ordinary SOS on each of several short shifts of a project, in one go, and tells each person once.

API klíč nebo relace.

Name the shifts, or none for every short shift of the project that is not over, read now. A shift that filled, ended or has an SOS already is skipped and counted; a shift of another project refuses the lot. Managers only.

V cestě

ParametrCo to je
idId zakázky.

Tělo požadavku

Raises an SOS over a project's short shifts.

PoleTypCo to je
offered_rate_multiplier celé číslo, nebo null

offered_rate_multiplier raises each taker's usual rate, with four implied decimals. Null is the default, 15000: half as much again. The project's maximum hourly rate caps what comes out.

Násobek se čtyřmi skrytými desetinnými místy: 15000 je 1,5×.

auto_accept boolean

auto_accept confirms a responder outright, up to the role's headcount; without it responders are applicants for the manager to approve.

timeslot_ids seznam: celé číslo

timeslot_ids are the shifts to cover, all of this project. Empty means every short shift of the project that is not over.

Odpověď

SOS over a project

Příklad
{
  "raised": [
    {
      "id": 1,
      "timeslot_id": 1,
      "offered_rate_multiplier": 15000,
      "opened_at": "2026-09-09T16:00:00Z",
      "told": 0
    }
  ],
  "already_raised": 0,
  "filled": 1,
  "over": 0,
  "told": 4
}

Stavové kódy

KódZpráva
201
400a multiplier must be more than nothing · invalid JSON body · invalid {thing} id
401authentication required
403not permitted · that application is the manager's to approve
404assignment not found · certificate not found · certification not found · client not found · gig not found · shift not found
409that invitation is no longer open · that is an invitation, and only the worker can accept it · that shift collides with work you have accepted · that shift is already full
500internal server error
Vyzkoušet

GET /api/staffing/short

Lists the company's upcoming shifts that need attention: short of accepted people, or carrying invitations nobody has answered.

API klíč nebo relace.

days is how far ahead to look, 7 unless given, up to 92. Earliest first, across every live project. A shift whose places are all covered by unanswered invitations is listed: an invitation staffs nothing. Managers only.

all=1 lists them at every company the caller manages, earliest first within each, with company on each row naming the entry: send its entry as X-Werzeick-Company to act on the shift. A caller acting as a worker may ask too, and gets the companies they manage. It cannot be combined with X-Werzeick-Company.

Parametry dotazu

  • all
  • days

Odpověď

seznam: Shift needing attention

Příklad
[
  {
    "id": 1,
    "gig_id": 1,
    "day_id": 1,
    "starts_at": "2026-09-10T05:00:00Z",
    "ends_at": "2026-09-10T13:00:00Z",
    "required_workers": 3,
    "role_label": "1× crane op, 2× labourer",
    "created_at": "2026-09-07T09:00:00Z",
    "accepted": 1,
    "pending": 1,
    "gig_title": "Warehouse roof",
    "short": 2,
    "sos_open": true,
    "roles": [
      {
        "id": 1,
        "label": "crane op",
        "headcount": 1,
        "rate_amount": 5200000,
        "rate_currency": "CZK",
        "accepted": 1,
        "pending": 0
      },
      {
        "id": 2,
        "label": "labourer",
        "headcount": 2,
        "rate_amount": null,
        "rate_currency": null,
        "accepted": 0,
        "pending": 1
      }
    ]
  }
]

Stavové kódy

KódZpráva
200
400all=1 reads every company: leave out X-Werzeick-Company · days must be a whole number from 1 to 92
401authentication required
403not permitted · that application is the manager's to approve
404assignment not found · certificate not found · certification not found · client not found · gig not found · shift not found
409that invitation is no longer open · that is an invitation, and only the worker can accept it · that shift collides with work you have accepted · that shift is already full
500internal server error
Vyzkoušet

Lidé ve firmě

The company's roster, for its managers: everyone with a membership at the company, what each may do here (manage projects, work shifts, or both), the default rate for anyone who works shifts, and what the company has noted each as certified for. An invitation to a shift names a person by the id listed here. Inviting somebody new to the company is the invitations endpoint.

GET /api/people

Lists everyone at the company, by name.

API klíč nebo relace.

rate_amount is each person's own default rate here, the fallback for a project with no pay rate of its own and a role with none; null is "no hourly rate". is_disabled marks somebody a manager has switched off, who cannot be invited. certifications is what the company has noted the person as certified for; such people are listed first in the web client's staffing picker, and nothing requires one. Somebody whose account was deleted is not listed. Managers only.

q narrows the list to the people a search finds, as the web client's person pickers do: every word of it has to be the start of a word of the person's name, or of the name, another common name or the scope of something they are certified for, with no case or accents needed. ?q=dvo finds Dvořák, ?q=vzv the forklift drivers, ?q=novák jeřáb a Novák noted for a crane, ?q=jeřáb 10 t a crane operator whose note's scope says 10 t. Without it, everybody.

Parametry dotazu

  • q

Odpověď

seznam: Person response

Příklad
[
  {
    "id": 1,
    "is_manager": true,
    "is_worker": false,
    "rate_amount": null,
    "rate_currency": null,
    "emergency_responses_enabled": false,
    "cancellation_emails_enabled": true,
    "is_disabled": false,
    "created_at": "2026-09-01T08:00:00Z",
    "org_name": "Alpha Stavby",
    "first_name": "Tomáš",
    "last_name": "Novák",
    "email": "tomas@alpha.test",
    "certifications": []
  },
  {
    "id": 2,
    "is_manager": false,
    "is_worker": true,
    "rate_amount": 4200000,
    "rate_currency": "CZK",
    "emergency_responses_enabled": true,
    "cancellation_emails_enabled": true,
    "is_disabled": false,
    "created_at": "2026-09-01T08:05:00Z",
    "org_name": "Alpha Stavby",
    "first_name": "Jana",
    "last_name": "Horáková",
    "email": "jana@alpha.test",
    "certifications": [
      {
        "id": 1,
        "membership_id": 2,
        "kind": "lift_crane_overhead",
        "label": null,
        "scope": "bridge cranes to 10 t",
        "expires_on": "2027-06-30",
        "granted_by_membership_id": 1,
        "granted_by_name": "Tomáš Novák",
        "created_at": "2026-10-28T09:00:00Z",
        "certificate_id": 1,
        "name": "Overhead or gantry crane operator"
      }
    ]
  }
]

Stavové kódy

KódZpráva
200
401authentication required
403not permitted
500internal server error
Vyzkoušet

POST /api/people/{id}/certifications

Notes a person as certified for something, by the manager's say-so, or by approving one of their certificates.

API klíč nebo relace.

Approving is sending certificate_id: the note copies what the document says and is linked to it. The note outlives the document: a certificate deleted later leaves it standing with certificate_id null.

One note per person and kind (per label for other_personal); a second of the same is refused. The person is pushed once. Nothing requires a note: it is the company's own record, shown to its managers when they staff a shift. Managers only.

V cestě

ParametrCo to je
idId členství člověka, jak je uvádí seznam lidí.

Tělo požadavku

Notes somebody as certified for something: by the manager's say-so, or by approving one of the person's certificates.

PoleTypCo to je
certificate_id celé číslo

certificate_id approves one of the person's certificates, as the people certificates endpoint lists them: the note takes the document's kind, label, scope and expiry and points at it, and the other fields here are ignored. Leave it out for a note with no proof.

kind řetězec

kind is a kind's id from the certificate kinds endpoint, or other_personal for one the list has no name for.

label řetězec

label says what an other_personal note is for. Required for that kind, refused for any other, at most 120 characters.

scope řetězec

At most 200 characters.

expires_on řetězec, nebo null

expires_on is the day it stops being valid, "2027-06-30", or null for unknown. Blank never means "for ever".

Odpověď

Certification response

Příklad
{
  "id": 1,
  "membership_id": 2,
  "kind": "lift_crane_overhead",
  "label": null,
  "scope": "bridge cranes to 10 t",
  "expires_on": "2027-06-30",
  "granted_by_membership_id": 1,
  "granted_by_name": "Tomáš Novák",
  "created_at": "2026-10-28T09:00:00Z",
  "certificate_id": 1,
  "name": "Overhead or gantry crane operator"
}

Stavové kódy

KódZpráva
201
400expires_on must be YYYY-MM-DD or null · invalid JSON body · invalid {thing} id
401authentication required
403not permitted · that application is the manager's to approve
404assignment not found · certificate not found · certification not found · client not found · gig not found · shift not found
409that invitation is no longer open · that is an invitation, and only the worker can accept it · that shift collides with work you have accepted · that shift is already full
500internal server error
Vyzkoušet

DELETE /api/people/{id}/certifications/{certificationID}

Takes a note away.

API klíč nebo relace.

Nobody is told. Managers only.

V cestě

ParametrCo to je
idId členství člověka, jak je uvádí seznam lidí.
certificationIDID certifikace, jak ji seznam lidí uvádí u osoby.

Odpověď

Bez těla.

Stavové kódy

KódZpráva
204
400invalid {thing} id
401authentication required
403not permitted · that application is the manager's to approve
404assignment not found · certificate not found · certification not found · client not found · gig not found · shift not found
409that invitation is no longer open · that is an invitation, and only the worker can accept it · that shift collides with work you have accepted · that shift is already full
500internal server error
Vyzkoušet

GET /api/people/{id}/certificates

Lists a person's certificates: the documents they hold, with their pages' sizes, as the person themselves sees them.

API klíč nebo relace.

A certificate is the person's, not the company's, so this is the same list the person's other employers see; who uploaded one is named only when it was a manager at your own company. Managers only.

V cestě

ParametrCo to je
idId členství člověka, jak je uvádí seznam lidí.

Odpověď

seznam: Certificate response

Příklad
[
  {
    "id": 1,
    "kind": "lift_crane_overhead",
    "label": null,
    "scope": "bridge cranes to 10 t",
    "number": "JB-4471",
    "issued_on": "2024-05-02",
    "expires_on": "2029-05-01",
    "pages": [
      {
        "position": 1,
        "content_type": "image/jpeg",
        "width": 1600,
        "height": 1067
      },
      {
        "position": 2,
        "content_type": "image/jpeg",
        "width": 1600,
        "height": 1067
      }
    ],
    "uploaded_by": {
      "membership_id": 1,
      "name": "Tomáš Novák",
      "company": "Alpha Stavby"
    },
    "created_at": "2026-10-28T09:00:00Z",
    "updated_at": "2026-10-28T09:04:00Z",
    "name": "Overhead or gantry crane operator"
  },
  {
    "id": 2,
    "kind": "other_personal",
    "label": "Drone pilot",
    "scope": null,
    "number": null,
    "issued_on": null,
    "expires_on": null,
    "pages": [],
    "uploaded_by": null,
    "created_at": "2026-10-28T10:00:00Z",
    "updated_at": "2026-10-28T10:00:00Z",
    "name": "Drone pilot"
  }
]

Stavové kódy

KódZpráva
200
400invalid {thing} id
401authentication required
403not permitted · that application is the manager's to approve
404assignment not found · certificate not found · certification not found · client not found · gig not found · shift not found
409that invitation is no longer open · that is an invitation, and only the worker can accept it · that shift collides with work you have accepted · that shift is already full
500internal server error
Vyzkoušet

POST /api/people/{id}/certificates

Adds a certificate on a person's behalf, for when the office holds the scans.

API klíč nebo relace.

It is recorded as uploaded by you, shown to the person as such, and is theirs afterwards like one they uploaded: they may correct or delete it, and you may not. The pages are added afterwards, one by one. Managers only.

V cestě

ParametrCo to je
idId členství člověka, jak je uvádí seznam lidí.

Tělo požadavku

What is typed about a certificate: what is printed on the card.

PoleTypCo to je
kind řetězec

kind is a kind's id from the certificate kinds endpoint, or other_personal for one the list has no name for.

label řetězec

label says what an other_personal certificate is. Required for that kind, refused for any other, at most 120 characters.

scope řetězec

At most 200 characters.

number řetězec

number is the number printed on the card, if any. At most 60 characters; nothing is checked against it.

issued_on řetězec, nebo null

issued_on is the day it was issued, "2024-05-02", or null.

expires_on řetězec, nebo null

expires_on is the day it stops being valid, "2029-05-01", or null for unknown. Blank never means "for ever".

Odpověď

Certificate response

Příklad
{
  "id": 2,
  "kind": "other_personal",
  "label": "Drone pilot",
  "scope": null,
  "number": null,
  "issued_on": null,
  "expires_on": null,
  "pages": [],
  "uploaded_by": null,
  "created_at": "2026-10-28T10:00:00Z",
  "updated_at": "2026-10-28T10:00:00Z",
  "name": "Drone pilot"
}

Stavové kódy

KódZpráva
201
400invalid JSON body · invalid {thing} id
401authentication required
403not permitted · that application is the manager's to approve
404assignment not found · certificate not found · certification not found · client not found · gig not found · shift not found
409that invitation is no longer open · that is an invitation, and only the worker can accept it · that shift collides with work you have accepted · that shift is already full
500internal server error
Vyzkoušet

POST /api/people/{id}/certificates/{certificateID}/pages

Adds the next page to a person's certificate, as the person's own pages endpoint does.

API klíč nebo relace.

The image comes as multipart/form-data with a part named page, or as JSON with the image in base64. At most 8 pages; what is kept is the pixels and nothing else. Managers only.

V cestě

ParametrCo to je
idId členství člověka, jak je uvádí seznam lidí.
certificateIDID dokladu, jak ho uvádí seznam dokladů.

Tělo požadavku

One page of a certificate as JSON: the image's bytes in base64. The same endpoint also takes multipart/form-data with the file in a part named page, which is what the app and the web client send.

PoleTypCo to je
image řetězec

A PDF is refused; a client with one renders its pages to images first. The server shrinks the image to about 1600 px on its long edge, re-encodes it as JPEG and keeps nothing else of it: no camera metadata, no position.

Odpověď

Certificate response

Příklad
{
  "id": 1,
  "kind": "lift_crane_overhead",
  "label": null,
  "scope": "bridge cranes to 10 t",
  "number": "JB-4471",
  "issued_on": "2024-05-02",
  "expires_on": "2029-05-01",
  "pages": [
    {
      "position": 1,
      "content_type": "image/jpeg",
      "width": 1600,
      "height": 1067
    },
    {
      "position": 2,
      "content_type": "image/jpeg",
      "width": 1600,
      "height": 1067
    }
  ],
  "uploaded_by": {
    "membership_id": 1,
    "name": "Tomáš Novák",
    "company": "Alpha Stavby"
  },
  "created_at": "2026-10-28T09:00:00Z",
  "updated_at": "2026-10-28T09:04:00Z",
  "name": "Overhead or gantry crane operator"
}

Stavové kódy

KódZpráva
201
400image must be base64 · invalid JSON body · invalid {thing} id · send the image as a part named page · the upload could not be read
401authentication required
403not permitted · that application is the manager's to approve
404assignment not found · certificate not found · certification not found · client not found · gig not found · shift not found
409that invitation is no longer open · that is an invitation, and only the worker can accept it · that shift collides with work you have accepted · that shift is already full
500internal server error
Vyzkoušet

GET /api/people/{id}/certificates/{certificateID}/pages/{position}

Answers one page of a person's certificate as the image itself, not as JSON.

API klíč nebo relace.

Managers only.

The body is the JPEG, with its content type.

V cestě

ParametrCo to je
idId členství člověka, jak je uvádí seznam lidí.
certificateIDID dokladu, jak ho uvádí seznam dokladů.
positionPořadí stránky na dokladu, počítáno od 1.

Odpověď

Bez těla.

Stavové kódy

KódZpráva
200
400invalid {thing} id
401authentication required
403not permitted · that application is the manager's to approve
404assignment not found · certificate not found · certification not found · client not found · gig not found · page not found · shift not found
409that invitation is no longer open · that is an invitation, and only the worker can accept it · that shift collides with work you have accepted · that shift is already full
500internal server error
Vyzkoušet

Doklady

About certificates: the documents a person holds, a crane licence or a welding test, with their photos, and the kinds there are. The list of kinds is the server's, so that no client carries a copy that can drift. The certificates here are the caller's own, whichever company or role the key acts in: a certificate is the person's, and every company they work for sees the same one. A manager reads and adds a member's certificates on the people endpoints, and notes somebody as certified for one there too.

GET /api/certificate-kinds

Lists every kind of certificate there is, with its name in the request's language, the group it is listed under, the words people use for it, and the trades with the order each offers kinds in.

API klíč nebo relace.

One kind, other_personal, is for a certificate the list has no name for; a note or a certificate of that kind carries a typed label. Either role.

Odpověď

Certificate kinds

Příklad
{
  "groups": [
    {
      "id": "education",
      "name": "Education"
    },
    {
      "id": "qualification",
      "name": "Qualification"
    }
  ],
  "kinds": [
    {
      "id": "other_personal",
      "name": "Other document",
      "group": "other",
      "aliases": [
        "jiný certifikát",
        "jiné oprávnění",
        "neznámý doklad"
      ]
    },
    {
      "id": "lift_crane_overhead",
      "name": "Overhead or gantry crane operator",
      "group": "induction",
      "aliases": [
        "jeřábnický průkaz",
        "mostový jeřáb"
      ]
    },
    {
      "id": "weld_iso9606",
      "name": "Welder qualification test (EN ISO 9606)",
      "group": "qualification",
      "aliases": [
        "svářečský certifikát",
        "úřední zkouška",
        "ISO 9606",
        "EN 287"
      ]
    }
  ],
  "trades": [
    {
      "id": "crane_operator",
      "name": "Crane / loader crane operator",
      "preferred": [
        "lift_crane_overhead",
        "lift_crane_mobile",
        "lift_crane_tower",
        "lift_loader_crane"
      ],
      "related": [
        "lift_slinger",
        "lift_signaller",
        "driver_licence"
      ],
      "common": [
        "edu_apprenticeship",
        "edu_diploma",
        "qual_nsk",
        "edu_retraining",
        "training_manufacturer",
        "training_bozp",
        "training_fire",
        "training_first_aid",
        "training_heights",
        "training_fall_protection",
        "scheme_scc",
        "scheme_vca",
        "other_personal"
      ]
    }
  ]
}

Stavové kódy

KódZpráva
200
401authentication required
Vyzkoušet

GET /api/certificates

Lists the caller's own certificates, oldest first, each with its pages' sizes.

API klíč nebo relace.

The pages themselves are read one at a time. Either role: the documents are the person's, whatever the key acts as.

Odpověď

seznam: Certificate response

Příklad
[
  {
    "id": 1,
    "kind": "lift_crane_overhead",
    "label": null,
    "scope": "bridge cranes to 10 t",
    "number": "JB-4471",
    "issued_on": "2024-05-02",
    "expires_on": "2029-05-01",
    "pages": [
      {
        "position": 1,
        "content_type": "image/jpeg",
        "width": 1600,
        "height": 1067
      },
      {
        "position": 2,
        "content_type": "image/jpeg",
        "width": 1600,
        "height": 1067
      }
    ],
    "uploaded_by": {
      "membership_id": 1,
      "name": "Tomáš Novák",
      "company": "Alpha Stavby"
    },
    "created_at": "2026-10-28T09:00:00Z",
    "updated_at": "2026-10-28T09:04:00Z",
    "name": "Overhead or gantry crane operator"
  },
  {
    "id": 2,
    "kind": "other_personal",
    "label": "Drone pilot",
    "scope": null,
    "number": null,
    "issued_on": null,
    "expires_on": null,
    "pages": [],
    "uploaded_by": null,
    "created_at": "2026-10-28T10:00:00Z",
    "updated_at": "2026-10-28T10:00:00Z",
    "name": "Drone pilot"
  }
]

Stavové kódy

KódZpráva
200
401authentication required
403not permitted
500internal server error
Vyzkoušet

POST /api/certificates

Adds a certificate of the caller's own, with no pages yet: the photos are added one by one afterwards.

API klíč nebo relace.

The managers of every company the caller works for are pushed once when the first page lands, naming nothing. A person holds at most 50.

Tělo požadavku

What is typed about a certificate: what is printed on the card.

PoleTypCo to je
kind řetězec

kind is a kind's id from the certificate kinds endpoint, or other_personal for one the list has no name for.

label řetězec

label says what an other_personal certificate is. Required for that kind, refused for any other, at most 120 characters.

scope řetězec

At most 200 characters.

number řetězec

number is the number printed on the card, if any. At most 60 characters; nothing is checked against it.

issued_on řetězec, nebo null

issued_on is the day it was issued, "2024-05-02", or null.

expires_on řetězec, nebo null

expires_on is the day it stops being valid, "2029-05-01", or null for unknown. Blank never means "for ever".

Odpověď

Certificate response

Příklad
{
  "id": 2,
  "kind": "other_personal",
  "label": "Drone pilot",
  "scope": null,
  "number": null,
  "issued_on": null,
  "expires_on": null,
  "pages": [],
  "uploaded_by": null,
  "created_at": "2026-10-28T10:00:00Z",
  "updated_at": "2026-10-28T10:00:00Z",
  "name": "Drone pilot"
}

Stavové kódy

KódZpráva
201
400invalid JSON body
401authentication required
403not permitted · that application is the manager's to approve
404assignment not found · certificate not found · certification not found · client not found · gig not found · shift not found
409that invitation is no longer open · that is an invitation, and only the worker can accept it · that shift collides with work you have accepted · that shift is already full
500internal server error
Vyzkoušet

POST /api/certificates/read

Reads the words off the photos of one document and proposes what the certificate's fields should say: its kind, the dates on it and its number, with how well each photo read.

API klíč nebo relace.

Nothing is stored; the client fills its form in from the answer and the person checks it before saving. Either role.

The photos come as multipart/form-data, each in a part named page, or as JSON with the images in base64; at most 8, each at most 4 MB. A photo is shrunk here before it is read, as it is before it is stored. Reading takes about a second a page. Answers 503 when reading is not set up on this server, in which case the form works by hand.

Tělo požadavku

The photos to read, as JSON. The same endpoint also takes multipart/form-data with each photo in a part named page, which is what the app and the web client send.

PoleTypCo to je
images seznam: řetězec

They are read and then forgotten; nothing is stored until the certificate is created.

Odpověď

Certificate reading

Příklad
{
  "kind": "lift_crane_overhead",
  "kind_name": "Overhead or gantry crane operator",
  "issued_on": "2024-05-02",
  "expires_on": "2029-05-01",
  "number": "JB-4471",
  "pages": [
    {
      "position": 1,
      "readability": 94,
      "legible": true
    },
    {
      "position": 2,
      "readability": 41,
      "legible": false
    },
    {
      "position": 3,
      "readability": null,
      "legible": false
    }
  ],
  "legible": false
}

Stavové kódy

KódZpráva
200
400image must be base64 · invalid JSON body · send at least one page to read · send the image as a part named page · the upload could not be read
401authentication required
403not permitted · that application is the manager's to approve
404assignment not found · certificate not found · certification not found · client not found · gig not found · shift not found
409that invitation is no longer open · that is an invitation, and only the worker can accept it · that shift collides with work you have accepted · that shift is already full
500internal server error
503reading photos is not set up on this server; fill the form in by hand
Vyzkoušet

PATCH /api/certificates/{id}

Corrects what is typed about one of the caller's certificates.

API klíč nebo relace.

Every field is written as sent, so send the whole record; the pages are untouched.

V cestě

ParametrCo to je
idID dokladu, jak ho uvádí seznam dokladů.

Tělo požadavku

What is typed about a certificate: what is printed on the card.

PoleTypCo to je
kind řetězec

kind is a kind's id from the certificate kinds endpoint, or other_personal for one the list has no name for.

label řetězec

label says what an other_personal certificate is. Required for that kind, refused for any other, at most 120 characters.

scope řetězec

At most 200 characters.

number řetězec

number is the number printed on the card, if any. At most 60 characters; nothing is checked against it.

issued_on řetězec, nebo null

issued_on is the day it was issued, "2024-05-02", or null.

expires_on řetězec, nebo null

expires_on is the day it stops being valid, "2029-05-01", or null for unknown. Blank never means "for ever".

Odpověď

Certificate response

Příklad
{
  "id": 1,
  "kind": "lift_crane_overhead",
  "label": null,
  "scope": "bridge cranes to 10 t",
  "number": "JB-4471",
  "issued_on": "2024-05-02",
  "expires_on": "2029-05-01",
  "pages": [
    {
      "position": 1,
      "content_type": "image/jpeg",
      "width": 1600,
      "height": 1067
    },
    {
      "position": 2,
      "content_type": "image/jpeg",
      "width": 1600,
      "height": 1067
    }
  ],
  "uploaded_by": {
    "membership_id": 1,
    "name": "Tomáš Novák",
    "company": "Alpha Stavby"
  },
  "created_at": "2026-10-28T09:00:00Z",
  "updated_at": "2026-10-28T09:04:00Z",
  "name": "Overhead or gantry crane operator"
}

Stavové kódy

KódZpráva
200
400invalid JSON body · invalid {thing} id
401authentication required
403not permitted · that application is the manager's to approve
404assignment not found · certificate not found · certification not found · client not found · gig not found · shift not found
409that invitation is no longer open · that is an invitation, and only the worker can accept it · that shift collides with work you have accepted · that shift is already full
500internal server error
Vyzkoušet

DELETE /api/certificates/{id}

Removes one of the caller's certificates with its pages.

API klíč nebo relace.

A note a company made from it stays, saying it has no proof on file. Nobody is told.

V cestě

ParametrCo to je
idID dokladu, jak ho uvádí seznam dokladů.

Odpověď

Bez těla.

Stavové kódy

KódZpráva
204
400invalid {thing} id
401authentication required
403not permitted · that application is the manager's to approve
404assignment not found · certificate not found · certification not found · client not found · gig not found · shift not found
409that invitation is no longer open · that is an invitation, and only the worker can accept it · that shift collides with work you have accepted · that shift is already full
500internal server error
Vyzkoušet

POST /api/certificates/{id}/pages

Adds the next page to one of the caller's certificates: the front, the back, an attachment, at most 8.

API klíč nebo relace.

The image comes as multipart/form-data in a part named page, or as JSON with the bytes in base64. Whatever is sent, what is kept is a JPEG of the pixels and nothing else: no camera metadata, no position. Answers the certificate with its pages.

V cestě

ParametrCo to je
idID dokladu, jak ho uvádí seznam dokladů.

Tělo požadavku

One page of a certificate as JSON: the image's bytes in base64. The same endpoint also takes multipart/form-data with the file in a part named page, which is what the app and the web client send.

PoleTypCo to je
image řetězec

A PDF is refused; a client with one renders its pages to images first. The server shrinks the image to about 1600 px on its long edge, re-encodes it as JPEG and keeps nothing else of it: no camera metadata, no position.

Odpověď

Certificate response

Příklad
{
  "id": 1,
  "kind": "lift_crane_overhead",
  "label": null,
  "scope": "bridge cranes to 10 t",
  "number": "JB-4471",
  "issued_on": "2024-05-02",
  "expires_on": "2029-05-01",
  "pages": [
    {
      "position": 1,
      "content_type": "image/jpeg",
      "width": 1600,
      "height": 1067
    },
    {
      "position": 2,
      "content_type": "image/jpeg",
      "width": 1600,
      "height": 1067
    }
  ],
  "uploaded_by": {
    "membership_id": 1,
    "name": "Tomáš Novák",
    "company": "Alpha Stavby"
  },
  "created_at": "2026-10-28T09:00:00Z",
  "updated_at": "2026-10-28T09:04:00Z",
  "name": "Overhead or gantry crane operator"
}

Stavové kódy

KódZpráva
201
400image must be base64 · invalid JSON body · invalid {thing} id · send the image as a part named page · the upload could not be read
401authentication required
403not permitted · that application is the manager's to approve
404assignment not found · certificate not found · certification not found · client not found · gig not found · shift not found
409that invitation is no longer open · that is an invitation, and only the worker can accept it · that shift collides with work you have accepted · that shift is already full
500internal server error
Vyzkoušet

GET /api/certificates/{id}/pages/{position}

Answers one page of one of the caller's certificates as the image itself, not as JSON.

API klíč nebo relace.

The body is the JPEG, with its content type.

V cestě

ParametrCo to je
idID dokladu, jak ho uvádí seznam dokladů.
positionPořadí stránky na dokladu, počítáno od 1.

Odpověď

Bez těla.

Stavové kódy

KódZpráva
200
400invalid {thing} id
401authentication required
403not permitted · that application is the manager's to approve
404assignment not found · certificate not found · certification not found · client not found · gig not found · page not found · shift not found
409that invitation is no longer open · that is an invitation, and only the worker can accept it · that shift collides with work you have accepted · that shift is already full
500internal server error
Vyzkoušet

DELETE /api/certificates/{id}/pages/{position}

Takes one page off one of the caller's certificates; the pages after it move up.

API klíč nebo relace.

Answers the certificate as it is now.

V cestě

ParametrCo to je
idID dokladu, jak ho uvádí seznam dokladů.
positionPořadí stránky na dokladu, počítáno od 1.

Odpověď

Certificate response

Příklad
{
  "id": 2,
  "kind": "other_personal",
  "label": "Drone pilot",
  "scope": null,
  "number": null,
  "issued_on": null,
  "expires_on": null,
  "pages": [],
  "uploaded_by": null,
  "created_at": "2026-10-28T10:00:00Z",
  "updated_at": "2026-10-28T10:00:00Z",
  "name": "Drone pilot"
}

Stavové kódy

KódZpráva
200
400invalid {thing} id
401authentication required
403not permitted · that application is the manager's to approve
404assignment not found · certificate not found · certification not found · client not found · gig not found · page not found · shift not found
409that invitation is no longer open · that is an invitation, and only the worker can accept it · that shift collides with work you have accepted · that shift is already full
500internal server error
Vyzkoušet

Klienti

The company's clients: the companies it invoices, each with the Czech tax identifiers an invoice needs. A project names one by its id. Clients are the company's own; one firm never sees another's.

GET /api/clients

Lists the company's clients, by name.

API klíč nebo relace.

Archived clients are left out unless ?archived=1. Any member of the company may read the list, as the app shows a project's client.

Parametry dotazu

  • archived

Odpověď

seznam: Client

Příklad
[
  {
    "id": 1,
    "name": "Stavby Novák s.r.o.",
    "ico": "12345678",
    "dic": "CZ12345678",
    "address_line1": "Průmyslová 12",
    "address_line2": null,
    "city": "Ostrava",
    "postal_code": "702 00",
    "country": "CZ",
    "contact_name": "Petr Novák",
    "contact_email": "petr@stavbynovak.test",
    "contact_phone": "+420777123456",
    "is_archived": false,
    "created_at": "2026-09-01T09:00:00Z"
  },
  {
    "id": 2,
    "name": "Jan Dvořák",
    "ico": null,
    "dic": null,
    "address_line1": null,
    "address_line2": null,
    "city": null,
    "postal_code": null,
    "country": "CZ",
    "contact_name": null,
    "contact_email": null,
    "contact_phone": null,
    "is_archived": false,
    "created_at": "2026-09-02T09:00:00Z"
  }
]

Stavové kódy

KódZpráva
200
401authentication required
403not permitted
500internal server error
Vyzkoušet

GET /api/clients/{id}

One client.

API klíč nebo relace.

Another company's is not found.

V cestě

ParametrCo to je
idId klienta.

Odpověď

Client

Příklad
{
  "id": 1,
  "name": "Stavby Novák s.r.o.",
  "ico": "12345678",
  "dic": "CZ12345678",
  "address_line1": "Průmyslová 12",
  "address_line2": null,
  "city": "Ostrava",
  "postal_code": "702 00",
  "country": "CZ",
  "contact_name": "Petr Novák",
  "contact_email": "petr@stavbynovak.test",
  "contact_phone": "+420777123456",
  "is_archived": false,
  "created_at": "2026-09-01T09:00:00Z"
}

Stavové kódy

KódZpráva
200
400invalid {thing} id
401authentication required
403not permitted · that application is the manager's to approve
404assignment not found · certificate not found · certification not found · client not found · gig not found · shift not found
409that invitation is no longer open · that is an invitation, and only the worker can accept it · that shift collides with work you have accepted · that shift is already full
500internal server error
Vyzkoušet

POST /api/clients

Adds a client to the company.

API klíč nebo relace.

A name is required and must be new at the company; everything else may be filled in later on the web, where the form can look a Czech company up by its registration number. Managers only.

Tělo požadavku

A new client.

PoleTypCo to je
name řetězec
ico řetězec, nebo null

ico is the Czech company registration number, eight digits with any leading zeros. Null for a private individual.

dic řetězec, nebo null

dic is the VAT number, "CZ12345678". Null when not VAT registered.

address_line1 řetězec, nebo null
address_line2 řetězec, nebo null
city řetězec, nebo null
postal_code řetězec, nebo null
country řetězec

country is a two-letter code; "CZ" unless given.

contact_name řetězec, nebo null

The client's own contact person, who a worker rings about a job when the project names no site contact of its own.

contact_email řetězec, nebo null
contact_phone řetězec, nebo null

Odpověď

Client

Příklad
{
  "id": 2,
  "name": "Jan Dvořák",
  "ico": null,
  "dic": null,
  "address_line1": null,
  "address_line2": null,
  "city": null,
  "postal_code": null,
  "country": "CZ",
  "contact_name": null,
  "contact_email": null,
  "contact_phone": null,
  "is_archived": false,
  "created_at": "2026-09-02T09:00:00Z"
}

Stavové kódy

KódZpráva
201
400client name is required · invalid JSON body
401authentication required
403not permitted · that application is the manager's to approve
404assignment not found · certificate not found · certification not found · client not found · gig not found · shift not found
409that invitation is no longer open · that is an invitation, and only the worker can accept it · that shift collides with work you have accepted · that shift is already full
500internal server error
Vyzkoušet

Hodiny zakázky

A project's hours as its managers read them: every time entry on the project, whoever worked it, at the rate each entry snapshotted. Records and totals only: there is no approval step, no payslip and no tax here.

GET /api/gigs/{id}/hours

Lists every time entry on a project, newest first.

API klíč nebo relace.

earned_amount is each entry's worth at its own rate, worked out here to the minute; an entry still on the clock has no clock-out and counts in no total. An archived project's hours are still listed. Managers only.

V cestě

ParametrCo to je
idId zakázky.

Odpověď

seznam: Hours row

Příklad
[
  {
    "id": 1,
    "membership_id": 2,
    "gig_id": 1,
    "timeslot_id": 1,
    "clock_in_at": "2026-09-10T04:52:00Z",
    "clock_out_at": "2026-09-10T13:06:00Z",
    "source": "manual",
    "rate_amount": 5200000,
    "rate_currency": "CZK",
    "earned_amount": 42813333,
    "client_event_id": "a1f0c2f1-3d6b-4b9c-9f3e-6e2d9a4c1b11",
    "corrected_at": null,
    "created_at": "2026-09-10T04:52:03Z",
    "worker_name": "Jana Horáková",
    "slot_starts_at": "2026-09-10T05:00:00Z",
    "slot_ends_at": "2026-09-10T13:00:00Z",
    "recorded_by": ""
  }
]

Stavové kódy

KódZpráva
200
400invalid {thing} id
401authentication required
403not permitted · that application is the manager's to approve
404assignment not found · certificate not found · certification not found · client not found · gig not found · shift not found
409that invitation is no longer open · that is an invitation, and only the worker can accept it · that shift collides with work you have accepted · that shift is already full
500internal server error
Vyzkoušet

Dostupnost

Answers the liveness check that uptime alerting polls.

Availability is a product risk here, not just an ops one: an SOS that cannot reach the server is emergency staffing that fails.

GET /healthz

Reports 200 when the server can reach its database, 503 otherwise.

Veřejné: není potřeba klíč ani relace.

The response body is deliberately free of detail: this endpoint is unauthenticated and reachable from the internet, so it says whether the service is up and nothing about why it is not.

Odpověď

objekt

Příklad
{
  "status": "ok"
}

Stavové kódy

KódZpráva
200
503
Vyzkoušet

Typy

Tvary, kterými volání výše odpovídají, každý popsaný jednou. Typ pole říká, zda může být null, a seznam říká, čeho je seznamem.

Request code response requestCodeResponse

The answer to asking for a sign-in code.

PoleTypCo to je
status řetězec
resend_after_seconds celé číslo

resend_after_seconds is how long until another code may be asked for the same address. A request sooner is answered 429 with a Retry-After.

Session sessionResponse

Describes who the caller is and where they may act.

token and expires_at are omitted when no new session was issued — /me returns this same shape without minting anything, and an empty token field would invite a client to store one.

PoleTypCo to je
token řetězec

V těle chybí, když je prázdné.

expires_at řetězec

V těle chybí, když je prázdné.

membership Entry
memberships seznam: Entry
language řetězec, nebo null

language is the language the account chose, "cs" or "en", and null for one that never chose. It is about the person, not the entry. The app shows it only on a phone with no per-app language setting (Android 12 and older), where its own picker sets it; everywhere else the phone says which language the app is in.

Deletion deletionResponse

What deleting the caller's account would do, company by company. It only ever describes the caller's own memberships, and carries no id a client could send back: the deletion names nothing, because the account it deletes is the session's.

PoleTypCo to je
can_delete boolean

can_delete is false while something refuses it — today, being the only manager a company has. The app shows why and offers no button.

companies seznam: Leaving company

Preview invitation services.PreviewInvitation

Describes an invitation to whoever holds the link, before they accept it.

It deliberately reveals only the company name and what they are invited to do — enough to decide whether to accept, and nothing about the organization's people or projects, since anyone holding the link is by definition not yet a member.

PoleTypCo to je
org_name řetězec
is_manager boolean
is_worker boolean
first_name řetězec
email řetězec
rate_amount celé číslo, nebo null

Peníze: celé číslo se čtyřmi skrytými desetinnými místy, takže 4200000 je 420,00, a vedle něj měna.

rate_currency řetězec, nebo null

Acceptance acceptResponse

Says what the app does next. outcome is one of three, and each fills its own fields and leaves the others null:

  • "signed_in": accepting created the account. session is the body a sign-in answers with, token included, and the app is in.
  • "needs_code": the account was there already. code_sent says a code is on its way to email, and the app opens at "enter the code".
  • "joined": the caller is already signed in as that account. membership is the entry it gained, so the app can offer to switch to it; the session it holds is unchanged and is simply read again.
PoleTypCo to je
outcome řetězec
email řetězec
code_sent boolean
session Session, nebo null
membership Entry, nebo null

Invitation services.Invitation

A pending offer of a job at one company.

PoleTypCo to je
id celé číslo
email řetězec
first_name řetězec
last_name řetězec
is_manager boolean
is_worker boolean
rate_amount celé číslo, nebo null

Peníze: celé číslo se čtyřmi skrytými desetinnými místy, takže 4200000 je 420,00, a vedle něj měna.

rate_currency řetězec, nebo null
expires_at časový údaj, RFC 3339 v UTC
accepted_at časový údaj, RFC 3339 v UTC, nebo null
created_at časový údaj, RFC 3339 v UTC

Dashboard services.Dashboard

One person's home screen at one company.

Exactly one of worker and manager is set, matching role. role comes from the active membership, so the same person can be a manager on one company's dashboard and a worker on the next.

PoleTypCo to je
role řetězec: worker | manager
days seznam: řetězec

days are the dates of the range, Monday of this week first, as YYYY-MM-DD: seven per week asked for, so seven by default.

today řetězec

today is one of days, so a client can mark it without deciding for itself which zone "today" is in.

worker Worker dashboard, nebo null

V těle chybí, když je prázdné.

manager Manager dashboard, nebo null

V těle chybí, když je prázdné.

Assignment services.Assignment

One worker's invitation into one timeslot.

PoleTypCo to je
id celé číslo
timeslot_id celé číslo
membership_id celé číslo
origin řetězec: staffed | sos | open | backfilled
status řetězec: pending | accepted | declined | expired | withdrawn | cancelled
rate_amount celé číslo, nebo null

rate_amount is the rate agreed for THIS assignment, snapshotted when the invitation was created. Never recompute it from the project or the membership: editing either rate must not change what already-promised work is worth.

Null when no hourly rate was agreed — the project sets none and neither does the worker. That is a real state, "hours only", and never a zero, which would read as unpaid work. Both halves are null together; the database refuses one without the other.

Peníze: celé číslo se čtyřmi skrytými desetinnými místy, takže 4200000 je 420,00, a vedle něj měna.

rate_currency řetězec, nebo null
role_id celé číslo

role_id is the role on the shift this assignment fills: where its rate came from, and whose places it takes one of. role_label is that role's name, filled by the reads a person sees it through (the schedule, the staffing screen); nil for the unnamed role of a plain shift, and on a write's answer, which does not join it.

role_label řetězec, nebo null
invited_at časový údaj, RFC 3339 v UTC
responded_at časový údaj, RFC 3339 v UTC, nebo null
expires_at časový údaj, RFC 3339 v UTC
created_at časový údaj, RFC 3339 v UTC
takes_from časový údaj, RFC 3339 v UTC, nebo null

takes_from/takes_until are the part of the shift the worker agreed to work, where they took it PARTIALLY around a colliding accepted shift. Nil is the whole shift, the ordinary case. Computed server-side at the moment of taking — never sent by a client — and settled then: a colliding shift later given up does not widen it.

takes_until časový údaj, RFC 3339 v UTC, nebo null
worker_name řetězec

worker_name is filled by reads a PM makes, so a staffing view can show who was invited without a second query per row.

V těle chybí, když je prázdné.

Schedule entry services.ScheduleEntry

One row of a worker's own schedule.

PoleTypCo to je
id celé číslo
timeslot_id celé číslo
membership_id celé číslo
origin řetězec: staffed | sos | open | backfilled
status řetězec: pending | accepted | declined | expired | withdrawn | cancelled
rate_amount celé číslo, nebo null

rate_amount is the rate agreed for THIS assignment, snapshotted when the invitation was created. Never recompute it from the project or the membership: editing either rate must not change what already-promised work is worth.

Null when no hourly rate was agreed — the project sets none and neither does the worker. That is a real state, "hours only", and never a zero, which would read as unpaid work. Both halves are null together; the database refuses one without the other.

Peníze: celé číslo se čtyřmi skrytými desetinnými místy, takže 4200000 je 420,00, a vedle něj měna.

rate_currency řetězec, nebo null
role_id celé číslo

role_id is the role on the shift this assignment fills: where its rate came from, and whose places it takes one of. role_label is that role's name, filled by the reads a person sees it through (the schedule, the staffing screen); nil for the unnamed role of a plain shift, and on a write's answer, which does not join it.

role_label řetězec, nebo null
invited_at časový údaj, RFC 3339 v UTC
responded_at časový údaj, RFC 3339 v UTC, nebo null
expires_at časový údaj, RFC 3339 v UTC
created_at časový údaj, RFC 3339 v UTC
takes_from časový údaj, RFC 3339 v UTC, nebo null

takes_from/takes_until are the part of the shift the worker agreed to work, where they took it PARTIALLY around a colliding accepted shift. Nil is the whole shift, the ordinary case. Computed server-side at the moment of taking — never sent by a client — and settled then: a colliding shift later given up does not widen it.

takes_until časový údaj, RFC 3339 v UTC, nebo null
worker_name řetězec

worker_name is filled by reads a PM makes, so a staffing view can show who was invited without a second query per row.

V těle chybí, když je prázdné.

timeslot Shift
gig_id celé číslo
gig_title řetězec
full boolean

full says every place in THIS entry's role is taken by somebody who accepted. A pending invitation to a full role cannot be accepted, so the clients show it as waiting for a place rather than offering an Accept that would be refused. Worked out here, not in a client.

collides_with_title řetězec, nebo null

Set on PENDING entries only. No client works any of this out for itself.

collides_with_company řetězec, nebo null

collides_with_company names the company the colliding shift is at when that is another of the worker's companies, and is null for this company's own: the clients say "at Beta" only then.

collides_from časový údaj, RFC 3339 v UTC, nebo null
collides_until časový údaj, RFC 3339 v UTC, nebo null
can_take_from časový údaj, RFC 3339 v UTC, nebo null
can_take_until časový údaj, RFC 3339 v UTC, nebo null

Answered invitations answeredMany

What answering all of a project's invitations did, as counts. The app re-reads the dashboard for the shifts themselves, as it does after answering one; these two numbers are what it has to say something about.

PoleTypCo to je
answered celé číslo

answered is how many invitations were accepted, or declined.

full celé číslo

full is how many were left waiting because their shift has no place. Always zero for a decline.

colliding celé číslo

colliding is how many were left waiting because they collide with accepted work. Always zero for a decline.

Time entry services.TimeEntry

One stretch of work: when someone started, when they stopped, and what it was worth.

PoleTypCo to je
id celé číslo
membership_id celé číslo
gig_id celé číslo
timeslot_id celé číslo, nebo null

timeslot_id is null for a stand-alone entry, which is normal rather than an error: someone who worked on a day nobody planned still worked.

clock_in_at časový údaj, RFC 3339 v UTC
clock_out_at časový údaj, RFC 3339 v UTC, nebo null

clock_out_at is null while the worker is still on site — and also when they forgot. The two are indistinguishable, and nothing here guesses.

source řetězec: manual | geofence | backfilled
rate_amount celé číslo, nebo null

rate_amount is snapshotted at creation: from the assignment when the entry linked to one, otherwise the usual rate at that moment — the project's, else the membership's. Never recomputed.

Null when no hourly rate applied: the hours are recorded and the entry is worth no money figure — not zero, which would read as unpaid work.

Peníze: celé číslo se čtyřmi skrytými desetinnými místy, takže 4200000 je 420,00, a vedle něj měna.

rate_currency řetězec, nebo null
client_event_id řetězec

client_event_id is the device's own id for this event, and the reason a retried push from a phone that was offline creates one row rather than two. Empty for entries created server-side.

V těle chybí, když je prázdné.

corrected_at časový údaj, RFC 3339 v UTC, nebo null
created_at časový údaj, RFC 3339 v UTC

Project gigResponse

A project as the app receives it: the project, and how to reach the manager running it.

Every endpoint that answers with a project answers with this, so the app parses one shape whichever screen asked.

PoleTypCo to je
id celé číslo
title řetězec
owner_id celé číslo

owner_id is a membership id — the PM *at this company* — not a user id.

client_id celé číslo, nebo null

The company being invoiced for this work. Nullable: a project may be internal, or booked before anyone has agreed who is paying.

client_name řetězec, nebo null
client_contact_name řetězec, nebo null

The client's own contact person, from the client's record.

It is NOT what a screen shows as "who to ring": that is job_contact, below, which is this person only when the project names nobody for the site.

client_contact_phone řetězec, nebo null
client_contact_email řetězec, nebo null
job_contact Job contact, nebo null

job_contact is who a worker rings about this job, already chosen: the site contact where the project names one, else the client's. Null when there is nobody at all.

latitude číslo, nebo null

Where the work happens, in WGS84 degrees. Nullable because a project can be created before anyone has pinned the site.

This is the SITE's location, never a worker's. The server never receives a position from a device — the app holds these coordinates, computes distance to them locally, and sends only a clock event.

longitude číslo, nebo null
geofence_radius_m celé číslo, nebo null

Radius in metres for optional geofence auto-clocking.

site_address řetězec, nebo null

Where to go, in words: "Gate 3, Průmyslová 12, Ostrava".

Stored rather than looked up on the phone, because the map tiles are the first thing to fail on a bad connection and that is precisely when somebody needs to know which gate. Free text — a site often has no postal address at all. Never the client's address, which is where the invoice goes.

site_outline seznam: Point

The drawn site outline, if the manager traced one rather than dropping a pin. latitude, longitude and geofence_radius_m are DERIVED from this when it is present — stored alongside rather than recomputed on read, because the geofence compares against them on a phone that may be offline.

Kept so the outline can be drawn again on any map, not only reduced to a circle: a worker looking at an L-shaped site should see its shape.

expected_minutes celé číslo, nebo null

expected_minutes is how much work this project is thought to be, and it is a FORECAST ONLY: it never reaches a rate, an assignment or a payslip. It exists so a project nobody has scheduled into timeslots yet can still say roughly what it is worth. Where timeslots exist they are the better answer and the screens prefer them. Stored in minutes, shown as hours.

expenses seznam: Expense
created_at časový údaj, RFC 3339 v UTC
is_assigned boolean
is_invited boolean

is_invited and shifts_to_take are what the acting worker's list says about each project beside is_assigned: an invitation of theirs still waiting for an answer, and how many of its open shifts they could take now. Worked out here so both clients mark a row the same way, and always false and 0 for a manager.

shifts_to_take celé číslo
archived_at časový údaj, RFC 3339 v UTC, nebo null

archived_at is when a manager finished with this project, and null while it is live. An archived project takes no new work — no days, shifts, invitations or clock-ins — and leaves every list of what is coming up, but nothing on it is removed: its hours, expenses and invoices are all still there. On the wire so a client can say "archived" instead of offering a clock-in that would be refused. Who archived it stays here, like every other manager's detail.

project_manager Project manager, nebo null

Null when there is nobody to show: the owner has left, or is no longer a manager. Never another company's manager, and never a worker.

company Company tag, nebo null

company is which of the caller's entries the row came from, on a list across them and nowhere else.

V těle chybí, když je prázdné.

Earnings projectEarnings

What one worker has earned on one project, and what they stand to earn on it.

Two lists, per currency, never mixed and never converted: this product holds no exchange rate and inventing one would be inventing money.

PoleTypCo to je
earned seznam: Money total

earned is hours already worked, valued from TIME ENTRIES.

upcoming seznam: Money total

upcoming is accepted work not yet done, valued from ASSIGNMENTS.

earned_unrated_minutes celé číslo

The minutes of each that had no hourly rate agreed, and so are in neither list. Always present, zero when everything had a rate, so the app can say "hours only" rather than show nothing.

upcoming_unrated_minutes celé číslo
running Running shift, nebo null

running is the shift the caller is on the clock for here right now, and what it has come to so far. Null when they are not on the clock, and null for a clock-out forgotten long ago. It is in neither list above: earned stays finished work only.

Point geo.Point

A WGS84 coordinate in degrees.

PoleTypCo to je
lat číslo
lon číslo

Expense services.GigExpense

A cost booked against a gig.

cost_amount is an int64 with 4 implied decimal places — 42 CZK is 420000 — and is never converted to a float anywhere in this codebase. It crosses the wire raw, alongside its currency, and is formatted only at the edge.

PoleTypCo to je
id celé číslo
gig_id celé číslo

gig_id is the one project this cost belongs to.

created_by_membership_id celé číslo

created_by_membership_id is who booked it, as a membership rather than a user — the same person at another company is a different author.

It is the whole access rule: a worker sees, edits and deletes only the expenses they booked, a manager every one on the organization's projects. Sent to clients so a screen can tell "mine" from "theirs" without asking again; the server decides regardless.

created_by_name řetězec

created_by_name is the author's name, resolved for display. Managers see whose cost each one is; a worker only ever receives their own rows, so it is their own name.

description řetězec
cost_amount celé číslo

Peníze: celé číslo se čtyřmi skrytými desetinnými místy, takže 4200000 je 420,00, a vedle něj měna.

cost_currency řetězec

"CZK" or "EUR"

created_at časový údaj, RFC 3339 v UTC

Tool icon services.ToolIcon

One choice in the picker: the stored name and what to call it.

PoleTypCo to je
name řetězec

name is what goes in the database and crosses the wire. Lower case, no spaces, stable forever.

label řetězec

label is the English word for it.

Tool services.Tool

One item on a worker's kit list.

A client is only ever shown its own tools, so the field would tell it something it already knows — and echoing an id a client never sends invites it to start sending one.

PoleTypCo to je
id celé číslo
name řetězec
icon řetězec
quantity celé číslo, nebo null

quantity is null for "one, or some". Nothing decrements it: this is a kit list, not a stock level.

created_at časový údaj, RFC 3339 v UTC
gig_ids seznam: celé číslo

gig_ids are the projects this tool is currently attached to, so a list screen can show where it is expected without a query per row.

Calendar day calendarDay

One day a project runs, with the shifts on it.

PoleTypCo to je
day řetězec

day is the calendar day, "2026-10-27". day_id is its id, which a new shift names.

day_id celé číslo
shifts seznam: Shift as a manager sees it

shifts are the day's shifts, earliest first; a day scheduled with no shift yet has none.

Scheduled day services.GigDay

One day a project runs.

The calendar is a set of days, not a range: a project pauses and resumes, and a gap is simply an absent row.

PoleTypCo to je
id celé číslo
gig_id celé číslo
day řetězec

Rendered as YYYY-MM-DD. A calendar day is a DATE, never a timestamp: answering "which days does this run" with instants shifts days across timezones.

Removed days removedDays

What removing days did, or would do.

PoleTypCo to je
confirmed boolean

confirmed is false for a preview, in which nothing changed.

days celé číslo

days is how many days are on the calendar to come off (a preview), or came off it.

people celé číslo

people is how many different people hold a live place on those days: who will be told. In a preview only.

cancelled celé číslo

cancelled is how many places were cancelled, once confirmed.

Role to add roleRequest

One role on a new shift.

PoleTypCo to je
label řetězec

label names the kind of worker. A shift with one role may leave it empty; two roles need names to be told apart.

headcount celé číslo

headcount is how many of this role the shift needs, at least 1.

rate_amount celé číslo, nebo null

rate_amount is what an hour in this role pays. Leave both null for the usual rate: the project's pay rate, else each worker's own. Refused above the project's maximum hourly rate.

Peníze: celé číslo se čtyřmi skrytými desetinnými místy, takže 4200000 je 420,00, a vedle něj měna.

rate_currency řetězec, nebo null

Added shifts addedShifts

What laying a shift on days made.

PoleTypCo to je
shifts seznam: Shift as a manager sees it
scheduled celé číslo

scheduled is how many of the days were not on the calendar before.

Role roleResponse

One role on a shift: a kind of worker with its own places and, where the manager set one, its own hourly rate.

PoleTypCo to je
id celé číslo
label řetězec, nebo null

label names the kind of worker ("crane op"). Null for the one unnamed role of a plain shift.

headcount celé číslo

headcount is how many of this role the shift needs.

rate_amount celé číslo, nebo null

rate_amount is what an hour in this role pays, or null for the usual rate: the project's pay rate, else each worker's own.

Peníze: celé číslo se čtyřmi skrytými desetinnými místy, takže 4200000 je 420,00, a vedle něj měna.

rate_currency řetězec, nebo null
accepted celé číslo

accepted fills the role's places; pending is what nobody has answered yet, and fills nothing.

pending celé číslo

Moved shifts movedShifts

What a move did, or would do.

PoleTypCo to je
confirmed boolean

confirmed is false for a preview, in which nothing changed.

shifts celé číslo

shifts is how many move; skipped how many were left where they were, having started or carrying an SOS.

skipped celé číslo
people celé číslo

people is how many hold a live place on the moving shifts and are asked again.

first_day řetězec

first_day is the earliest moved shift's new day, "2026-10-29".

Removed shift removedShift

What removing a shift did, or would do.

PoleTypCo to je
confirmed boolean

confirmed is false for a preview, in which nothing changed.

accepted celé číslo

accepted and pending are the live places on the shift: who had agreed to work it, and who was asked and had not answered. In a preview.

pending celé číslo
cancelled celé číslo

cancelled is how many places were cancelled, once confirmed.

Shift with its people shiftDetail

A shift with the people on it.

PoleTypCo to je
id celé číslo
gig_id celé číslo
day_id celé číslo
starts_at časový údaj, RFC 3339 v UTC
ends_at časový údaj, RFC 3339 v UTC
required_workers celé číslo
role_label řetězec, nebo null

role_label is the one-string summary of Roles ("2× crane op, 3× labourer"; a single named role is its label alone; the unnamed role of a plain shift is nil), written by this service in the same transaction as the lines. It is what the app and most screens show of the roles.

created_at časový údaj, RFC 3339 v UTC
accepted celé číslo

Staffing is filled by the reads that compute it. accepted is what fills the slot; pending is what a PM still has no answer on. Short is the places nobody has accepted, counted ROLE BY ROLE: a labourer too many does not stand in for the crane op who is missing. Off the wire: the clients are told what follows from it (full, which open shifts are takeable), never asked to count.

pending celé číslo
short celé číslo

short is the places nobody has accepted, counted role by role: a labourer too many does not stand in for the crane op who is missing.

is_open boolean

is_open says the shift is advertised to the company, so any worker there may take a place without being invited. open_auto_accept says a taker is confirmed outright; otherwise they land as an applicant for the manager to approve.

open_auto_accept boolean
offered_rate_multiplier celé číslo, nebo null

offered_rate_multiplier raises each taker's usual rate, with four implied decimals: 15000 is 1.5×. Null when the shift offers each role's rate as it stands. An SOS is an open shift with this set.

Násobek se čtyřmi skrytými desetinnými místy: 15000 je 1,5×.

roles seznam: Role
people seznam: Assignment

people is everyone with an assignment on the shift, in the order they were asked: invited, accepted, declined, lapsed, withdrawn, cancelled. Only accepted fills a place.

Person on a project personOnProject

One person with live places on a project's upcoming shifts.

PoleTypCo to je
membership_id celé číslo
name řetězec
accepted celé číslo

accepted and pending are their upcoming places: what they agreed to, and what is still waiting on an answer. Never merged: an invitation staffs nothing.

pending celé číslo
first_start časový údaj, RFC 3339 v UTC

first_start and last_start are the earliest and latest of those shifts.

last_start časový údaj, RFC 3339 v UTC

Taken off a project takenOff

What taking somebody off a project did, or would do.

PoleTypCo to je
confirmed boolean

confirmed is false for a preview, in which nothing changed.

accepted celé číslo

accepted and pending are the places cancelled: work they had agreed to, and invitations or applications still open.

pending celé číslo
first_day řetězec

first_day is the earliest cancelled shift's day on site, "2026-10-29".

Shift as a manager sees it shiftResponse

A shift as a manager reads it: the shift, how short it is, whether it is open to the company, and its roles.

PoleTypCo to je
id celé číslo
gig_id celé číslo
day_id celé číslo
starts_at časový údaj, RFC 3339 v UTC
ends_at časový údaj, RFC 3339 v UTC
required_workers celé číslo
role_label řetězec, nebo null

role_label is the one-string summary of Roles ("2× crane op, 3× labourer"; a single named role is its label alone; the unnamed role of a plain shift is nil), written by this service in the same transaction as the lines. It is what the app and most screens show of the roles.

created_at časový údaj, RFC 3339 v UTC
accepted celé číslo

Staffing is filled by the reads that compute it. accepted is what fills the slot; pending is what a PM still has no answer on. Short is the places nobody has accepted, counted ROLE BY ROLE: a labourer too many does not stand in for the crane op who is missing. Off the wire: the clients are told what follows from it (full, which open shifts are takeable), never asked to count.

pending celé číslo
short celé číslo

short is the places nobody has accepted, counted role by role: a labourer too many does not stand in for the crane op who is missing.

is_open boolean

is_open says the shift is advertised to the company, so any worker there may take a place without being invited. open_auto_accept says a taker is confirmed outright; otherwise they land as an applicant for the manager to approve.

open_auto_accept boolean
offered_rate_multiplier celé číslo, nebo null

offered_rate_multiplier raises each taker's usual rate, with four implied decimals: 15000 is 1.5×. Null when the shift offers each role's rate as it stands. An SOS is an open shift with this set.

Násobek se čtyřmi skrytými desetinnými místy: 15000 je 1,5×.

roles seznam: Role

SOS raised sosRaised

One emergency opened on one shift.

PoleTypCo to je
id celé číslo
timeslot_id celé číslo
offered_rate_multiplier celé číslo

offered_rate_multiplier is the raise, with four implied decimals.

Násobek se čtyřmi skrytými desetinnými místy: 15000 je 1,5×.

opened_at časový údaj, RFC 3339 v UTC
told celé číslo

told is how many people were told, each once: every worker at the company who opted into emergency cover and could take it.

SOS over a project sosBatch

What an SOS over several shifts did.

PoleTypCo to je
raised seznam: SOS raised

raised is the emergency opened on each shift, earliest first.

already_raised celé číslo

What was skipped and why: an SOS already running, every place taken meanwhile, the shift over.

filled celé číslo
over celé číslo
told celé číslo

told is how many people were told, each once for the whole batch.

Shift needing attention shortShift

An upcoming shift that needs a manager's attention.

PoleTypCo to je
id celé číslo
gig_id celé číslo
day_id celé číslo
starts_at časový údaj, RFC 3339 v UTC
ends_at časový údaj, RFC 3339 v UTC
required_workers celé číslo
role_label řetězec, nebo null

role_label is the one-string summary of Roles ("2× crane op, 3× labourer"; a single named role is its label alone; the unnamed role of a plain shift is nil), written by this service in the same transaction as the lines. It is what the app and most screens show of the roles.

created_at časový údaj, RFC 3339 v UTC
accepted celé číslo

Staffing is filled by the reads that compute it. accepted is what fills the slot; pending is what a PM still has no answer on. Short is the places nobody has accepted, counted ROLE BY ROLE: a labourer too many does not stand in for the crane op who is missing. Off the wire: the clients are told what follows from it (full, which open shifts are takeable), never asked to count.

pending celé číslo
gig_title řetězec
short celé číslo

short is the places nobody has accepted, role by role.

sos_open boolean

sos_open says an emergency is already running on it, so no second one is raised.

roles seznam: Role
company Company tag, nebo null

company is which of the caller's entries the shift came from, on a list across them and nowhere else.

V těle chybí, když je prázdné.

Person response personResponse

One person on the roster: the membership, and the company's "certified for" notes about them.

PoleTypCo to je
id celé číslo
is_manager boolean
is_worker boolean
rate_amount celé číslo, nebo null

The default rate for new agreements at this company. Assignments and time entries snapshot their own copy; changing this never alters past work. Null for somebody who does not work shifts.

Peníze: celé číslo se čtyřmi skrytými desetinnými místy, takže 4200000 je 420,00, a vedle něj měna.

rate_currency řetězec, nebo null
emergency_responses_enabled boolean
cancellation_emails_enabled boolean

cancellation_emails_enabled: a cancelled accepted shift is emailed as well as pushed. On by default; only the worker turns it off.

is_disabled boolean
created_at časový údaj, RFC 3339 v UTC
org_name řetězec
first_name řetězec
last_name řetězec
email řetězec
certifications seznam: Certification response

certifications is what this company has noted the person as certified for, oldest first. Empty for nobody noted. A note is the company's own and requires nothing: nothing is filtered by it.

Certification response certificationResponse

One "certified for" note, with the kind's name in the request's language.

PoleTypCo to je
id celé číslo
membership_id celé číslo
kind řetězec

kind is the kind's id from the list of certificate kinds, or "other_personal" with a label.

label řetězec, nebo null

label says what an "other" certification is for; null for a listed kind, whose name the list gives.

scope řetězec, nebo null
expires_on řetězec, nebo null

expires_on is the day it stops being valid, "2027-06-30", or null for unknown; never "for ever".

granted_by_membership_id celé číslo

granted_by_membership_id is the manager who made the note, by membership id, and granted_by_name their name, or "Deleted user".

granted_by_name řetězec
created_at časový údaj, RFC 3339 v UTC
certificate_id celé číslo, nebo null

certificate_id is the person's certificate the note was approved from (step 97b), or null for a note made with no proof, or one whose certificate the person has since deleted.

name řetězec

name is what the note is for, in words: the kind's name, or the typed label of a note whose kind is other_personal.

Certificate response certificateResponse

One certificate, with the kind's name in the request's language.

PoleTypCo to je
id celé číslo
kind řetězec

kind is the kind's id from the list of certificate kinds, or "other_personal" with a label.

label řetězec, nebo null

label says what an "other" certificate is; null for a listed kind.

scope řetězec, nebo null
number řetězec, nebo null

number is what is printed on the card, as typed.

issued_on řetězec, nebo null

issued_on and expires_on are calendar days, "2027-06-30", or null. A null expiry is unknown, never "for ever".

expires_on řetězec, nebo null
pages seznam: Certificate page

pages are the photos, in order, without their bytes: each page is read on its own by position.

uploaded_by Uploaded by, nebo null

uploaded_by is the manager who added it on the person's behalf, or null for one the person added. A manager at another company is shown null here too: which other firms somebody works for is not theirs to learn from a photo's byline.

created_at časový údaj, RFC 3339 v UTC
updated_at časový údaj, RFC 3339 v UTC
name řetězec

name is what the certificate is, in words: the kind's name, or the typed label of one whose kind is other_personal.

Certificate kinds certificateKinds

The list of kinds, in the request's language.

PoleTypCo to je
groups seznam: Certificate group

groups are the headings kinds are listed under, in order.

kinds seznam: Certificate kind

kinds are every kind, in the list's own order.

trades seznam: Certificate trade

trades are lines of work, each with the kinds it offers first, the ones its activities may need, and the ones anybody may hold. A trade is a way of ordering the list and is stored nowhere.

Certificate reading certificateReading

What the photos of one document say, as far as they can be read: a proposal for each field, null where the pages gave nothing, and how well each page read. Every field is a proposal for the person to check and change; none of it is stored until they save.

PoleTypCo to je
kind řetězec, nebo null

kind is the kind of document the words point to, as a kind's id from the certificate kinds endpoint, or null when no kind stood out. Never other_personal.

kind_name řetězec, nebo null

kind_name is that kind's name in the request's language, or null.

issued_on řetězec, nebo null

issued_on and expires_on are the dates found on the pages, "2024-05-02", or null: the date after "platnost do" or "valid until" is the expiry, the one after "vydáno" or "issued" the issue date; without such a word the later of two dates is the expiry and the earlier the issue date, and a lone date still ahead is the expiry.

expires_on řetězec, nebo null
number řetězec, nebo null

number is the number printed after "č." or "No.", or null.

pages seznam: Page reading

pages says how well each page read, in the order sent.

legible boolean

legible is true when every page read well. A page that did not can still be kept; the client says it is hard to read and suggests taking the photo again.

Client services.Client

A company you invoice.

The tax identifiers are here because invoicing is planned and a Czech invoice is not valid without them.

PoleTypCo to je
id celé číslo
name řetězec
ico řetězec, nebo null

IČO, the Czech company registration number: eight digits including any leading zeros, hence text. Null for a private individual.

dic řetězec, nebo null

DIČ, the VAT number, e.g. "CZ12345678". Null when not VAT registered.

address_line1 řetězec, nebo null
address_line2 řetězec, nebo null
city řetězec, nebo null
postal_code řetězec, nebo null
country řetězec
contact_name řetězec, nebo null
contact_email řetězec, nebo null
contact_phone řetězec, nebo null
is_archived boolean
created_at časový údaj, RFC 3339 v UTC

Hours row hoursRow

One time entry on a project, with who worked it.

PoleTypCo to je
id celé číslo
membership_id celé číslo
gig_id celé číslo
timeslot_id celé číslo, nebo null

timeslot_id is null for a stand-alone entry, which is normal rather than an error: someone who worked on a day nobody planned still worked.

clock_in_at časový údaj, RFC 3339 v UTC
clock_out_at časový údaj, RFC 3339 v UTC, nebo null

clock_out_at is null while the worker is still on site — and also when they forgot. The two are indistinguishable, and nothing here guesses.

source řetězec: manual | geofence | backfilled
rate_amount celé číslo, nebo null

rate_amount is snapshotted at creation: from the assignment when the entry linked to one, otherwise the usual rate at that moment — the project's, else the membership's. Never recomputed.

Null when no hourly rate applied: the hours are recorded and the entry is worth no money figure — not zero, which would read as unpaid work.

Peníze: celé číslo se čtyřmi skrytými desetinnými místy, takže 4200000 je 420,00, a vedle něj měna.

rate_currency řetězec, nebo null
client_event_id řetězec

client_event_id is the device's own id for this event, and the reason a retried push from a phone that was offline creates one row rather than two. Empty for entries created server-side.

V těle chybí, když je prázdné.

corrected_at časový údaj, RFC 3339 v UTC, nebo null
created_at časový údaj, RFC 3339 v UTC
worker_name řetězec

worker_name is who clocked the hours.

slot_starts_at časový údaj, RFC 3339 v UTC, nebo null

slot_starts_at and slot_ends_at are the shift the entry linked to, or null for hours worked outside any shift, which is normal and not an error.

slot_ends_at časový údaj, RFC 3339 v UTC, nebo null
recorded_by řetězec

recorded_by names the manager who entered the hours for somebody added to a shift afterwards, and is empty for hours the worker clocked.

Entry membershipResponse

What a client needs to render "who am I, and where": one entry of the company switcher.

An entry is a membership in ONE role, and its identity is the pair (membership_id, role). Somebody who manages projects and works shifts at one company appears twice in memberships, with the same membership_id and a different role, and membership is the one of the two the session is in. role stays a single string, so a client that asks "is this a manager" has one answer per entry.

It carries no organization id a client could send back: switching names a membership and a role, and the server proves the caller holds both.

PoleTypCo to je
membership_id celé číslo
org_name řetězec
role řetězec
first_name řetězec
last_name řetězec
emergency_responses_enabled boolean

The worker's own opt-in to emergency cover, per membership: they may want emergency shifts from one employer and not another. This only ever describes the caller's own memberships — there is no endpoint that tells a manager who has opted in.

cancellation_emails_enabled boolean

Whether a cancelled accepted shift is emailed too, on top of the push. The worker's own setting, like the one above, and only ever describing the caller's own memberships.

Leaving company services.LeavingCompany

What deleting an account does at one of the companies the person belongs to. It only ever describes the caller's own memberships.

PoleTypCo to je
org_name řetězec
upcoming_shifts celé číslo

upcoming_shifts they have accepted and will be withdrawn from. invitations (and applications) not answered yet, which will be declined. Both count only shifts that have not started.

invitations celé číslo
clocked_in boolean

clocked_in: an entry here has no clock-out. It is left open, for a manager to settle, and the person is told so they can clock out first.

last_manager boolean

last_manager: they are the only manager this company has. That refuses the deletion, exactly as it refuses demoting or disabling them: there is no platform admin to let anybody back in.

Worker dashboard services.WorkerDashboard

"this week, this much, what is open" — and it is where the worker's schedule lives. On Monday morning they do not yet know which project to open, so the cross-project week has to be here.

Shifts are grouped on the server so both clients put the same shift under the same heading: which group something is in is a decision, not styling.

PoleTypCo to je
awaiting_you seznam: Schedule entry

awaiting_you are invitations the worker has not answered, whenever they are. They lapse on their own at the shift's start and reopen a vacancy, so they lead.

One project's invitations sit together: the projects in the order of their earliest shift, and each project's shifts in the order they happen. A manager can invite somebody to a week in one go, and both clients draw a project's run under one heading with "Accept all" beside it — by starting a new heading wherever gig_id changes, so the grouping is decided here and neither client sorts anything.

invitation_summaries seznam: Invitation summary

invitation_summaries says what each project's run of awaiting_you adds up to: one per project, in the order the projects appear there. Both clients show a project with several invitations as its summary, with the shifts folded away under it, so a week of invitations is one thing to answer and not seven rows to scroll past.

this_week seznam: Schedule entry

this_week is every other assignment on a shift within Days, in any state — booked, applied for, and also cancelled or given up, because a cancelled shift must be obvious rather than silently absent. It is named for the default range; asked for two weeks, it holds two.

later seznam: Schedule entry

later is what lies beyond the range that is still live, plus anything a manager cancelled. The worker's own declines are left out: they know.

open_shifts seznam: Open shift

open_shifts are shifts at the company a PM opened that this worker could take now, each with the figure they would be paid and whether taking it books them outright. Ones they already hold are in their shifts instead.

expiring_certificates seznam: Expiring certificate

expiring_certificates is the worker's own certificates that expire within 30 days or have expired, soonest first. Derived from each one's expires_on on every read; nothing stores that one was seen. A certificate with no expiry on record is never here. Empty for nothing expiring.

worked_this_week Worked

Earned is from time entries; still_to_earn from accepted assignments. Two tables, two snapshots, neither the membership rate. The worked figures are the calendar week and month whatever range is shown: the range is how far ahead to look, and hours already worked are behind.

worked_this_month Worked
still_to_earn seznam: Money total
still_to_earn_unrated_minutes celé číslo

still_to_earn_unrated_minutes is accepted work ahead with no hourly rate agreed, and so in none of still_to_earn.

Manager dashboard services.ManagerDashboard

What needs a PM's attention, then the week in numbers.

PoleTypCo to je
attention seznam: Short shift

attention is upcoming shifts short of accepted workers or waiting on somebody's answer. Unanswered invitations count: on an imminent shift they are as urgent as an empty place.

attention_summaries seznam: Attention summary

attention_summaries says what each project's run of attention adds up to: one per project, in the order the projects appear there. Both clients show a project with several shifts needing attention as its summary, with the shifts folded away under it, matching worker invitations.

turned_down seznam: Decline

turned_down is who said no, recently, to a shift still short.

hours_to_check seznam: Flagged entry

hours_to_check are time entries somebody should ask about.

week seznam: Day staffing

week is the company's staffing for each of Days — the whole range, whatever its length, despite the name.

worked_this_week Worked

worked_this_week is every worker's finished hours this calendar week, at the rates agreed for them, whatever range is shown.

Shift services.Timeslot

A block of work on one day needing some number of workers.

PoleTypCo to je
id celé číslo
gig_id celé číslo
day_id celé číslo
starts_at časový údaj, RFC 3339 v UTC
ends_at časový údaj, RFC 3339 v UTC
required_workers celé číslo
role_label řetězec, nebo null

role_label is the one-string summary of Roles ("2× crane op, 3× labourer"; a single named role is its label alone; the unnamed role of a plain shift is nil), written by this service in the same transaction as the lines. It is what the app and most screens show of the roles.

created_at časový údaj, RFC 3339 v UTC
accepted celé číslo

Staffing is filled by the reads that compute it. accepted is what fills the slot; pending is what a PM still has no answer on. Short is the places nobody has accepted, counted ROLE BY ROLE: a labourer too many does not stand in for the crane op who is missing. Off the wire: the clients are told what follows from it (full, which open shifts are takeable), never asked to count.

pending celé číslo

Job contact services.JobContact

The one person a worker is told to ring about a job.

A worker standing at a locked gate needs a number, not a screen telling them to find one — and it has to be the right number.

PoleTypCo to je
company řetězec, nebo null

company is the client's name when this is the client's own contact, and null when a manager named the person for the site: a foreman or a caretaker is not said to answer for the customer. It can be all there is — a client with no contact person — because somebody holding only the company's name can still find a number.

name řetězec, nebo null
phone řetězec, nebo null

Project manager services.ProjectManager

How somebody working on a project reaches the manager who runs it: a name to ask for and the two ways to get hold of them.

Deliberately nothing else from the membership. A worker reads this, and a manager's rate, role history or other projects are none of their business. The phone and email are the person's own, from users, because that is the only place this product keeps them.

PoleTypCo to je
name řetězec
phone řetězec, nebo null
email řetězec, nebo null

Company tag companyTag

Says which of the person's entries a row of a read across them came from, and what to send to act on it.

PoleTypCo to je
entry řetězec

entry is the value of X-Werzeick-Company (or the MCP's company) that acts as this entry: "12:manager".

org_name řetězec
role řetězec

Money total services.MoneyTotal

A sum in one currency.

Currencies are never mixed, and never converted: this product holds no exchange rate and inventing one would be inventing money. A company working in two currencies sees two totals.

The amount goes raw as an int64 with four implied decimals, never pre-formatted and never a float.

PoleTypCo to je
amount celé číslo

Peníze: celé číslo se čtyřmi skrytými desetinnými místy, takže 4200000 je 420,00, a vedle něj měna.

currency řetězec

Running shift services.RunningShift

A shift the acting worker is on the clock for right now, and what it has come to so far.

It is the one figure in this product about work that is not finished, and three things keep it honest:

  • No client multiplies anything, and the membership's rate today has no part in it.
  • It is "so far", and it is in no total. So a figure a worker has seen in a total never goes down because they clocked out and then corrected the entry.
  • A forgotten clock-out has none.
PoleTypCo to je
since časový údaj, RFC 3339 v UTC

since is when they clocked in.

minutes celé číslo
amount celé číslo, nebo null

amount is those minutes at the entry's snapshotted rate. Null, with currency, when no hourly rate was agreed: hours and no money figure, never zero.

Peníze: celé číslo se čtyřmi skrytými desetinnými místy, takže 4200000 je 420,00, a vedle něj měna.

currency řetězec, nebo null
as_of časový údaj, RFC 3339 v UTC

as_of is the server's clock when this was worked out. The figure is true of that minute and of no later one.

Skipped invitation skippedInvite

A person already live on a shift, so not asked again.

PoleTypCo to je
membership_id celé číslo
worker_name řetězec
shift Shift reference

Over-invited shift overInvited

A shift asked of more people than it has places: allowed, since some will say no, and said.

PoleTypCo to je
shift Shift reference
invited celé číslo
places celé číslo

Overlapping invitation inviteClash

A person asked to a shift that overlaps other work of theirs at this company: allowed, and said.

PoleTypCo to je
membership_id celé číslo
worker_name řetězec
shift Shift reference
with Shift reference

with is the shift it overlaps; in_batch says that one is in this very batch rather than already on their schedule.

in_batch boolean

Certificate page services.CertificatePage

One photo of a certificate, by position, without its bytes.

PoleTypCo to je
position celé číslo
content_type řetězec
width celé číslo
height celé číslo

Uploaded by services.UploadedBy

Names the manager who added a certificate, and at which company. The name reads "Deleted user" for one who has left.

PoleTypCo to je
membership_id celé číslo
name řetězec
company řetězec

Certificate group certificateGroup

PoleTypCo to je
id řetězec
name řetězec

Certificate kind certificateKind

PoleTypCo to je
id řetězec

id is what a note or a certificate carries as its kind.

name řetězec
group řetězec

group is the heading it is listed under, by the group's id.

aliases seznam: řetězec

aliases are the words people use for it, in Czech, for a search.

Certificate trade certificateTrade

PoleTypCo to je
id řetězec
name řetězec
preferred seznam: řetězec

preferred, related and common are kinds by id, in the order to offer them for this trade.

related seznam: řetězec
common seznam: řetězec

Page reading pageReading

How well one page read.

PoleTypCo to je
position celé číslo

position is the page's place among those sent, counted from 1.

readability celé číslo, nebo null

readability is how sure the reader is of the words it found, 0 to 100, or null for a page it could not read at all.

legible boolean

legible is whether the page read well enough to trust: enough words, at 60 or more.

Invitation summary services.InvitationSummary

What one project's unanswered invitations add up to: how many, which days, how long, and what they would pay.

It is worked out here and not in a client because one of its figures is money.

Nothing stores that invitations were sent together, so this is every invitation the worker has not answered on the project, read now. It is the same set "Accept all" and "Decline all" act on.

PoleTypCo to je
gig_id celé číslo
gig_title řetězec
count celé číslo

count is how many invitations are waiting on the project. full_count is how many of those are to a shift with no place left, which cannot be accepted until one opens. They are in every figure below all the same: the summary says what was asked, and full_count is what lets a client say that part of it cannot be taken yet.

full_count celé číslo
first_day řetězec

first_day and last_day are the dates, on site, the earliest and the latest shift start on, as YYYY-MM-DD. Equal when every shift is on one day. Dates and not instants, so a client prints them without deciding which zone a day is in; a night shift belongs to the day it starts.

last_day řetězec
shift_summary řetězec

shift_summary is a brief dynamic summary of the shifts: which days carry which hours and which days are off, e.g. "Shifts Mon - Fri, 07:00 - 15:00, Sat 07:00 - 12:00; Sundays off" or "Shifts Mon - Fri, 07:00 - 15:00; weekends off".

V těle chybí, když je prázdné.

minutes celé číslo
would_earn seznam: Money total

would_earn is what accepting every one of them would come to, a total per currency. unrated_minutes is the part of minutes on invitations with no hourly rate agreed, and so in none of would_earn: empty totals beside unrated minutes is "no hourly rate", never zero.

unrated_minutes celé číslo

Open shift services.OpenSlotRow

One ROLE on a shift a worker could take: a shift with two roles is two rows, each with its own places, label and figure, because taking is per role.

PoleTypCo to je
id celé číslo
gig_id celé číslo
day_id celé číslo
starts_at časový údaj, RFC 3339 v UTC
ends_at časový údaj, RFC 3339 v UTC
required_workers celé číslo
role_label řetězec, nebo null

role_label is the one-string summary of Roles ("2× crane op, 3× labourer"; a single named role is its label alone; the unnamed role of a plain shift is nil), written by this service in the same transaction as the lines. It is what the app and most screens show of the roles.

created_at časový údaj, RFC 3339 v UTC
accepted celé číslo

Staffing is filled by the reads that compute it. accepted is what fills the slot; pending is what a PM still has no answer on. Short is the places nobody has accepted, counted ROLE BY ROLE: a labourer too many does not stand in for the crane op who is missing. Off the wire: the clients are told what follows from it (full, which open shifts are takeable), never asked to count.

pending celé číslo
gig_title řetězec
role_id celé číslo

role_id is the role this row offers, and what a take names.

rate_amount celé číslo, nebo null

rate_amount is what THIS worker would be paid for it: the role's rate, else the usual rate — the project's, else their own — raised by the shift's multiplier where it has one, capped by the project. Resolved server-side for the same reason it is resolved at signup: nobody takes a shift without seeing the figure, and the figure is not a client's to decide.

Null when the shift offers nothing and there is no usual rate either: taking it records hours with no hourly rate, which is a real state.

Peníze: celé číslo se čtyřmi skrytými desetinnými místy, takže 4200000 je 420,00, a vedle něj měna.

rate_currency řetězec, nebo null
mine_status řetězec: pending | accepted | declined | expired | withdrawn | cancelled

mine_status is the worker's own live place on this shift, when they have one: 'accepted' if they are on it, 'pending' if they applied and the PM has not picked yet. Empty when they hold neither.

The two are not the same thing to the person reading it — one is work they have, the other is work they might get — and a screen collapsing both into "taken" would be promising somebody a shift nobody has agreed they are doing.

taking_confirms boolean

taking_confirms is the slot's auto-accept flag, under a name that says what it means to the person about to tap: taking it books them outright, or lands them as an applicant the PM picks from. The terms are part of the offer, like the figure, and nobody takes a shift without both.

collides_with_title řetězec, nebo null

Shift conflicts, the same fields a worker's own schedule entry carries and for the same reason: said here so neither client works it out, and nobody taps a take that can only be refused.

collides_with_company řetězec, nebo null

collides_with_company names the company the colliding shift is at when that is another of the worker's companies, and is null for this company's own: the clients say "at Beta" only then.

collides_from časový údaj, RFC 3339 v UTC, nebo null
collides_until časový údaj, RFC 3339 v UTC, nebo null
can_take_from časový údaj, RFC 3339 v UTC, nebo null
can_take_until časový údaj, RFC 3339 v UTC, nebo null

Expiring certificate services.ExpiringCertificate

One of the person's own certificates that is expiring or has expired, as the worker's dashboard and bell list it.

PoleTypCo to je
id celé číslo
kind řetězec
label řetězec, nebo null

label is the typed name of an "other" certificate, null otherwise.

name řetězec

name is what it is, in words, in the request's language: the kind's name or the label. The server words it, as the certificates list does; a client never looks a kind up for itself.

expires_on řetězec

expires_on is the last valid day, "2026-11-20".

days_left celé číslo

days_left is whole days until then: 0 on the day, negative once past.

expired boolean

expired says the day has passed; otherwise it is within the window.

Worked services.Worked

Hours on the clock in some period, and what they came to.

Open entries count for neither: a shift in progress has no length yet, and a forgotten clock-out is a discrepancy for a PM, not a number to estimate.

PoleTypCo to je
minutes celé číslo
earned seznam: Money total
unrated_minutes celé číslo

unrated_minutes are the part of minutes worked with no hourly rate, and so in none of earned. Zero at a firm where everybody has one.

Short shift services.VacancyRow

One upcoming timeslot that a PM should look at, with enough context to act on it without a second query.

PoleTypCo to je
id celé číslo
gig_id celé číslo
day_id celé číslo
starts_at časový údaj, RFC 3339 v UTC
ends_at časový údaj, RFC 3339 v UTC
required_workers celé číslo
role_label řetězec, nebo null

role_label is the one-string summary of Roles ("2× crane op, 3× labourer"; a single named role is its label alone; the unnamed role of a plain shift is nil), written by this service in the same transaction as the lines. It is what the app and most screens show of the roles.

created_at časový údaj, RFC 3339 v UTC
accepted celé číslo

Staffing is filled by the reads that compute it. accepted is what fills the slot; pending is what a PM still has no answer on. Short is the places nobody has accepted, counted ROLE BY ROLE: a labourer too many does not stand in for the crane op who is missing. Off the wire: the clients are told what follows from it (full, which open shifts are takeable), never asked to count.

pending celé číslo
gig_title řetězec

Attention summary services.AttentionSummary

What one project's upcoming shifts needing attention add up to: how many, which days, dynamic shift schedule, and staffing counts (accepted, required, pending, vacancies).

PoleTypCo to je
gig_id celé číslo
gig_title řetězec
count celé číslo
first_day řetězec
last_day řetězec
shift_summary řetězec

V těle chybí, když je prázdné.

required celé číslo
accepted celé číslo
pending celé číslo
short celé číslo
imminent boolean

Decline services.TurnedDownRow

Somebody saying no to work a PM was counting on: an invitation declined, or an accepted shift given up.

PoleTypCo to je
id celé číslo
timeslot_id celé číslo
membership_id celé číslo
origin řetězec: staffed | sos | open | backfilled
status řetězec: pending | accepted | declined | expired | withdrawn | cancelled
rate_amount celé číslo, nebo null

rate_amount is the rate agreed for THIS assignment, snapshotted when the invitation was created. Never recompute it from the project or the membership: editing either rate must not change what already-promised work is worth.

Null when no hourly rate was agreed — the project sets none and neither does the worker. That is a real state, "hours only", and never a zero, which would read as unpaid work. Both halves are null together; the database refuses one without the other.

Peníze: celé číslo se čtyřmi skrytými desetinnými místy, takže 4200000 je 420,00, a vedle něj měna.

rate_currency řetězec, nebo null
role_id celé číslo

role_id is the role on the shift this assignment fills: where its rate came from, and whose places it takes one of. role_label is that role's name, filled by the reads a person sees it through (the schedule, the staffing screen); nil for the unnamed role of a plain shift, and on a write's answer, which does not join it.

role_label řetězec, nebo null
invited_at časový údaj, RFC 3339 v UTC
responded_at časový údaj, RFC 3339 v UTC, nebo null
expires_at časový údaj, RFC 3339 v UTC
created_at časový údaj, RFC 3339 v UTC
takes_from časový údaj, RFC 3339 v UTC, nebo null

takes_from/takes_until are the part of the shift the worker agreed to work, where they took it PARTIALLY around a colliding accepted shift. Nil is the whole shift, the ordinary case. Computed server-side at the moment of taking — never sent by a client — and settled then: a colliding shift later given up does not widen it.

takes_until časový údaj, RFC 3339 v UTC, nebo null
worker_name řetězec

worker_name is filled by reads a PM makes, so a staffing view can show who was invited without a second query per row.

V těle chybí, když je prázdné.

timeslot Shift
gig_title řetězec

Flagged entry services.FlaggedEntry

One time entry a manager should look at, from any project.

The flags are decided here, on the server, so both clients show the same reason.

PoleTypCo to je
entry Time entry
worker_name řetězec
gig_title řetězec
slot_starts_at časový údaj, RFC 3339 v UTC, nebo null
slot_ends_at časový údaj, RFC 3339 v UTC, nebo null
missing_clock_out boolean
outside_shift boolean

Day staffing services.DayStaffing

One calendar day's staffing, summed across its timeslots.

This is what turns the calendar from "which days does this run" into "which days need me". A day is the unit a PM actually thinks in — they staff a week, not a timeslot — so the counts are aggregated to the day and the calendar renders them directly.

PoleTypCo to je
day řetězec

YYYY-MM-DD

slots celé číslo
required celé číslo
accepted celé číslo
pending celé číslo
short celé číslo

short is the day's places nobody has accepted, summed over its shifts role by role: never required less accepted, which a labourer too many on one shift would flatter.

Shift reference shiftRef

One shift, as a batch's answer names it.

PoleTypCo to je
timeslot_id celé číslo
starts_at časový údaj, RFC 3339 v UTC
ends_at časový údaj, RFC 3339 v UTC