API REST publique

Tikklok REST API v1

Une API REST sans état, authentifiée par clé API, pour les intégrations tierces. Lisez les employés, les établissements et les données de performance de votre entreprise. Chaque réponse est en JSON.

URL de base

https://api.tikklok.appproduction
http://localhost:8084développement local

Tous les endpoints sont versionnés sous /v1. Chaque requête doit se faire en HTTPS en production.

Authentification

HTTP Basic Auth en HTTPS. Envoyez un en-tête Authorization avec votre identifiant de clé et votre secret, encodés en base64 :

Authorization: Basic base64(KEY_ID:SECRET)
IdentifiantFormatNotes
KEY_IDTK_PUB_LIVE_… (28)Identifiant public, en majuscules, suffixe 16-hex. Sans risque à journaliser.
SECRETTK_SEC_LIVE_… (60)Privé. Affiché une seule fois à la création ; seul un hachage SHA-256 est conservé — irrécupérable en cas de perte.

Un échec d'authentification renvoie 401 unauthorized. L'API ne distingue jamais une mauvaise clé d'un mauvais secret, pour empêcher l'énumération.

Exemple

curl -u TK_PUB_LIVE_A1B2C3D4E5F60718:TK_SEC_LIVE_… \
     https://api.tikklok.app/v1/me

Limites de débit

PortéeLimite
Par clé60 requêtes / minute · 1000 / heure (fenêtres fixes)
Par IP, avant auth20 requêtes / minute (avant vérification du Basic Auth)
Par IP, échecs d'auth10 échecs / minute → blocage temporaire

Un dépassement renvoie 429 rate_limited. Attendez une minute et réessayez.

Réponses & erreurs

Chaque réponse est en JSON avec un booléen success. Les erreurs portent aussi une courte chaîne error lisible par machine. Les lectures n'émettent jamais success: false pour des données manquantes — un corps 404 signifie que la ressource elle-même était absente. Chaque réponse porte Cache-Control: no-store.

StatuterrorSignification
400invalid_roleValeur de filtre role inconnue.
400invalid_dateDate manquante/mal formée, ou min_date > max_date.
400range_too_largePériode de performance supérieure à 366 jours.
401unauthorizedIdentifiants manquants ou invalides.
404not_foundRessource absente — ou appartenant à une autre entreprise (indiscernable, par conception).
413payload_too_largeCorps de requête supérieur à 1 Mo.
429rate_limitedLimite de débit dépassée.

Portée & ID

Chaque requête est limitée à l'entreprise propriétaire de la clé API. Les ressources sont adressées par leurs ID globaux :

IDSignification
company_user_idUne personne dans votre entreprise (l'identité « employé »). Stable, globalement unique.
location_idL'un des établissements de votre entreprise. Stable, globalement unique.
Le locations[] de chaque employé inclut son location_user_id — la clé d'affectation interne — qui sert à cibler les pointages de cet employé sur cet établissement. Les paramètres de chemin adressent toujours une affectation par le couple (company_user_id, location_id). Tout ID dans un chemin qui n'appartient pas à votre entreprise renvoie 404 not_found — identique à un ID inexistant, de sorte que les ID étrangers ne peuvent pas être sondés. Les corps de requête doivent faire ≤ 1 Mo (sinon 413 payload_too_large).

Endpoints

Tous les endpoints sont en GET. Chaque endpoint sauf /v1/health requiert une authentification.

GET/v1/healthsans auth

Sonde de disponibilité. Aucune authentification.

Réponse 200

{
  "success": true,
  "status": "ok",
  "version": "v1",
  "time": "2026-08-08T14:23:00Z"
}
GET/v1/meauth

Confirme que vos identifiants fonctionnent et indique à quelle entreprise ils correspondent.

Réponse 200

{
  "success": true,
  "company_id": 1,
  "company_name": "Acme Corp",
  "key_id": "TK_PUB_LIVE_A1B2C3D4E5F60718",
  "key_name": "My Slack integration"
}
GET/v1/employeesauth

Liste paginée des personnes de votre entreprise (company_users), chacune avec une liste concise des établissements auxquels elle est activement affectée. Les owners/admins apparaissent aussi, avec un tableau locations vide s'ils n'ont aucune affectation.

Paramètres de requête

ParamDéfautNotes
limit100Borné à 1–500.
offset0Pour la pagination.
location_idUniquement les employés activement affectés à cet établissement.
roleRôle d'entreprise : owner, admin, employee. Invalide → 400 invalid_role.
include_inactive01 pour inclure les employés désactivés.

Réponse 200

{
  "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" }
      ]
    }
  ]
}
GET/v1/employees/{company_user_id}auth

Détail complet d'un employé et de chaque affectation à un établissement (active et historique — chacune avec son propre is_active). Chaque affectation inclut son location_user_id (la clé d'affectation, pour les pointages via l'API). 404 not_found si l'employé n'est pas dans votre entreprise.

Réponse 200

{
  "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",
    "contract": "fixed_schedule",
    "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,
        "overtime": true,
        "valid_from": null,
        "valid_to": null,
        "is_active": true
      }
    ]
  }
}
GET/v1/employees/{company_user_id}/locations/{location_id}auth

L'affectation d'un employé à un établissement. 404 not_found si l'employé n'est pas dans votre entreprise, si l'établissement n'est pas dans votre entreprise, ou s'il n'existe aucune affectation entre les deux.

Réponse 200

{
  "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,
    "overtime": true,
    "valid_from": null,
    "valid_to": null,
    "is_active": true,
    "created": "2025-01-15 10:30:00",
    "updated": "2025-08-27 14:22:15"
  }
}
GET/v1/employees/{company_user_id}/performanceauth

Les mêmes données de performance que le rapport téléchargeable du tableau de bord, en JSON, groupées par établissement. Pour chaque établissement auquel l'employé est (ou était) affecté, une ventilation par jour plus des totals additionnés. Tous les chiffres sont en heures (2 décimales) ; overtime_hours peut être négatif (sous-temps).

expected_hours = planned − closed − location_holiday − user_holiday − sick · overtime_hours = worked − expected

Paramètres de requête (les deux requis)

ParamNotes
min_dateYYYY-MM-DD
max_dateYYYY-MM-DD, ≥ min_date

Date invalide/manquante ou min_date > max_date400 invalid_date. Une période de plus de 366 jours → 400 range_too_large. 404 not_found si l'employé n'est pas dans votre entreprise. Un employé sans données sur la période renvoie 200 avec un tableau locations vide.

Réponse 200

{
  "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
        }
      }
    ]
  }
}
GET/v1/locationsauth

Les établissements de votre entreprise. qr_base64 est volontairement omis (volumineux, et le pointage se fait côté application).

Paramètres de requête

ParamDéfautNotes
include_inactive01 pour inclure les établissements désactivés.

Réponse 200

{
  "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"
    }
  ]
}
GET/v1/locations/{location_id}auth

Un établissement, même forme d'objet que la liste. 404 not_found s'il n'est pas dans votre entreprise.

Gestion des clés API

Les clés API se créent, se listent et se révoquent depuis le tableau de bord Tikklok (Paramètres → Clés API, owner/admin uniquement). Le secret est affiché une seule fois à la création — copiez-le immédiatement. La révocation est immédiate.

Spéc OpenAPI

Une description OpenAPI 3.0 lisible par machine est disponible pour l'import dans Postman, Insomnia ou des générateurs de SDK client.

Télécharger openapi.yaml