Congés et soldes

Les absences, et ce qui reste sur chaque compteur. Pourquoi quelqu'un est absent est la donnée la plus sensible que porte cette API : elle est retirée sauf si un scope dédié vous a été accordé — voir Pourquoi une absence a été prise, plus bas.

L'enveloppe restricted employée ici est celle décrite sous Champs retirés dans Sociétés, salariés et contrats.

Ce qu'une lecture de congés rend : des lignes, pas des demandes

Une demande peut porter plusieurs lignes. Trois jours de congés payés suivis de deux jours de RTT font une demande à deux lignes, et chaque ligne a ses propres dates, sa propre quantité et son propre type. Cette API sert des lignes, et c'est requestId qui regroupe celles d'une même absence.

Sans lui, deux lignes d'une même demande sont indiscernables de deux demandes déposées sur des dates voisines — et ce ne sont pas les mêmes faits. Regroupez sur requestId avant de présenter quoi que ce soit à un utilisateur.

Une frontière de page peut séparer les lignes d'une même absence. Elles sortent dans l'ordre de leurs identifiants, donc côte à côte — mais rien ne garantit qu'elles tombent dans la même page. Regroupez sur requestId après avoir parcouru la pagination jusqu'au bout, jamais page par page.

Lister les absences

GET /api/v1/client/leave-requests (scopes : leaves:read)

{
  "items": [
    {
      "id": "WV5RJ7",
      "requestId": "ePloqJ",
      "employeeId": "GNnBNO",
      "companyId": "dV3QPr",
      "startDate": "2026-01-12",
      "endDate": "2026-01-15",
      "duration": 3.5,
      "durationUnit": "Days",
      "status": "Approved",
      "createdOn": "<generated>",
      "leaveType": null,
      "isWorkStoppage": null,
      "restricted": [
        {
          "reason": "requires_scope",
          "fields": [
            "leaveType",
            "isWorkStoppage"
          ]
        },
        {
          "reason": "requires_company_opt_in",
          "fields": [
            "leaveType",
            "isWorkStoppage"
          ]
        }
      ]
    },
    {
      "id": "mNw9JY",
      "requestId": "ePloqJ",
      "employeeId": "GNnBNO",
      "companyId": "dV3QPr",
      "startDate": "2026-01-12",
      "endDate": "2026-01-15",
      "duration": 3.5,
      "durationUnit": "Days",
      "status": "Approved",
      "createdOn": "<generated>",
      "leaveType": null,
      "isWorkStoppage": null,
      "restricted": [
        {
          "reason": "requires_scope",
          "fields": [
            "leaveType",
            "isWorkStoppage"
          ]
        },
        {
          "reason": "requires_company_opt_in",
          "fields": [
            "leaveType",
            "isWorkStoppage"
          ]
        }
      ]
    }
  ],
  "nextCursor": null
}
Paramètre Ce qu'il fait
from, to Dates ISO bornant l'absence. L'un ou l'autre peut être omis.
status Un code de cycle de vie, ou plusieurs séparés par des virgules.
establishmentId Restreint la page à UN établissement de votre périmètre. Omis, elle les lit tous.
cursor, limit Pagination. Renvoyez nextCursor ; n'arrêtez que lorsqu'il vaut null.

establishmentId restreint, il n'élargit jamais. Nommer un établissement hors de votre périmètre ne renvoie rien plutôt que de l'atteindre, et il en va de même d'une valeur qui n'est pas un identifiant émis par cette API : un signet périmé vous donne une page vide, pas une erreur et pas le périmètre entier. Même paramètre et même règle sur la liste des salariés.

La fenêtre filtre par recouvrement, pas par inclusion. Une absence allant du 28 janvier au 3 février est rendue pour janvier et pour février. C'est ce qu'il vous faut pour clôturer un mois de paie : demander les absences entièrement contenues dans le mois écarterait précisément celles qui chevauchent la clôture.

Une date illisible laisse ce côté de la fenêtre ouvert plutôt que de faire échouer l'appel. Vous pouvez recevoir plus que demandé, jamais moins.

Une absence accordée n'est pas un statut mais trois

Une absence accordée entre en Approved, devient Treated une fois reprise par la paie, puis Terminated. Filtrer sur Approved seul perd les absences au moment précis où elles deviennent certaines. Pour une vue de planning, demandez les trois :

