Pour les développeurs

L’API Floowa

Une API REST en JSON, des jetons API personnels et des webhooks signés. La référence est publique ; pour l’essayer, il vous faut un compte Floowa.

Authentification

Un administrateur crée un jeton sous Paramètres → Accès API, choisit les droits par fonction et une date d’expiration (30, 90 ou 365 jours ou illimitée). Le jeton n’est affiché qu’une seule fois.

Authorization: Bearer <token>
Accept: application/json

URL de base: https://www.floowa.de/api/v1

  • Chaque requête s’exécute dans l’entreprise du titulaire du jeton et ne peut jamais dépasser ce que permettent le jeton et les droits propres du titulaire.
  • L’API est incluse dans toutes les offres ; les points d’accès des modules souscrits sont disponibles dès que le module est actif.
  • Les messages d’erreur sont dans la langue de l’en-tête Accept-Language (sinon en anglais).

Limites et comportement

Limites et comportement
Limite de débit 120 requêtes par minute et par jeton ; au-delà, l’API répond par HTTP 429.
Listes Les listes sont paginées ; avec per_page, vous obtenez jusqu’à 100 entrées par page.
Répéter sans risque Avec l’en-tête Idempotency-Key, une requête répétée renvoie la même réponse pendant 24 heures au lieu de créer un doublon.
Révision de l’API Chaque réponse porte l’en-tête Floowa-Api-Revision avec la date de la dernière modification de l’API.

Webhooks et signature

Chaque livraison est un POST en JSON vers votre adresse HTTPS, avec les en-têtes X-Floowa-Event, X-Floowa-Delivery et X-Floowa-Signature.

La signature a la forme t=<horodatage>,v1=<signature>. v1 est un HMAC-SHA256 sur « <horodatage>.<corps brut> » avec votre clé de signature. Comparez en temps constant et rejetez les horodatages anciens.

Si votre serveur ne répond pas avec un statut 2xx, Floowa réessaie après 1, 5 et 30 minutes puis après 2 heures. Après 20 échecs consécutifs, le webhook est désactivé.

Exemple de livraison

{
    "id": "8f2c3a1e-5b7d-4c1a-9e2f-0a1b2c3d4e5f",
    "event": "absence.requested",
    "created_at": "2026-10-28T09:15:00+01:00",
    "data": {
        "id": "01a1…",
        "employee_id": "01a0…",
        "absence_type_id": "01a0…",
        "start_date": "2026-11-02",
        "end_date": "2026-11-06",
        "half_day_start": false,
        "half_day_end": false,
        "days": 5,
        "status": "pending"
    }
}

Vérifier la signature (PHP)

$header = $_SERVER["HTTP_X_FLOOWA_SIGNATURE"] ?? "";
parse_str(str_replace(",", "&", $header), $parts);
$body = file_get_contents("php://input");
$expected = hash_hmac("sha256", $parts["t"] . "." . $body, $secret);

if (! hash_equals($expected, $parts["v1"] ?? "") || abs(time() - (int) $parts["t"]) > 300) {
    http_response_code(400);
    exit;
}

Tous les événements en clair

Les événements que Floowa envoie par webhook
Événement Quand Nom technique
Collaborateur créé Un collaborateur est créé – manuellement, par import ou via l’API. employee.created
Collaborateur modifié Les données de base d’un collaborateur changent. employee.updated
Collaborateur supprimé Un collaborateur est supprimé. employee.deleted
Absence demandée Quelqu’un demande un congé ou une autre absence. absence.requested
Absence approuvée Une demande est approuvée ou une absence saisie directement. absence.approved
Absence refusée Une demande est refusée. absence.rejected
Absence annulée Une demande ou une absence est retirée. absence.cancelled
Temps enregistré Une saisie de temps est créée – en pointant l’arrivée, en saisissant après coup ou à la pointeuse. time_entry.created
Temps modifié Une saisie de temps change, par exemple en pointant le départ. time_entry.updated
Temps supprimé Une saisie de temps est supprimée. time_entry.deleted
Mois clôturé Un mois est clôturé dans la préparation de la paie. payroll.closed
Mois rouvert Un mois clôturé est rouvert pour des corrections. payroll.reopened
Créneau publié Un créneau est publié avec le planning. shift.published
Créneau modifié Un créneau publié change. shift.changed
Créneau supprimé Un créneau publié est supprimé. shift.deleted

Historique des modifications

Toutes les modifications de l’API avec date et mention des changements non rétrocompatibles. Lisible par machine via GET /api/v1/changelog.

