Guide de l’API Palisade
Premiers pas avec l’API Palisade. Vous cherchez le détail des points de terminaison? Consultez la référence de l’API. Vous cherchez plutôt la documentation de l’application? La documentation du produit Palisade couvre le tableau de bord, la configuration des domaines et le déploiement de DMARC.
Authentification
L’API Palisade authentifie les requêtes au moyen de clés d’API. Créez et gérez vos clés à partir du tableau de bord — ouvrez le menu de votre avatar dans le coin supérieur droit et choisissez Clés d’API — avec n’importe quel forfait, ou obtenez-en une par programmation avec l’inscription sans interface.
Important : vos clés d’API donnent un accès étendu à votre compte; gardez-les donc en sécurité. Ne communiquez pas vos clés secrètes dans des dépôts publics, du code côté client ou tout autre endroit non sécurisé.
Toutes les requêtes à l’API doivent passer par HTTPS. Les requêtes envoyées en HTTP simple sont refusées. À part un petit nombre de points de terminaison publics (comme cette documentation et la spécification OpenAPI), toute requête qui ne contient pas d’identifiants valides échoue. Les sessions du tableau de bord s’authentifient avec un JWT Bearer plutôt qu’avec une clé d’API.
La clé d’API sert de nom d’utilisateur dans l’authentification HTTP Basic, avec un mot de passe vide :
curl https://api.palisade.email/domains \
-u "$PALISADE_API_KEY:" \
-H "Palisade-Version: 2025-04-30"
Inscription sans interface
Créez un compte Palisade entièrement au moyen de l’API — aucun navigateur requis. Cette fonction est conçue pour les agents d’IA et les automatisations qui contrôlent une boîte de réception.
1. Commencez l’inscription avec une adresse courriel. Les adresses professionnelles et personnelles sont toutes deux acceptées; les domaines jetables sont refusés avec un 422 (disposable_email_domain). Aucun captcha n’est requis. Le point de terminaison a une limite de débit par adresse IP; respectez donc les en-têtes de réponse RateLimit-*. Chaque adresse courriel est aussi limitée séparément à un petit nombre de codes par heure; au-delà, la réponse est un 429 (signup_email_throttled) :
curl -X POST https://api.palisade.email/signup \
-H "Content-Type: application/json" \
-d '{"email": "ops@example.com", "organization_name": "Example Corp"}'
{"signup_id": "<uuid>", "expires_in_seconds": 900}
2. Un code à six chiffres est envoyé à la boîte de réception. Vérifiez-le dans les 15 minutes et en 5 tentatives erronées au plus; au-delà de l’une ou l’autre limite, l’inscription est morte et chaque appel suivant renvoie signup_challenge_invalid; commencez-en donc une nouvelle :
curl -X POST https://api.palisade.email/signup/verify \
-H "Content-Type: application/json" \
-d '{"signup_id": "<uuid>", "code": "123456"}'
La réponse contient votre organisation et une clé d’API affichée une seule fois — conservez-la en lieu sûr. Le compte est une organisation Palisade complète : la même adresse courriel pourra plus tard se connecter au tableau de bord en réinitialisant le mot de passe.
Ensuite, le parcours habituel est le suivant : POST /domains pour ajouter un domaine, GET /domains/{id}/dns-records pour obtenir les enregistrements DNS exacts à publier chez votre fournisseur DNS, puis POST /domains/{id}/verify jusqu’à ce que chaque enregistrement indique verified.
Serveur MCP
Palisade offre un serveur Model Context Protocol natif pour que les agents d’IA puissent piloter la plateforme directement. Il expose les principaux flux de travail de Palisade sous forme d’outils, limités à l’organisation à laquelle l’appelant s’est connecté.
- Point de terminaison :
https://api.palisade.email/mcp(Streamable HTTP) - Authentification : OAuth, au moyen du client de connecteur de Palisade pour les clients que vous configurez vous-même. Les clés d’API ne sont pas acceptées sur ce point de terminaison.
- Sans compte :
https://api.palisade.email/mcp/publicoffre les deux outils qui lisent le DNS en vigueur et ne demande aucune connexion. Consultez le point de terminaison d’audit public. - Découverte :
https://api.palisade.email/.well-known/mcpdécrit le serveur, son transport et chaque outil avec son schéma d’entrée, ethttps://api.palisade.email/.well-known/mcp/server-card.jsonprésente le même catalogue sous forme de carte de serveur MCP (SEP-1649). Les deux sont publics et ne demandent aucune connexion; un client peut donc lire ce qu’il pourra faire avant de s’authentifier.
Fonctionnement de la connexion
Il n’y a rien à créer d’abord. Un client qui appelle le point de terminaison sans identifiants reçoit un 401 portant un défi RFC 9728 qui nomme les métadonnées de la ressource protégée :
WWW-Authenticate: Bearer resource_metadata="https://api.palisade.email/.well-known/oauth-protected-resource"
Ces métadonnées nomment le serveur d’autorisation. Chaque client que vous configurez vous-même se connecte avec le même client OAuth public, ryKtuiPypMeYMoL1Cmhxtz6BYrEYQbLV, qui n’a pas de secret (PKCE). Le navigateur ouvre la page de connexion de Palisade, vous choisissez une organisation, et le client obtient un jeton limité à celle-ci et à votre rôle; un lecteur ne peut donc rien modifier au moyen de MCP. Les connexions que vous avez autorisées sont énumérées sous API et MCP à app.palisade.email. Tous les assistants qui se connectent avec ce client partagent une même connexion, qui y figure avec les assistants qui l’ont utilisée; la révoquer les déconnecte donc tous, dans chaque organisation dont vous êtes membre. Un jeton qu’un assistant détient déjà continue de fonctionner jusqu’à son expiration.
Un client qui inscrit son propre client OAuth est refusé. L’inscription dynamique de client et les documents de métadonnées d’identifiant de client produisent tous deux un client auquel le serveur d’autorisation ne peut pas rattacher d’organisation; le point de terminaison répond donc 403 et nomme le client à utiliser à la place.
Connecteurs personnalisés de claude.ai
Dans claude.ai, ouvrez Settings, puis Connectors, puis Add custom connector :
- URL :
https://api.palisade.email/mcp - Authentification : Always required
- Client OAuth : Use your own OAuth client, identifiant de client
ryKtuiPypMeYMoL1Cmhxtz6BYrEYQbLV, secret laissé vide
Laissez de côté l’option que recommande la boîte de dialogue, Use Anthropic’s hosted client metadata, ainsi que register one automatically : il s’agit dans les deux cas de clients qui s’inscrivent eux-mêmes, et Palisade les refuse.
Claude Code
Une seule commande, qui porte l’identifiant de client et un port de rappel fixe, parce que le serveur d’autorisation enregistre des URI de redirection exacts :
claude mcp add --transport http --client-id ryKtuiPypMeYMoL1Cmhxtz6BYrEYQbLV --callback-port 8765 palisade https://api.palisade.email/mcp
Codex et les autres clients stdio
Les clients qui exécutent des serveurs stdio, dont Codex, Cursor et Windsurf, utilisent la passerelle publiée, qui enveloppe le serveur distant avec mcp-remote et se connecte avec le même client. Rien à exporter :
codex mcp add palisade -- npx -y @palisadeemail/mcp
La même chose sous forme de configuration de client :
{
"mcpServers": {
"palisade": {
"command": "npx",
"args": ["-y", "@palisadeemail/mcp"]
}
}
}
Outils
Chaque outil agit sur l’organisation à laquelle vous vous êtes connecté, sauf les deux lectures du DNS en vigueur, qui prennent un simple nom de domaine et lisent le DNS public de n’importe quel domaine, qu’il figure dans le compte ou non.
- Compte :
get_account - DNS en vigueur, n’importe quel domaine :
audit_domainnote sur 100 l’ensemble de la configuration SPF/DKIM/DMARC/BIMI/MTA-STS d’un domaine;validate_spf_includeindique ce que coûterait un include SPF par rapport à la limite de 10 recherches avant que vous l’ajoutiez - Domaines :
list_domains,get_domain(l’état d’un domaine du compte, par identifiant ou par nom),create_domain,update_domain,delete_domain,verify_domain - Configuration DNS :
get_dns_records— les enregistrements exacts à publier, avec l’état de chacun - Plan de correction :
get_domain_plan— où en est un domaine dans le parcours DMARC et ce que Palisade fera ensuite, y compris les étapes pour lesquelles il n’a pas encore ouvert de billets - Diagnostics SPF :
get_spf— l’enregistrement en vigueur, son nombre de recherches DNS par rapport à la limite de 10, et les problèmes trouvés - DMARC hébergé et MTA-STS :
enable_hosted_dmarc,get_mta_sts,enable_mta_sts,disable_mta_sts - Billets :
list_tasks,get_task,complete_task,dismiss_task - Rapports DMARC :
get_dmarc_summary,list_dmarc_senders— des chiffres agrégés et des ventilations par source, jamais le XML brut des rapports - Groupes :
list_groups,create_group,update_group,delete_group - Webhooks :
list_webhook_events,list_webhook_endpoints,create_webhook_endpoint,delete_webhook_endpoint - Facturation :
get_subscription,start_checkout,start_billing_portal— le paiement lui-même se fait toujours sur des pages hébergées par Stripe - Rapports de prospection :
create_prospecting_report(jusqu’à dix domaines audités et présentés dans un PDF hébergé derrière un lien Palisade),list_prospecting_reports,get_prospecting_report,delete_prospecting_report - Connexions aux fournisseurs DNS :
list_dns_connections,get_dns_connection,get_dns_connection_coverage— si Palisade peut publier lui-même les enregistrements d’un domaine plutôt que de les remettre pour qu’on les copie - Journal d’activité :
list_activity_log,list_activity_log_actions
Le parcours idéal pour intégrer un domaine : create_domain → get_dns_records → publier les enregistrements chez votre fournisseur DNS → verify_domain → surveiller list_tasks et les rapports → complete_task une fois une correction vérifiée.
ChatGPT
Palisade prend en charge ChatGPT sur le point de terminaison principal https://api.palisade.email/mcp, avec le même client OAuth publié qu’utilise claude.ai. Activez Developer mode sous Settings → Plugins, ouvrez Plugins dans la barre latérale et choisissez Create app, collez le point de terminaison, choisissez OAuth, puis, sous Advanced OAuth settings, réglez Registration method à User-Defined OAuth Client et entrez l’identifiant de client sans secret. Les deux autres méthodes d’inscription font inscrire un client par lui-même et sont refusées; voir plus haut. Palisade ne figure pas dans le répertoire d’applications d’OpenAI, et la présence dans ce répertoire est distincte de la prise en charge de ChatGPT.
Microsoft 365 Copilot
L’administrateur Microsoft 365 de votre organisation doit installer l’agent Palisade dans votre locataire Microsoft 365 et donner accès à votre compte professionnel. Les administrateurs peuvent communiquer avec l’équipe de soutien de Palisade pour obtenir le paquet d’installation et de l’aide pour la configuration. La distribution est gérée par votre organisation; Palisade ne figure pas dans le Microsoft Agent Store public. L’accès dépend des politiques de votre locataire et de vos licences Copilot.
- Ouvrez Microsoft 365 Copilot avec le compte professionnel que votre administrateur a autorisé, puis sélectionnez l’agent Palisade.
- Demandez List my Palisade domains.
- Lorsque vous y êtes invité, connectez-vous à Palisade et choisissez votre organisation Palisade.
- Confirmez que les domaines renvoyés appartiennent à cette organisation.
Votre locataire Microsoft 365 détermine qui peut ouvrir l’agent. L’organisation Palisade et le rôle que vous avez choisis déterminent les données et les actions auxquelles il a accès. L’agent installé comprend ses paramètres de connexion; vous n’avez besoin ni d’une clé d’API, ni d’un identifiant de client OAuth, ni d’un secret de client.
Si l’agent est absent, demandez à votre administrateur Microsoft 365 de vérifier l’installation et l’attribution de votre compte. Si la connexion réussit, mais que les domaines n’apparaissent pas, utilisez Chat settings → Agents → Palisade → Sign out, puis rouvrez l’agent et connectez-vous de nouveau. Si le problème persiste, communiquez avec l’équipe de soutien en indiquant l’erreur et l’heure de la tentative; n’envoyez ni jetons ni secrets.
Pour déconnecter Copilot, ouvrez API et MCP → Assistants connectés dans Palisade et révoquez sa connexion dédiée. Son libellé est le nom d’application Palisade configuré, qui peut être différent du nom de l’agent. Cela ne révoque pas la connexion Palisade partagée qu’utilisent les autres assistants. Un jeton d’accès déjà émis reste valide jusqu’à son expiration.
Point de terminaison de répertoire en lecture seule
https://api.palisade.email/mcp/directory est un deuxième point de terminaison, en lecture seule, qui offre 14 des outils énumérés ci-dessus — surveillance et diagnostic seulement, sans modification ni action de facturation. Il existe pour les clients qui joignent Palisade par un répertoire d’applications public, où la connexion est établie avant que quiconque ait choisi une organisation.
Il diffère de https://api.palisade.email/mcp par la façon dont il détermine votre organisation. Il utilise toujours l’organisation de votre jeton lorsqu’il y en a une; ce qu’il ajoute, c’est une solution de repli lorsqu’il n’y en a pas : il recherche votre compte et prend l’unique organisation qu’il trouve. Ce repli ne fonctionne que si la réponse est sans ambiguïté; un compte qui n’appartient à aucune organisation active reçoit donc un 403, tout comme un compte qui appartient à plus d’une organisation, parce que la connexion ne peut pas choisir sans risque. Le point de terminaison principal n’a pas de repli et refuse simplement un jeton sans organisation.
Pour un jeton OAuth sans organisation, la connexion de répertoire standard exige les quatre autorisations domains:read, groups:read, tasks:read et dmarc_reports:read. Palisade reconnaît aussi les propres clients OAuth de ChatGPT, c’est-à-dire les clients tiers qui ne peuvent terminer la connexion qu’en redirigeant vers https://chatgpt.com : quand l’un d’eux ne reçoit que offline_access et aucune autorisation d’API, le point de terminaison de répertoire déduit un accès en lecture du rôle de l’utilisateur dans son unique organisation active. Cette exception est propre à ces clients; les autres connexions sans organisation qui n’ont pas les quatre autorisations de lecture reçoivent un 401 qui nomme les autorisations requises dans l’en-tête WWW-Authenticate :
WWW-Authenticate: Bearer resource_metadata="https://api.palisade.email/.well-known/oauth-protected-resource/mcp/directory", scope="domains:read groups:read tasks:read dmarc_reports:read"
Vous avez besoin d’une organisation Palisade avant de vous connecter. Chaque outil MCP agit sur une organisation; connectez-vous donc à app.palisade.email (ou créez un compte avec l’inscription sans interface) avant d’ajouter le connecteur. Une connexion sans organisation renvoie un 403 qui indique où en créer une.
Point de terminaison d’audit public
https://api.palisade.email/mcp/public est un troisième point de terminaison qui ne demande ni compte, ni organisation, ni identifiants. Il n’offre que les deux outils qui lisent le DNS public de n’importe quel domaine : audit_domain, qui note sur 100 l’ensemble de la configuration SPF/DKIM/DMARC/BIMI/MTA-STS d’un domaine, et validate_spf_include, qui calcule ce que coûte un include SPF par rapport à la limite de 10 recherches avant que vous l’ajoutiez. Ni l’un ni l’autre ne lit quoi que ce soit qui appartient à Palisade; il n’y a donc aucune organisation à laquelle les limiter, et des identifiants envoyés à ce point de terminaison sont ignorés plutôt que vérifiés.
C’est l’équivalent MCP du point de terminaison REST anonyme GET /tools/audit. Sa limite de débit s’applique par adresse de client plutôt que par identité, dans une catégorie DNS qui lui est propre, dimensionnée comme la portée dns décrite sous Limites de débit, mais non partagée avec elle; un appel au-delà de la limite revient sous forme d’erreur d’outil dont l’error.scope est mcp_dns et qui porte retry_after_seconds. Tout client qui parle Streamable HTTP s’y connecte sans rien configurer :
claude mcp add --transport http palisade-audit https://api.palisade.email/mcp/public
Tout le reste — la surveillance, les enregistrements à publier, DMARC hébergé, les rapports et les billets — se trouve sur https://api.palisade.email/mcp et exige une organisation Palisade.
Erreurs
Palisade utilise les codes de réponse HTTP standard pour indiquer si une requête à l’API a réussi ou non.
- Les codes de la plage 2xx signifient que la requête a réussi.
- Les codes de la plage 4xx signifient que la requête comportait une erreur (par exemple, un paramètre manquant ou une requête qui a échoué).
- Les codes de la plage 5xx signifient qu’un problème est survenu du côté de Palisade.
Les erreurs des points de terminaison de la référence de l’API sont des corps JSON qui portent un code en minuscules sur lequel vous pouvez vous fonder et un message rédigé pour une personne; certaines ajoutent un param qui nomme le champ fautif ou un objet details qui donne plus de précisions. L’entrée de chaque point de terminaison dans la référence documente les formes d’erreur qu’il peut renvoyer. Deux erreurs sont renvoyées avant qu’un point de terminaison soit atteint et ont donc la même forme dans toute l’API : une requête sans identifiants de clé d’API valides reçoit un 401 avec code: "unauthorized" et un en-tête WWW-Authenticate, et un chemin qui ne correspond à aucune route reçoit un 404 avec code: "not_found" et, sous details, des liens vers ce guide et vers le document OpenAPI, pour qu’un client qui a deviné une URL puisse trouver la bonne :
{
"code": "not_found",
"message": "No API route matches this request.",
"details": {
"documentation": "https://developer.palisade.email/docs/guide",
"openapi": "https://api.palisade.email/swagger.json"
}
}
Le 401 a la même forme. Son message indique si aucun identifiant n’a été envoyé ou si la clé n’a pas été acceptée, details.documentation pointe vers Authentification, et l’en-tête WWW-Authenticate nomme les deux mécanismes que l’API accepte : Basic pour une clé d’API et Bearer pour un jeton de session du tableau de bord. Une requête faite par un navigateur avec fetch reçoit un défi Bearer seulement, parce qu’un défi Basic ferait ouvrir au navigateur sa propre boîte de dialogue de connexion par-dessus l’application.
HTTP/1.1 401 Unauthorized
WWW-Authenticate: Basic realm="palisade", Bearer realm="palisade"
{
"code": "unauthorized",
"message": "The API key is not valid, has been rotated, or has been revoked.",
"details": {
"documentation": "https://developer.palisade.email/docs/guide#authentication"
}
}
Un client qui envoie Accept: text/plain ou Accept: text/html reçoit plutôt la ligne d’état en texte brut pour l’une ou l’autre erreur, ce que les deux renvoyaient avant que ce contrat existe; tout le reste, y compris l’absence d’en-tête Accept, reçoit le JSON.
Versions
Chaque version majeure de Palisade peut comporter des changements non rétrocompatibles; la mise à niveau pourrait donc exiger des modifications à votre code existant. La version majeure actuelle est 2025-04-30. Il n’y a pour l’instant aucun calendrier de publication fixe, mais nous nous engageons à maintenir les versions majeures pendant au moins un an.
Les clients qui utilisent une clé d’API doivent indiquer explicitement la version de l’API dans chaque requête, au moyen de l’en-tête Palisade-Version; toute requête avec une clé d’API qui ne contient pas de version valide échoue. Les sessions du tableau de bord (JWT) utilisent la plus récente version par défaut quand l’en-tête est omis.
Limites de débit
L’API applique des catégories de limite de débit indépendantes : une catégorie globale pour chaque requête, une catégorie par clé d’API pour chaque requête authentifiée avec une clé d’API, et des catégories DNS (dont une plus stricte par clé d’API) pour les points de terminaison qui déclenchent une résolution DNS sortante. Chaque réponse porte les en-têtes RateLimit-Limit, RateLimit-Remaining et RateLimit-Reset; les réponses 429 ajoutent Retry-After. Respectez les en-têtes — ne codez pas les limites en dur. Le contrat complet est documenté dans l’introduction de la référence de l’API.
Pagination
Toutes les ressources de premier niveau de l’API Palisade permettent la récupération en lot au moyen de méthodes de « liste ». Par exemple, vous pouvez lister les domaines, les groupes ou les billets. Ces méthodes de liste suivent une structure uniforme et acceptent au moins deux paramètres : page et per_page.
Chaque méthode de « liste » renvoie l’état actuel de la pagination dans le champ page_info. Ce champ comprend aussi le nombre total de ressources qui correspondent aux filtres fournis.
Développer les réponses
Palisade vous permet de demander des détails supplémentaires dans les réponses de l’API au moyen du paramètre de requête expand. Ce paramètre fonctionne avec toutes les requêtes à l’API et ne touche que la réponse à cette requête précise.
Beaucoup d’objets de Palisade ne renvoient que l’identifiant des objets liés. Par exemple, un domaine peut comporter l’identifiant d’un groupe. Avec le paramètre expand, vous pouvez demander à Palisade d’inclure l’objet groupe complet plutôt que son seul identifiant. Les champs qui peuvent être développés sont indiqués dans le paramètre expand.
Certains champs, comme les données sensibles ou facultatives, ne sont pas inclus par défaut. Vous pouvez aussi les demander avec le paramètre expand.
Vous ne pouvez utiliser expand qu’avec des requêtes d’obtention ou de liste, et vous pouvez développer plusieurs champs à la fois en incluant plusieurs éléments dans le tableau expand. Gardez à l’esprit que développer en profondeur les réponses de liste peut ralentir les choses.
Webhooks
Plutôt que d’interroger l’API à intervalles réguliers pour repérer les changements, vous pouvez inscrire un point de terminaison HTTPS, et Palisade lui enverra un événement par POST chaque fois que quelque chose se produit dans votre compte. Gérez les points de terminaison sous /webhook-endpoints; le catalogue des événements est disponible à GET /webhook-events.
Catalogue des événements
Le tableau ci-dessous est généré à partir du même catalogue que celui selon lequel l’émetteur valide et que sert GET /webhook-events; il ne peut donc pas s’écarter de ce que Palisade envoie réellement. Les noms d’événements ne font que s’ajouter : de nouveaux noms apparaissent, mais les noms existants ne sont jamais renommés ni réaffectés. Traitez un type inconnu comme quelque chose à ignorer plutôt que comme une erreur.
| Événement | Déclenché quand | data.object |
|---|---|---|
domain.created | Un domaine a été ajouté à l’organisation. | domain |
domain.updated | Un domaine a changé. Se déclenche lors des transitions d’état de surveillance, des changements de score et des mises à jour de configuration. | domain |
domain.deleted | Un domaine a été retiré de l’organisation. | domain |
domain.monitoring.activated | Un domaine a atteint la surveillance DMARC complète pour la première fois. L’atteindre de nouveau après une interruption correspond à domain.monitoring.recovered. | domain |
domain.monitoring.failed | La surveillance n’a pas pu être établie ou a été perdue. L’objet domaine porte monitoring_failure_reason, qui indique si l’enregistrement est absent, se trouve seulement sur le parent, n’a pas le rua de Palisade, et ainsi de suite. | domain |
domain.monitoring.drifted | Un domaine qui était configuré ne résout plus les enregistrements que Palisade attend. | domain |
domain.monitoring.recovered | Un domaine est revenu à la surveillance complète après une dérive ou un échec. | domain |
domain.hosted_record.ready | Un enregistrement hébergé par Palisade est en service. data.record indique lequel : dmarc, spf, dkim, bimi ou mta_sts. | domain |
domain.hosted_record.error | Un enregistrement hébergé par Palisade est en erreur. data.record indique lequel. Le rétablissement est détecté par un rapprochement horaire; l’événement ready correspondant peut donc arriver une heure ou plus en retard. | domain |
domain.score_changed | Un domaine a franchi une tranche de score — critical, bad, good ou great — plutôt que de simplement gagner ou perdre un point. La nouvelle tranche est score_band sur l’objet domaine; data.previous_attributes porte l’ancien score et l’ancienne tranche. | domain |
domain.policy_changed | La politique DMARC du domaine a changé, par exemple de none à quarantine, puis à reject. data.previous_attributes porte l’ancienne politique. | domain |
mta_sts.enabled | MTA-STS hébergé par Palisade a été activé pour un domaine. | mta_sts |
mta_sts.updated | Une politique MTA-STS a été modifiée, par exemple son mode ou ses hôtes MX. | mta_sts |
mta_sts.disabled | MTA-STS hébergé par Palisade a été désactivé pour un domaine. | mta_sts |
task.opened | Un billet de correction a été ouvert et est resté ouvert pendant toute la période de stabilisation. Pas en temps réel : consultez les notes sur les délais de livraison dans le guide de l’API. | task |
task.completed | Un billet a été résolu. | task |
task.canceled | Palisade a déterminé que le billet ne s’applique plus et l’a fermé. Distinct de task.dismissed, qui correspond à une personne qui le rejette. | task |
task.dismissed | Quelqu’un a écarté le billet. Distinct de task.canceled, qui correspond à Palisade qui le ferme automatiquement. | task |
task.reopened | Un billet qui avait été résolu ou annulé est revenu. Abonnez-vous à cet événement en plus de task.completed; sinon, un billet fermé à l’achèvement n’apprendra jamais que le travail est revenu. | task |
organization.updated | Les renseignements ou les paramètres de l’organisation ont changé. | organization |
member.added | Un compte Palisade existant a été ajouté à l’organisation. | member |
member.updated | Les rôles d’un membre ou son accès aux groupes ont changé. | member |
member.removed | Un membre a été retiré de l’organisation. | member |
invitation.created | Quelqu’un a été invité à se joindre à l’organisation. | invitation |
invitation.revoked | Une invitation en attente a été retirée. Il n’y a délibérément aucun événement invitation.accepted : l’acceptation se fait dans Auth0, et Palisade ne peut pas l’observer en temps réel pour l’instant. | invitation |
group.created | Un groupe a été créé. | group |
group.updated | Un groupe a été renommé ou ses paramètres ont changé. | group |
group.deleted | Un groupe a été supprimé. | group |
Les événements TLS-RPT ne figurent pas dans le catalogue. Les rapports sont ingérés par un pipeline distinct qui n’a aucun canal de retour vers l’API; ce service n’a donc rien à observer. Interrogez plutôt GET /domains/{domainId}/tls-reports.
Charges utiles des événements
Chaque livraison a la même enveloppe. data.object est la ressource touchée, sous la forme que renvoie l’API REST. Pour les événements qui concernent quelque chose qui n’existe plus, c’est la ressource telle qu’elle était juste avant sa suppression. Le seul cas qui peut être plus mince est invitation.revoked : une invitation supprimée au moyen de l’identifiant brut du fournisseur n’est jamais relue; cette charge utile ne porte donc que {id, object}. Une suppression au moyen de l’identifiant que renvoie GET /invitations — ce que fait l’API — donne l’objet complet.
{
"id": "evt_9f2c1b7d8e4a5c3b0d6f1a2e3c4b5d6e",
"type": "domain.updated",
"api_version": "2025-04-30",
"created": "2026-08-11T14:02:11.482Z",
"data": { "object": { "id": "...", "url": "example.com", "monitoring_status": "setup" } }
}
Vérifier les signatures
Chaque requête porte un en-tête Palisade-Signature de la forme t=<unix seconds>,v1=<hex>. La signature est un HMAC-SHA256, calculé avec le secret de signature de votre point de terminaison, sur la chaîne <timestamp>.<raw request body>. Vérifiez la signature sur le corps brut — sérialiser de nouveau le JSON analysé change les octets, et la signature ne correspondra pas.
import crypto from 'node:crypto';
function verify(rawBody, header, secret, toleranceSeconds = 300) {
if (!header) return false;
const parts = Object.fromEntries(
header.split(',').map((p) => p.split('=').map((s) => s.trim())),
);
const timestamp = Number(parts.t);
if (!Number.isInteger(timestamp)) return false;
if (Math.abs(Math.floor(Date.now() / 1000) - timestamp) > toleranceSeconds) return false;
if (!parts.v1) return false;
const expected = crypto.createHmac('sha256', secret).update(timestamp + '.' + rawBody).digest('hex');
const a = Buffer.from(expected, 'hex');
const b = Buffer.from(parts.v1, 'hex');
// timingSafeEqual throws on a length mismatch, and Buffer.from silently drops non-hex
// characters, so both have to be checked before comparing.
if (a.length !== b.length) return false;
return crypto.timingSafeEqual(a, b);
}
import hashlib, hmac, time
def verify(raw_body: bytes, header: str, secret: str, tolerance: int = 300) -> bool:
if not header:
return False
try:
parts = dict(p.strip().split("=", 1) for p in header.split(","))
timestamp = int(parts["t"])
received = parts["v1"]
except (ValueError, KeyError):
return False
if abs(int(time.time()) - timestamp) > tolerance:
return False
signed = f"{timestamp}.".encode() + raw_body
expected = hmac.new(secret.encode(), signed, hashlib.sha256).hexdigest()
return hmac.compare_digest(expected, received)
Le secret de signature est renvoyé une fois, à la création du point de terminaison, puis seulement si vous appelez POST /webhook-endpoints/{id}/rotate-secret. Le renouvellement prend effet immédiatement; les livraisons signées avec l’ancien secret échoueront donc à la vérification.
Garanties de livraison
- Au moins une fois. Le même événement peut arriver plus d’une fois. Chaque livraison porte le même
idd’une tentative à l’autre; dédoublonnez donc sur cette valeur et rendez votre traitement idempotent. - Sans ordre garanti. Lors des nouvelles tentatives, un événement plus ancien peut arriver après un plus récent. Comparez les horodatages de l’objet plutôt que de supposer que l’ordre d’arrivée reflète ce qui s’est passé.
- Répondez rapidement. Renvoyez un 2xx dans les 10 secondes. Faites le travail de façon asynchrone; un traitement lent est interprété comme une livraison échouée.
- Nouvelles tentatives. Les 5xx, 408, 429, délais d’attente dépassés et erreurs de connexion font l’objet de nouvelles tentatives avec un délai exponentiel. Les autres réponses 4xx sont traitées comme un refus délibéré et ne sont pas retentées.
- Désactivation automatique. Après 20 échecs consécutifs sur différents événements, un point de terminaison passe à
AUTO_DISABLEDet cesse de recevoir des livraisons jusqu’à ce que vous le réactiviez. La réactivation remet le compteur d’échecs à zéro. - Les redirections ne sont pas suivies. Inscrivez l’URL finale.
Examinez ce qui s’est passé avec GET /webhook-endpoints/{id}/deliveries, qui renvoie les tentatives récentes avec leur code d’état de réponse et leur erreur. Les enregistrements de livraison sont conservés 30 jours, puis supprimés; traitez donc la liste comme une aide au débogage plutôt que comme des archives — si vous avez besoin d’un registre permanent des événements, conservez-les à leur réception. L’historique survit au point de terminaison : vous pouvez encore le lire après avoir supprimé le point de terminaison auquel il appartenait, ce qui est habituellement le moment où vous en avez besoin.
Délais à prévoir
Les événements reflètent un état validé; un domain.updated décrit donc toujours quelque chose qui est déjà vrai. Trois délais méritent d’être pris en compte dans votre conception.
- Les événements de billets sont délibérément retardés de quatre heures. Les billets fraîchement détectés sont instables (une vérification peut en ouvrir un et la suivante le résoudre); un billet doit donc garder son état pendant cette période avant qu’un événement soit envoyé. Deux conséquences : un billet visible dans le tableau de bord ou par
GET /tasksn’aura pas encore produit detask.opened, et un billet qui s’ouvre et se résout pendant cette période ne produit aucun événement plutôt qu’une paire correspondante. Si vous avez besoin d’immédiateté, interrogez/tasks; si vous avez besoin de calme, utilisez le webhook. - Le rétablissement des enregistrements hébergés passe par une vérification horaire; un enregistrement qui recommence à fonctionner peut donc prendre une heure ou plus à le signaler.
- Les transitions de surveillance des domaines proviennent d’une vérification périodique plutôt que d’un flux en direct; elles ne sont donc pas instantanées.
En raison du premier point, abonnez-vous à task.reopened en plus de task.completed. Sinon, un billet fermé à l’achèvement n’apprendra jamais que le travail est revenu.
domain.score_changed se déclenche quand un domaine franchit une tranche plutôt qu’à chaque point. La tranche dans laquelle il est passé est score_band sur l’objet domaine, et celle qu’il a quittée se trouve dans data.previous_attributes; vous n’avez donc jamais à réimplémenter les seuils.