GET /api/v1/client/leave-requests?from=2026-01-01&to=2026-01-31&status=Approved,Treated,Terminated

L'ensemble complet est SentForUpdate, ApprobationPending, Approved, Refused, TreatmentPending, Treated, Terminated, AbortionPending, Aborted, Imported. Les brouillons non soumis ne sont jamais servis : c'est l'intention non envoyée d'un salarié, que personne d'autre ne voit non plus dans Staff & Go.

Une ligne qui disparaît est absente, pas retirée

Il n'y a ni flux de delta ni pierre tombale. Une demande annulée après votre lecture cesse simplement d'être rendue — rien ne l'annonce. Relisez la fenêtre plutôt que d'attendre un événement de suppression, et ne tenez pas pour toujours active une ligne vue autrefois sous prétexte qu'aucun événement n'a dit le contraire.

Une absence

GET /api/v1/client/leave-requests/{id} (scopes : leaves:read)

Prend l'id d'une ligne, tel que rendu par le listing.

Les quantités voyagent toujours avec leur unité

Champ Ce qu'il vous dit
duration Ce que représente la ligne, demi-journées comprises — un après-midi vaut 0.5.
durationUnit Ce que ce nombre compte : Days ou Hours.

duration seul ne veut rien dire. Le même 7 vaut sept jours ou sept heures selon la configuration de la société pour ce type de congé. Lire le nombre sans l'unité vous trompe d'environ une journée de travail, dans le sens que vous aurez deviné. N'en stockez et n'en affichez jamais un sans l'autre.

Pourquoi une absence a été prise

leaveType et isWorkStoppage sont derrière leaves:read:reason, exigé en plus de leaves:read, qui ne l'implique jamais.

Un type de congé révèle un arrêt maladie ou un congé maternité, donc de la donnée de santé au sens de l'article 9 du RGPD — la catégorie la plus sensible que touche cette API. La réponse par défaut dit donc quand et combien, jamais pourquoi. Une intégration de planning a besoin des dates ; seule une intégration au besoin établi devrait détenir ce scope.

Les deux champs sont libérés ensemble et retirés ensemble. Un partenaire ne détenant que le drapeau d'arrêt de travail pourrait encore séparer la maladie des vacances : libérer l'un seul divulguerait ce que la paire existe pour protéger.

isWorkStoppage: null veut dire retiré. Jamais false. Le lire comme false affirmerait que l'absence n'est pas un arrêt de travail — une affirmation sur la santé de quelqu'un, et non l'absence d'affirmation. Consultez restricted avant de l'interpréter.

Soldes

GET /api/v1/client/employees/{id}/leave-balances (scopes : leaves:read)

{
  "items": [
    {
      "employeeId": "GNnBNO",
      "companyId": "1VaKPa",
      "counterCode": "CP",
      "counterName": "Cong\u00E9s pay\u00E9s",
      "unit": "Days",
      "acquired": 25,
      "taken": 10,
      "remaining": 14.5
    },
    {
      "employeeId": "GNnBNO",
      "companyId": "1VaKPa",
      "counterCode": "RTT",
      "counterName": "RTT",
      "unit": "Days",
      "acquired": 12,
      "taken": 12,
      "remaining": 0
    }
  ]
}
Champ Ce qu'il vous dit
employeeId À qui appartient ce solde.
companyId L'établissement dont il relève — l'identifiant opaque servi par /companies. Toujours présent : un dossier salarié appartient à un seul.
counterCode Stable entre sociétés (CP, RTT) — comparez sur celui-ci, pas sur counterName.
counterName Un libellé, dans votre langue. La société peut le renommer.
unit Days ou Hours.
acquired, taken, remaining Acquis, pris, restant.

Ne recalculez jamais remaining comme acquired − taken. Les trois sont maintenus indépendamment par le moteur d'acquisition : un compteur qui se reporte depuis un autre, ou qui porte un ajustement manuel, ne satisfait pas cette soustraction. Le recalculer vous met en désaccord avec ce que le salarié voit dans Staff & Go, précisément pour ces salariés-là. Lisez remaining tel qu'il est servi.

Non paginé — une société a une poignée de compteurs, et ils reviennent tous d'un coup. Cette lecture n'a pas d'enveloppe restricted : un solde dit combien il reste, jamais pourquoi une absence a été prise, donc il n'y a rien à y retirer.

Un identifiant de salarié qui n'est pas des vôtres répond 404, pas une liste vide.