2026-11-02 · 2 novembre 2026

  • Nouveau Paramètres d’horaire cible des salariés : les réponses contiennent effective_weekly_hours (heures hebdomadaires propres ou standard de l’entreprise ; null sans horaire cible fixe), no_fixed_hours (pas d’horaire cible fixe, p. ex. direction ou temps de travail de confiance) et working_time_law_exempt (pas de contrôles de la loi sur le temps de travail, p. ex. gérants de GmbH ou cadres dirigeants). POST et PUT acceptent no_fixed_hours et working_time_law_exempt en option ; nouveau employment_type managing_director (direction). weekly_hours reste inchangé. GET /employeesGET /employees/{id}POST /employeesPUT /employees/{id}

2026-10-30 · 30 octobre 2026

  • Nouveau Contrôles d’inventaire et qualifications exigées par l’inventaire : GET /qualifications renvoie required_inventory_category_ids et la nouvelle catégorie check (sans document) ; GET /employees/{id}/qualifications renvoie requirement_reasons (pourquoi une qualification est obligatoire – unité ou objet remis) ; GET /inventory-items/{id} contient inspections avec due_on, last_done_on et status (ok, due_soon, overdue). GET /qualificationsGET /employees/{id}/qualificationsGET /inventory-items/{id}
  • Nouveau Absences : POST /absences/{id}/cancel accepte un motif facultatif (reason) et annule aussi les absences approuvées ; les réponses contiennent cancel_requested_at (demande d’annulation en attente d’un salarié) et cancel_reason. POST /absences/{id}/decision tranche une demande d’annulation (approve = annuler, reject = maintenir l’absence). POST /absences/{id}/cancelGET /absences
  • Modifié Les noms de projet ne doivent plus être uniques que par client ; le même nom est autorisé pour des clients différents. Les projets sans client restent uniques entre eux. POST /time-projectsPUT /time-projects/{id}

2026-10-29 · 29 octobre 2026

  • Nouveau Temps projet par entrée : les entrées acceptent customer_id (client sans projet) et parts (répartition sur plusieurs projets/clients avec minutes ou start/end) ; GET /time-allocations renvoie customer_id, label, started_at/ended_at et kind part, filtre customer_id. POST /time-entriesPUT /time-entries/{id}GET /time-allocations
  • Nouveau Unités : clock_web et clock_app (true/false, null = comme le parent) déterminent si les collaborateurs de l’unité peuvent pointer dans le navigateur ou l’application. GET /org-unitsPOST /org-unitsPUT /org-units/{id}
  • Supprimé non rétrocompatible L’attribution libre par jour PUT /employees/{id}/time-allocations/{date} est supprimée – envoyez la répartition via parts sur l’entrée. Les attributions libres existantes ont été rattachées à l’entrée la plus longue du jour. PUT /employees/{id}/time-allocations/{date}

2026-10-28 · 28 octobre 2026

  • Nouveau Temps projet séparé de la présence : GET /time-allocations indique à quel projet le temps d’une journée est attribué ; PUT /employees/{id}/time-allocations/{date} définit les attributions libres d’une journée. time_project_id sur les entrées reste et crée automatiquement une attribution liée. GET /time-allocationsPUT /employees/{id}/time-allocations/{date}

2026-10-26 · 26 octobre 2026

  • Nouveau Préparation de la paie : nouvel objet surcharges_3b par employé avec les minutes de majoration selon le § 3b EStG (night_25, night_40, sunday_50, holiday_125, holiday_150). Les champs night et holiday restent des totaux. GET /payroll/{month}
  • Modifié non rétrocompatible Préparation de la paie : sunday ne compte plus les jours fériés, mais inclut 0–4 h le lundi après une équipe commencée le dimanche. holiday inclut en plus les 24 et 31 décembre à partir de 14 h. Les pauses sont déduites au prorata. GET /payroll/{month}
  • Confidentialité/sécurité non rétrocompatible Absences : les utilisateurs disposant uniquement de droits de lecture voient les types d'absence confidentiels (p. ex. maladie) comme une absence neutre – absence_type_id, type, note et decision_note sont null et le nouveau champ type_hidden vaut true. Le rapport de paie regroupe ces jours dans la colonne type_hidden. GET /absencesGET /reports/payroll
  • Nouveau Nouveau point de terminaison GET /changelog et en-tête Floowa-Api-Revision sur chaque réponse. GET /changelog

2026-10-23 · 23 octobre 2026

  • Nouveau Première version de l'API v1 : organisation, personnel, documents, qualifications, inventaire, bulletins de paie, saisie des temps avec pointeuse et validation, projets et clients, absences, jours fériés, rapports, préparation de la paie, Idempotency-Key et webhooks.

C'est parti. Bienvenue chez Floowa.