Webhooks
Les webhooks permettent à une application tierce d'être notifiée en temps réel des évènements qui surviennent dans atimeüs, sans avoir à interroger l'API en continu.
Principe
Un webhook associe une URL à un ou plusieurs déclencheurs. À chaque occurrence d'un déclencheur souscrit, atimeüs envoie une requête POST en application/json; charset=utf-8 vers l'URL configurée.
POST /mon-endpoint HTTP/1.1
Host: exemple.com
Content-Type: application/json; charset=utf-8
X-Atimeus-Webhook-Date: 2026-09-16T13:42:07
X-Atimeus-Webhook-Signature: hV2mQ0d1v3Yb8Kx6Lp9Tn4Rj7Ws5Cz1Ae0Uf2Gh3Io=
{"trigger":"project.created","date":"2026-09-16T13:42:05","data":{...}}Créer un webhook
Depuis l'interface
La gestion des webhooks s'effectue depuis l'écran : https://<instance>/admin/settings/webhooks
L'accès à cet écran nécessite le droit Webhooks.
Le formulaire de création comporte les champs suivants :
| Champ | Description |
|---|---|
Nom | Libellé du webhook, utilisé uniquement pour le retrouver dans la liste. |
URL | Adresse appelée lors de chaque envoi. |
Secret | Clé utilisée pour signer les envois. Optionnel. |
Déclencheur(s) | Un ou plusieurs déclencheurs parmi la liste ci-dessous. |
Un webhook est créé actif. La liste des webhooks permet ensuite de l'activer ou de le désactiver via la colonne Actif ?, et affiche dans la colonne Dernier appel le code HTTP retourné lors du dernier envoi.
Depuis l'API
Les webhooks peuvent également être pilotés par l'API, pour les besoins d'automatisation :
| Requête | Description |
|---|---|
GET restapi/webhooks/triggers | Liste des déclencheurs disponibles. |
GET restapi/webhooks/views/view-all | Liste des webhooks configurés. |
GET restapi/webhooks/{id} | Détail d'un webhook. |
POST restapi/webhooks | Création d'un webhook. |
PATCH restapi/webhooks/{id} | Mise à jour d'un webhook (voir Mise à jour d'une entité). |
DELETE restapi/webhooks/{id} | Suppression d'un webhook. |
GET restapi/webhooks/{id}/lastrun | Résultat du dernier envoi du webhook. |
Le détail des schémas est disponible dans la Référence de l'API.
Deux points d'attention :
- les déclencheurs sont stockés dans une chaîne unique, séparés par des points-virgules :
project.created;project.synced; - le champ
secretn'est jamais renvoyé en lecture par l'API. Il peut uniquement être réécrit.
Déclencheurs disponibles
La colonne « Contenu envoyé » indique laquelle des cinq formes de corps décrites dans la section Format de la requête est utilisée.
| Déclencheur | Description | Contenu envoyé |
|---|---|---|
project.created | Un projet a été créé. | data |
project.updated | Un projet a été modifié. | from / to |
project.deleted | Un projet a été supprimé. | id |
project.synced | Un projet a été synchronisé. | id |
project-task.created | Une tâche de projet a été créée. | data |
project-task.updated | Une tâche de projet a été modifiée. | from / to |
project-task.deleted | Une tâche de projet a été supprimée. | id |
contract.created | Un contrat a été créé. | data |
contract.updated | Un contrat a été modifié. | from / to |
contract.deleted | Un contrat a été supprimé. | id |
invoice.created | Une facture a été créée. | data |
invoice.updated | Une facture a été modifiée. | from / to |
invoice.deleted | Une facture a été supprimée. | id |
invoice.validated | Une facture a été validée. | id |
employee.created | Un collaborateur a été créé. | data |
employee.updated | Un collaborateur a été modifié. | from / to |
employee.deleted | Un collaborateur a été supprimé. | id |
customer.created | Un client a été créé. | data |
customer.updated | Un client a été modifié. | from / to |
customer.deleted | Un client a été supprimé. | id |
subcontractor.created | Un sous-traitant a été créé. | data |
subcontractor.updated | Un sous-traitant a été modifié. | from / to |
subcontractor.deleted | Un sous-traitant a été supprimé. | id |
user-task.created | Une tâche utilisateur a été créée. | data |
user-task.updated | Une tâche utilisateur a été modifiée. | from / to |
user-task.deleted | Une tâche utilisateur a été supprimée. | id |
quotes.validated | Un devis a été validé. | id |
opportunity.created | Une opportunité a été créée. | data |
opportunity.updated | Une opportunité a été modifiée. | from / to |
opportunity.deleted | Une opportunité a été supprimée. | id |
opportunity.won | Une opportunité est passée au statut gagné. | data |
opportunity.lost | Une opportunité est passée au statut perdu. | data |
contact.created | Un contact a été créé. | data |
contact.updated | Un contact a été modifié. | from / to |
contact.deleted | Un contact a été supprimé. | id |
application.created | Une candidature a été créée. | data |
application.updated | Une candidature a été modifiée. | from / to |
application.deleted | Une candidature a été supprimée. | id |
application.won | Une candidature est passée au statut gagné. | data |
application.lost | Une candidature est passée au statut perdu. | data |
candidate.created | Un candidat a été créé. | data |
candidate.updated | Un candidat a été modifié. | from / to |
candidate.deleted | Un candidat a été supprimé. | id |
month.closed | Un mois a été clôturé. | (aucun) |
timesheet.completed | Un collaborateur a complété son CRA. | période de CRA |
timesheet.validated | Un CRA a été validé par le manager. | période de CRA |
timesheet.closed | Un CRA a été clôturé. | période de CRA |
timesheet.unlocked | Un CRA a été déverrouillé. | période de CRA |
Format de la requête
En-têtes
| En-tête | Description |
|---|---|
X-Atimeus-Webhook-Date | Date d'envoi UTC, au format yyyy-MM-ddTHH:mm:ss. Elle change à chaque nouvelle tentative. |
X-Atimeus-Webhook-Signature | Signature HMAC-SHA256 du message, encodée en Base64. Présente uniquement si un secret est défini sur le webhook. |
Enveloppe commune
Quelle que soit sa forme, le corps contient au minimum les propriétés trigger et date :
trigger: le déclencheur à l'origine de l'envoi ;date: la date UTC de l'évènement, au formatyyyy-MM-ddTHH:mm:ss, sans millisecondes ni suffixe de fuseau. Contrairement à l'en-têteX-Atimeus-Webhook-Date, elle reste identique entre les tentatives d'un même évènement.
Les propriétés sont sérialisées en camelCase.
L'objet contenu dans data, from et to est identique à la réponse de lecture REST de l'entité correspondante — par exemple GET restapi/projects/{id} pour project.created — champs personnalisés du tenant inclus. Le détail des champs est disponible dans la Référence de l'API.
Forme data
L'enveloppe porte une propriété data contenant l'entité complète. Cette forme est utilisée par les déclencheurs *.created, ainsi que par opportunity.won, opportunity.lost, application.won et application.lost.
{
"trigger": "project.created",
"date": "2026-09-16T13:42:05",
"data": {
"id": "b1f9e0c4-3a7d-4e21-9f55-0c2a8d61b743",
"name": "Refonte du portail client",
"createDate": "2026-09-16T13:42:05",
... // l'ensemble des champs retournés par GET restapi/projects/{id}
}
}Forme from / to
L'enveloppe porte deux propriétés : from, l'état antérieur de l'entité, et to, son état courant. Cette forme est utilisée par les déclencheurs *.updated.
{
"trigger": "project.updated",
"date": "2026-09-16T14:05:11",
"from": {
"id": "b1f9e0c4-3a7d-4e21-9f55-0c2a8d61b743",
"name": "Refonte du portail client",
...
},
"to": {
"id": "b1f9e0c4-3a7d-4e21-9f55-0c2a8d61b743",
"name": "Refonte du portail client - phase 2",
...
}
}Lorsque l'état antérieur n'a pas pu être reconstitué, seule la propriété to est présente.
Forme id
L'enveloppe porte une unique propriété id contenant l'identifiant de l'entité concernée. Cette forme est utilisée par les déclencheurs *.deleted, ainsi que par project.synced, invoice.validated et quotes.validated.
{
"trigger": "project.deleted",
"date": "2026-09-16T14:22:48",
"id": "b1f9e0c4-3a7d-4e21-9f55-0c2a8d61b743"
}Forme période de CRA
L'enveloppe porte quatre propriétés identifiant le CRA concerné : id, employeeId, year et month. Cette forme est utilisée par les déclencheurs timesheet.completed, timesheet.validated, timesheet.closed et timesheet.unlocked.
{
"trigger": "timesheet.validated",
"date": "2026-09-16T13:42:05",
"id": "7c3e9a51-4d82-4f0b-8a16-5b9d2e7c41f8",
"employeeId": "b1f9e0c4-3a7d-4e21-9f55-0c2a8d61b743",
"year": 2026,
"month": 9
}Le corps ne contient volontairement aucune donnée personnelle : ni le nom du collaborateur, ni son manager, ni sa société. Le consommateur qui a besoin du détail rappelle les vues de CRA de l'API, soit sur l'id de la période, soit en filtrant sur le triplet collaborateur / année / mois.
Si la période a été supprimée entre l'évènement et son envoi, le corps retombe sur la forme id et porte le même identifiant de période que les évènements précédents.
Forme minimale
Aucune propriété au-delà de trigger et date.
{
"trigger": "month.closed",
"date": "2026-10-01T02:00:00"
}Secret et signature
Le secret est saisi librement lors de la création du webhook. Il est optionnel, mais sans secret aucune signature n'est émise : l'en-tête X-Atimeus-Webhook-Signature est alors absent et l'authenticité de l'appel ne peut pas être vérifiée.
Pour vérifier une signature :
- calculer le HMAC-SHA256 en utilisant le secret comme clé, sur la concaténation de la valeur de l'en-tête
X-Atimeus-Webhook-Date, d'un caractère deux-points, puis du corps brut de la requête ; - encoder le résultat en Base64 ;
- comparer la valeur obtenue à l'en-tête
X-Atimeus-Webhook-Signature.
La vérification doit porter sur le corps brut reçu, avant toute désérialisation ou reformatage : une simple réindentation du JSON invalide la signature.
Trois pièges à éviter :
- la date utilisée est celle de l'en-tête
X-Atimeus-Webhook-Date, et non la propriétédatedu corps — les deux diffèrent dès la première nouvelle tentative ; - le séparateur entre la date et le corps est un deux-points ;
- l'encodage de sortie est le Base64, et non l'hexadécimal, et la valeur ne comporte aucun préfixe de type
sha256=.
Les webhooks dont l'URL cible Make.com font exception : le secret y est transmis via un en-tête d'authentification dédié, x-make-apikey, à la place de la signature HMAC.
Livraison et nouvelles tentatives
Un envoi est considéré comme réussi lorsque l'endpoint répond un code 2xx. Tout autre code, comme toute absence de réponse, est traité comme un échec.
En cas d'échec, l'envoi est retenté jusqu'à 5 tentatives au total, avec un délai exponentiel entre chacune.
Au-delà de la cinquième tentative, l'évènement n'est plus retenté.
Enfin, un même évènement peut être reçu plusieurs fois, notamment lorsqu'une tentative a abouti côté atimeüs sans que la réponse soit parvenue. Le consommateur doit donc tolérer les doublons, par exemple en rendant son traitement idempotent.