Uptime-check. Geen authenticatie.
Respons 200
{
"success": true,
"status": "ok",
"version": "v1",
"time": "2026-08-08T14:23:00Z"
}
Publieke REST API
Een stateless, met API-sleutel geauthenticeerde REST API voor integraties van derden. Lees de medewerkers, vestigingen en prestatiegegevens van je bedrijf. Elke respons is JSON.
Alle endpoints staan onder versie /v1. Elke aanvraag moet in productie via HTTPS gebeuren.
HTTP Basic Auth via HTTPS. Stuur een Authorization-header met je sleutel-ID en secret, base64-gecodeerd:
Authorization: Basic base64(KEY_ID:SECRET)
| Credential | Formaat | Opmerkingen |
|---|---|---|
KEY_ID | TK_PUB_LIVE_… (28) | Publieke identificator, hoofdletters, 16-hex staart. Veilig om te loggen. |
SECRET | TK_SEC_LIVE_… (60) | Privé. Wordt exact één keer getoond bij aanmaak; alleen een SHA-256-hash wordt bewaard — onherstelbaar als je hem kwijt bent. |
Bij een mislukte authenticatie volgt 401 unauthorized. De API maakt nooit onderscheid tussen een foute sleutel en een foute secret, om enumeratie te voorkomen.
curl -u TK_PUB_LIVE_A1B2C3D4E5F60718:TK_SEC_LIVE_… \
https://api.tikklok.app/v1/me
| Bereik | Limiet |
|---|---|
| Per sleutel | 60 aanvragen / minuut · 1000 / uur (vaste vensters) |
| Per IP, vóór auth | 20 aanvragen / minuut (voordat Basic Auth wordt gecontroleerd) |
| Per IP, mislukte auth | 10 mislukkingen / minuut → tijdelijke blokkade |
Bij overschrijding volgt 429 rate_limited. Wacht een minuut en probeer opnieuw.
Elke respons is JSON met een success-boolean. Fouten dragen ook een korte machineleesbare error-string. Reads geven nooit success: false bij ontbrekende data — een 404-body betekent dat de resource zelf ontbrak. Elke respons draagt Cache-Control: no-store.
| Status | error | Betekenis |
|---|---|---|
| 400 | invalid_role | Onbekende role-filterwaarde. |
| 400 | invalid_date | Ontbrekende/ongeldige datum, of min_date > max_date. |
| 400 | range_too_large | Prestatieperiode langer dan 366 dagen. |
| 401 | unauthorized | Ontbrekende of ongeldige gegevens. |
| 402 | subscription_required | Bedrijf heeft geen actief (betaald) abonnement — de gratis proefperiode geeft geen API-toegang (elk endpoint behalve /v1/me). |
| 404 | not_found | Resource ontbreekt — of hoort bij een ander bedrijf (niet te onderscheiden, met opzet). |
| 413 | payload_too_large | Aanvraagbody groter dan 1 MB. |
| 429 | rate_limited | Rate limit overschreden. |
Elke aanvraag is beperkt tot het bedrijf dat de API-sleutel bezit. Resources worden geadresseerd met hun globale ID's:
| ID | Betekenis |
|---|---|
company_user_id | Een persoon in je bedrijf (de „medewerker”-identiteit). Stabiel, globaal uniek. |
location_id | Eén van de vestigingen van je bedrijf. Stabiel, globaal uniek. |
locations[] van elke medewerker bevat de location_user_id — de interne toewijzingssleutel — waarmee je klokgebeurtenissen voor die medewerker op die vestiging aanstuurt. Padparameters adresseren een toewijzing nog steeds met het paar (company_user_id, location_id). Een ID in een pad dat niet bij je bedrijf hoort, geeft 404 not_found — identiek aan een onbestaand ID, zodat vreemde ID's niet afgetast kunnen worden. Aanvraagbodies moeten ≤ 1 MB zijn (anders 413 payload_too_large).De meeste endpoints zijn GET-reads. Er is één write-endpoint (POST /v1/pos/clock-events) dat uitsluitend voor Onlinefact bedoeld is. Elk endpoint behalve /v1/health vereist authenticatie.
Uptime-check. Geen authenticatie.
{
"success": true,
"status": "ok",
"version": "v1",
"time": "2026-08-08T14:23:00Z"
}
Bevestigt dat je gegevens werken en toont bij welk bedrijf ze horen.
{
"success": true,
"company_id": 1,
"company_name": "Acme Corp",
"key_id": "TK_PUB_LIVE_A1B2C3D4E5F60718",
"key_name": "My Slack integration"
}
Gepagineerde lijst van de mensen in je bedrijf (company_users), elk met een beknopte lijst van de vestigingen waaraan ze actief zijn toegewezen. Owners/admins verschijnen ook, met een lege locations-array als ze geen toewijzingen hebben.
| Param | Standaard | Opmerkingen |
|---|---|---|
limit | 100 | Begrensd tot 1–500. |
offset | 0 | Voor paginering. |
location_id | — | Alleen medewerkers die actief aan deze vestiging zijn toegewezen. |
role | — | Bedrijfsrol: owner, admin, employee. Ongeldig → 400 invalid_role. |
include_inactive | 0 | 1 om gedeactiveerde medewerkers mee te nemen. |
{
"success": true,
"total": 25,
"limit": 100,
"offset": 0,
"data": [
{
"company_user_id": 42,
"first_name": "Jane",
"last_name": "Doe",
"is_active": true,
"locations": [
{ "location_user_id": 15, "location_id": 7, "location_name": "Main Store" }
]
}
]
}
Volledige details van één medewerker plus elke vestigingstoewijzing (actief en historisch — elk met zijn eigen is_active). Elke toewijzing bevat zijn location_user_id (de toewijzingssleutel, voor klokgebeurtenissen via de API). 404 not_found als de medewerker niet in je bedrijf zit.
{
"success": true,
"data": {
"company_user_id": 42,
"first_name": "Jane",
"last_name": "Doe",
"email": "jane@example.com",
"tel": "+32 470 00 00 00",
"role": "employee",
"status": "active",
"is_active": true,
"created": "2025-01-15 10:30:00",
"updated": "2025-08-27 14:22:15",
"locations": [
{
"location_user_id": 15,
"location_id": 7,
"location_name": "Main Store",
"role": "staff",
"function_id": 3,
"function_name": "Sales",
"is_user_primary": true,
"clocking_allowed": true,
"valid_from": null,
"valid_to": null,
"is_active": true
}
]
}
}
De toewijzing van één medewerker op één vestiging. 404 not_found als de medewerker niet in je bedrijf zit, de vestiging niet in je bedrijf zit, of er geen toewijzing tussen beide bestaat.
{
"success": true,
"data": {
"company_user_id": 42,
"location_user_id": 15,
"location_id": 7,
"location_name": "Main Store",
"role": "staff",
"function_id": 3,
"function_name": "Sales",
"is_user_primary": true,
"clocking_allowed": true,
"valid_from": null,
"valid_to": null,
"is_active": true,
"created": "2025-01-15 10:30:00",
"updated": "2025-08-27 14:22:15"
}
}
Dezelfde prestatiegegevens als het downloadbare rapport van het dashboard, als JSON, gegroepeerd per vestiging. Voor elke vestiging waaraan de medewerker is (of was) toegewezen, een opsplitsing per dag plus opgetelde totals. Alle cijfers zijn uren (2 decimalen); overtime_hours kan negatief zijn (te weinig gewerkt).
expected_hours = planned − closed − location_holiday − user_holiday − sick · overtime_hours = worked − expected
| Param | Opmerkingen |
|---|---|
min_date | YYYY-MM-DD |
max_date | YYYY-MM-DD, ≥ min_date |
Ongeldige/ontbrekende datum of min_date > max_date → 400 invalid_date. Een periode langer dan 366 dagen → 400 range_too_large. 404 not_found als de medewerker niet in je bedrijf zit. Een medewerker zonder data in de periode geeft 200 met een lege locations-array.
{
"success": true,
"data": {
"company_user_id": 42,
"employee_name": "Jane Doe",
"period": { "min_date": "2025-01-01", "max_date": "2025-01-31" },
"locations": [
{
"location_id": 7,
"location_name": "Main Store",
"days": [
{
"date": "2025-01-06",
"planned_hours": 8,
"worked_hours": 7.75,
"closed_hours": 0,
"location_holiday_hours": 0,
"user_holiday_hours": 0,
"sick_hours": 0,
"expected_hours": 8,
"overtime_hours": -0.25
}
],
"totals": {
"planned_hours": 40, "worked_hours": 39, "closed_hours": 0,
"location_holiday_hours": 0, "user_holiday_hours": 0, "sick_hours": 0,
"expected_hours": 40, "overtime_hours": -1
}
}
]
}
}
De vestigingen van je bedrijf. qr_base64 wordt bewust weggelaten (groot, en inklokken gebeurt aan de app-kant).
| Param | Standaard | Opmerkingen |
|---|---|---|
include_inactive | 0 | 1 om gedeactiveerde vestigingen mee te nemen. |
{
"success": true,
"data": [
{
"location_id": 7,
"name": "Main Store",
"street": "Rue de la Paix",
"house_nr": "42",
"postal_code": "1000",
"city": "Brussels",
"country": "BE",
"timezone": "Europe/Brussels",
"is_company_primary": true,
"latitude": 50.8503,
"longitude": 4.3517,
"geo_radius_meters": 100,
"is_active": true,
"created": "2024-06-01 09:00:00",
"updated": "2025-08-27 14:22:15"
}
]
}
Eén vestiging, dezelfde objectvorm als de lijst. 404 not_found als ze niet in je bedrijf zit.
De actieve mensen die op één vestiging werken — elke actieve toewijzing (location_users-rij) gecombineerd met de naam van de persoon. Alleen rijen waar de toewijzing, de company_user én de user allemaal actief zijn, worden teruggegeven. 404 not_found als de vestiging niet bij je bedrijf hoort; een vestiging binnen je bedrijf zonder actief personeel geeft 200 met een lege data.
{
"success": true,
"location_id": 7,
"data": [
{
"location_user_id": 15,
"first_name": "Jane",
"last_name": "Doe",
"role": "staff",
"function_id": 3,
"function_name": "Sales"
}
]
}
Huidige klokstatus van één medewerker op één vestiging, afgeleid van hun meest recente klokgebeurtenis daar. clocked_in is true als de laatste gebeurtenis een IN is, false bij een OUT of als de medewerker daar nog nooit geklokt heeft. 404 not_found als de medewerker of vestiging niet in je bedrijf zit, of als de medewerker geen toewijzing op die vestiging heeft. De last_event_*-velden zijn null als er daar nog nooit geklokt is.
{
"success": true,
"data": {
"company_user_id": 42,
"location_id": 7,
"location_user_id": 15,
"clocked_in": true,
"last_event_type": "IN",
"last_event_time_utc": "2026-09-03 08:00:00",
"last_event_time_local": "2026-09-03 10:00:00"
}
}
Klokstatus van meerdere medewerkers op één vestiging in één aanvraag — bedoeld voor een admin-overzicht. Elke rij is de huidige status van één medewerker, afgeleid van hun laatste klokgebeurtenis op die vestiging. 404 not_found als de vestiging niet in je bedrijf zit; een vestiging zonder overeenkomende medewerkers geeft 200 met een lege data.
| Param | Opmerkingen |
|---|---|
company_user_ids | Optioneel. Kommagescheiden (bijv. 42,43,44), max. 500. Laat weg om elke actieve medewerker op de vestiging te krijgen. Een id dat geen actieve medewerker op deze vestiging is, wordt stil overgeslagen (een fout id laat de aanvraag niet mislukken). |
{
"success": true,
"location_id": 7,
"data": [
{
"company_user_id": 42,
"location_user_id": 15,
"clocked_in": true,
"last_event_type": "IN",
"last_event_time_utc": "2026-09-03 08:00:00",
"last_event_time_local": "2026-09-03 10:00:00"
}
]
}
Registreer een klok-IN of -OUT voor een medewerker van je bedrijf — gebruikt door de kassa-integratie van Onlinefact. De server is autoritair: hij bepaalt IN/OUT op basis van de laatste gebeurtenis van de medewerker en valideert de event_type die je stuurt tegen die status (409 bij een mismatch). Gebeurtenissen krijgen de servertijd in de tijdzone van de vestiging (geen terugdatering), met source: "pos". Bij OUT wordt de bijbehorende IN tot een sessie gekoppeld en de hashketen voor manipulatiedetectie uitgebreid — identiek aan de manager-klok van het dashboard.
| Veld | Type | Opmerkingen |
|---|---|---|
company_user_id | int | De medewerker (company_user_id). Moet een actieve medewerker in je bedrijf zijn. |
location_id | int | De vestiging (location_id). Moet een actieve vestiging van je bedrijf zijn, en de medewerker moet eraan toegewezen zijn. |
event_type | string | IN of OUT. Wordt gevalideerd tegen de serverstatus. |
{
"success": true,
"clock_event_id": 90210,
"event_type": "IN"
}
| Status | error | Betekenis |
|---|---|---|
| 400 | invalid_request | Body is geen JSON, location_user_id ontbreekt/is nul, of event_type is niet IN/OUT. |
| 402 | subscription_required | Bedrijf heeft geen actief (betaald) abonnement — de gratis proefperiode geeft geen API-toegang. |
| 404 | not_found | De company_user_id of location_id zit niet in je bedrijf (vreemde ID's zijn niet te onderscheiden van ontbrekende). |
| 422 | not_assigned | De medewerker en de vestiging bestaan beide in je bedrijf, maar de medewerker heeft geen actieve toewijzing op die vestiging. Er hoort een leesbare message bij. |
| 409 | conflict | De serverstatus vereist het andere gebeurtenistype, of de medewerker is nog ingeklokt op een andere vestiging. Er hoort een leesbare message bij. |
| 422 | location_misconfigured | De vestiging van de medewerker heeft geen tijdzone ingesteld. |
In de plugin-config van Onlinefact moet het volgende opgeslagen worden:
| Opslaan in de plugin-config | Waarde |
|---|---|
| Per kassanummer | location_id |
| Per kassamedewerker | company_user_id |
De API-sleutel is admin-scoped: ze kan vrij inklokken voor eender welke gebruiker. Daarom is dit endpoint enkel toegankelijk voor de servers van Onlinefact — voor de zekerheid, en omdat zinvolle rate limiting anders niet haalbaar zou zijn.
De pincode van de medewerker in de kassa zorgt ervoor dat collega's niet in elkaars naam kunnen inklokken. Eventueel kunnen we de manager toelaten om medewerkers in te klokken via functies, of via een extra pincode binnen functies.
API-sleutels worden aangemaakt, opgelijst en ingetrokken vanuit het Tikklok-dashboard (Instellingen → API-sleutels, alleen owner/admin). De secret wordt één keer getoond bij aanmaak — kopieer hem meteen. Intrekken gebeurt onmiddellijk.
Een machineleesbare OpenAPI 3.0-beschrijving is beschikbaar om te importeren in Postman, Insomnia of generators voor client-SDK's.