Aller au contenu

Pour commencer

Les plus lues

API

Vue d'ensemble de l'API v1 : le jeton Bearer, les 4 routes, les quotas par plan, les codes d'erreur et le format des réponses.

Mis à jour le 25 septembre 2026

Sur cette page

L'API de PostShip fait 2 choses, et 2 seulement : lancer une vérification sur une URL — la même que le cycle — et lire l'état de vos projets depuis vos propres outils. Tout est en JSON, sur https://postship.fr/api/v1/, avec un jeton en en-tête. Aucune route n'écrit dans un projet, et il n'en existera pas : un jeton d'API vit dans une variable d'environnement de CI, et une suppression au bout de celui-là serait à un copier-coller de distance. Ce qui modifie un projet passe par l'application, où quelqu'un est connecté.

Authentification

Une clé psk_…, créée depuis Réglages de l'espace → API, passée dans l'en-tête Authorization. La même clé sert à toutes les routes.

export POSTSHIP_TOKEN=psk_…

curl -sS https://postship.fr/api/v1/projects \
  -H "Authorization: Bearer $POSTSHIP_TOKEN"

La clé passe par une variable d'environnement, jamais en argument d'une commande : un argument se lit dans la liste des processus du runner, où le masquage des secrets ne s'applique pas. Un jeton invalide ou révoqué répond 401 avec {"error":"Clé d'API invalide ou révoquée."}, sur toutes les routes de la même façon. PostShip ne garde que l'empreinte SHA-256 du jeton et note la date de sa dernière utilisation — c'est ce qui permet d'en révoquer un sans se demander s'il tourne encore quelque part.

Un jeton voit exactement ce que son propriétaire voit : ses projets, et ceux qu'on lui a partagés en tant que membre accepté. Une invitation en attente n'en est pas un.

Les routes

MéthodeRouteCe qu'elle faitQuota
POST/api/v1/checkVérifie une URL maintenant et rend le Ship Score (référence)Compté
GET/api/v1/projectsVos projets : identifiant, nom, adresse, dernier état (référence)Libre
GET/api/v1/projects/{id}/incidentsLes URL en échec en ce moment, et depuis quandLibre
GET/api/v1/projects/{id}/last-shipLe dernier déploiement de production, avec son scoreLibre

La lecture ne consomme pas votre compteur mensuel. Ce compteur paie du travail réel — des requêtes vers votre site ; une lecture ne coûte qu'une requête à notre base. Les mélanger vous ferait payer un tableau de bord au prix d'une sonde.

Le format

Les réponses sont en JSON, en UTF-8, avec Cache-Control: no-store sur les lectures : une réponse d'API ne se met pas en cache. Les dates sont en ISO 8601 (UTC). Les erreurs portent toujours un champ error avec une phrase en français, et parfois un champ de plus (quota sur un 429) :

{ "error": "Quota mensuel atteint (500/500 vérifications).", "quota": { "used": 500, "limit": 500, "remaining": 0 } }

Les codes HTTP

CodeQuandCorps
200Tout s'est bien passéLa ressource
400URL refusée sur /check : pas en https, identifiants dans l'URL, hôte privé ou introuvable{"error":"…"} avec la raison exacte
401Clé absente, mal formée, inconnue ou révoquée{"error":"Clé d'API invalide ou révoquée."}
404Projet inconnu — ou que ce jeton n'a pas le droit de voir{"error":"Projet introuvable."}
429Quota mensuel de vérifications atteint{"error":"…", "quota":{…}}

Un projet qui n'existe pas et un projet qu'on n'a pas le droit de voir répondent la même chose. Les distinguer confirmerait l'existence d'un identifiant à qui le devine — et un identifiant confirmé est la moitié du travail d'un inventaire.

Limites et plans

Les vérifications lancées par l'API sont comptées par mois calendaire (UTC) et par espace, tous jetons de l'espace confondus.

DécouverteProPro Plus
Vérifications par mois305003000
Lectures (projects, incidents, last-ship)IllimitéesIllimitéesIllimitées
Jetons actifs555

Au-delà du quota, l'appel est refusé avec le compte exact — jamais un résultat dégradé : une CI qui ment est pire qu'une CI qui casse. La place est prise avant la vérification, de façon atomique : 100 appels lancés en parallèle ne passent pas tous sous la limite. Le compteur du mois se lit dans Réglages de l'espace → API (« 12/500 vérifications de CI ce mois-ci »). Voir les plans.

Dépannage

Pourquoi 401 alors que le jeton vient d'être créé ?

Vérifiez l'en-tête : Authorization: Bearer psk_…, avec l'espace après Bearer, et le jeton entier — il commence par psk_ et n'est affiché qu'une fois. Un jeton révoqué ne revient pas : créez-en un autre.

Pourquoi 404 sur un projet que je vois dans l'application ?

Le jeton appartient à un autre compte que celui qui voit le projet, ou vous êtes invité sur ce projet sans avoir accepté l'invitation. Un jeton ne voit que les projets de son propriétaire et ceux où il est membre accepté.

Pourquoi le quota a-t-il baissé sans que ma CI ait tourné ?

Le compteur est par espace : un autre jeton du même espace consomme la même réserve, et un jeton d'un autre espace a la sienne. La date de dernière utilisation de chaque jeton, dans Réglages de l'espace → API, dit lequel a servi.

POST /api/v1/check

La référence complète de la vérification à la demande : le corps, chaque champ de la réponse, les codes HTTP, et des exemples curl, JavaScript et GitHub Actions.

POST https://postship.fr/api/v1/check vérifie une URL publique maintenant, avec le même moteur que le cycle — les 6 vérifications d'une URL — et rend le résultat dans la réponse, en synchrone. Une CI qui devrait interroger une file d'attente attendrait plus longtemps qu'elle ne met à vérifier, et chaque sondage serait une occasion de plus de se tromper. Comptez jusqu'à 60 secondes.

La requête

MéthodePOST
En-têtesAuthorization: Bearer psk_… et Content-Type: application/json
Corps{"url": "https://votre-site.fr/page"} — une seule clé, url, en https

L'URL doit être en https, sans identifiants (https://user:pass@… est refusé), et mener vers un hôte public : la même garde que pour toute URL surveillée, parce qu'un jeton valide n'autorise pas à faire pointer notre sonde sur un réseau privé. Une URL refusée ne consomme pas de quota : elle est contrôlée avant la réservation.

Depuis un terminal
export POSTSHIP_TOKEN=psk_…

curl -sS -X POST https://postship.fr/api/v1/check \
  -H "Authorization: Bearer $POSTSHIP_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"url":"https://votre-site.fr"}'

La réponse

200 avec un objet JSON :

{
  "url": "https://votre-site.fr/",
  "score": 75,
  "reason": "−25 asset manquant",
  "outcome": "fail",
  "failed": 1,
  "checks": [
    { "kind": "http", "label": "Page et ressources", "outcome": "fail", "detail": "2 ressources déclarées mais absentes" },
    { "kind": "index", "label": "Indexabilité", "outcome": "pass", "detail": "Crawlable, canonical cohérent" },
    { "kind": "og", "label": "Carte sociale", "outcome": "pass", "detail": "Titre et image valides" },
    { "kind": "sitemap", "label": "Sitemap", "outcome": "skip", "detail": "Aucun sitemap déclaré" },
    { "kind": "ssl", "label": "Certificat SSL", "outcome": "pass", "detail": "61 jours avant expiration" },
    { "kind": "ia", "label": "Visibilité IA", "outcome": "pass", "detail": "Lisible et citable par les moteurs de réponse" }
  ],
  "quota": { "used": 12, "limit": 500, "remaining": 488 }
}
ChampTypeCe qu'il contient
urlstringL'URL vérifiée, normalisée
scorenumberLe Ship Score, de 0 à 100, calculé par la fonction qui note un vrai déploiement
reasonstring ou nullLa retenue principale (« −30 site non indexable »), null quand tout est passé
outcome"pass" ou "fail"pass si aucune ligne n'est en fail ni en error ; c'est le champ sur lequel faire échouer une étape
failednumberLe nombre de lignes en fail ou error
checks[]arrayUne ligne par vérification (voir ci-dessous)
checks[].kindstringhttp, index, og, sitemap, ssl, ia
checks[].labelstringLe nom lisible : Page et ressources, Indexabilité, Carte sociale, Sitemap, Certificat SSL, Visibilité IA
checks[].outcomestringpass, fail, error (PostShip n'a pas pu conclure : délai, DNS), ou skip (rien à vérifier — un site sans sitemap)
checks[].detailstringUne phrase, celle qu'une personne dirait : « Statut 200 · 412 ms », « ChatGPT ne peut pas vous lire »
quota.usednumberLes vérifications consommées ce mois-ci, celle-ci comprise
quota.limitnumberLe plafond du plan : 30, 500 ou 3000
quota.remainingnumberCe qui reste

Une ligne skip ne pèse pas sur la note ni sur outcome : un site sans sitemap n'a rien cassé. Une ligne error compte comme un échec — un certificat illisible ou une page qui ne répond pas dans les délais est un problème, pas une absence de problème.

Ce que les 6 lignes regardent est décrit sur la page Les 6 vérifications d'une URL : c'est le même audit, sous un budget de 40 requêtes vers le site.

Les codes HTTP

CodeQuandCorps
200La vérification a eu lieu, quel que soit son verdictL'objet ci-dessus
400Corps illisible ou sans url{"error":"URL invalide (https requis)."}
400URL refusée{"error":"L'URL doit être en https."}, {"error":"URL invalide (identifiants non autorisés)."}, ou la raison de la garde réseau
401Clé invalide ou révoquée{"error":"Clé d'API invalide ou révoquée."}
429Quota du mois atteint{"error":"Quota mensuel atteint (500/500 vérifications).","quota":{"used":500,"limit":500,"remaining":0}}

Un 200 avec outcome: "fail" est une réponse normale : le site a un problème. Un 4xx veut dire que la vérification n'a pas eu lieu. Une CI doit distinguer les deux — voir Vérifier depuis votre CI pour les codes de sortie.

Limites et plans

DécouverteProPro Plus
Vérifications par mois305003000

Par mois calendaire (UTC) et par espace, tous jetons de l'espace confondus. La place est réservée avant l'audit, atomiquement : des appels lancés en parallèle ne dépassent pas la limite. Voir API et les plans.

Dépannage

Pourquoi la réponse met-elle 20 secondes ?

Les 6 vérifications tournent en parallèle sous un budget partagé ; la réponse arrive dans le temps de la plus lente, en général celle des ressources ou du sitemap sur un site lent. Prévoyez un délai d'au moins 60 secondes côté client.

Pourquoi outcome est-il fail alors que le score est à 90 ?

Une ligne en error fait échouer outcome mais ne coûte que 10 points (« URL en échec »). C'est voulu : un score sert à comparer, un verdict sert à bloquer. Regardez checks[] pour la ligne en cause.

Pourquoi la ligne sitemap est-elle skip alors que mon sitemap existe ?

Il n'est pas déclaré dans robots.txt (Sitemap:) et n'est pas à /sitemap.xml sur la même origine. Déclarez-le dans robots.txt : c'est là que les moteurs le cherchent aussi.

GET /api/v1/projects

La référence des routes de lecture : vos projets, le détail d'un projet, ses incidents ouverts, son dernier déploiement, son historique de production, et votre compte.

6 routes, toutes en lecture, toutes en JSON, pour lire l'état de vos projets depuis vos propres outils : un tableau de bord interne, un script du lundi matin, un bot. Aucune n'écrit quoi que ce soit, et il n'existe pas de route qui le fasse. Aucune ne consomme votre quota mensuel de vérifications. Le jeton est celui de l'API, en en-tête Authorization: Bearer.

GET /api/v1/projects

Ce que ce jeton a le droit de voir : les projets possédés par le compte et ceux où il est membre accepté, dans l'ordre de création.

export POSTSHIP_TOKEN=psk_…

curl -sS https://postship.fr/api/v1/projects \
  -H "Authorization: Bearer $POSTSHIP_TOKEN"
{
  "projects": [
    {
      "id": "3f1c…",
      "name": "Boutique",
      "url": "https://boutique.fr",
      "status": "pass",
      "lastCheckedAt": "2026-09-11T08:42:10.000Z",
      "paused": false
    }
  ]
}
ChampTypeCe qu'il contient
idstringL'identifiant du projet, à passer aux 2 routes suivantes
namestringLe nom du projet
urlstringL'adresse de production déclarée
status"pass", "fail" ou nullLe dernier état résumé : fail dès qu'une cible active est en fail ou en error ; null avant le premier passage
lastCheckedAtstring ou nullLa date du dernier passage complet, ISO 8601
pausedbooleanLe projet est en pause : rien ne tourne

Un compte sans projet reçoit {"projects":[]}. Les colonnes sont nommées une par une côté serveur : un select("*") ferait sortir les secrets de webhook et les jetons d'hébergeur le jour où quelqu'un ajoute une colonne, sans que personne n'ait rien décidé.

GET /api/v1/projects/{id}/incidents

Ce qui est en panne en ce moment, et depuis quand. Ce sont les incidents au sens de l'application — des cibles actives dont le dernier verdict est fail ou error — et non les incidents publiés sur la page de statut, qui sont un récit choisi par le propriétaire. Les 2 portent le même nom et ne disent pas la même chose ; celui-ci est le fait brut.

curl -sS https://postship.fr/api/v1/projects/3f1c…/incidents \
  -H "Authorization: Bearer $POSTSHIP_TOKEN"
{
  "incidents": [
    { "url": "https://boutique.fr/checkout", "kind": "http", "outcome": "fail", "since": "2026-09-11T08:40:02.000Z" },
    { "url": "https://boutique.fr", "kind": "securite", "outcome": "fail", "since": "2026-09-10T17:12:44.000Z" }
  ]
}
ChampTypeCe qu'il contient
urlstringL'URL de la cible (pour un contrôle du site, l'URL de base du projet)
kindstringLe type de vérification : http, og, sitemap, ssl, form, journey, api, heartbeat, et les contrôles du site (securite, cookies, exposition, certificats, integrite…)
outcome"fail" ou "error"fail : le site a répondu faux ; error : PostShip n'a pas pu conclure
sincestringLe début du dernier passage de cette cible, ISO 8601

Une cible désactivée garde son dernier verdict pour toujours : c'est une trace, pas une panne, et elle n'apparaît pas ici. Un projet sans rien en échec rend {"incidents":[]}.

GET /api/v1/projects/{id}/last-ship

Le dernier déploiement de production, et pas le dernier tout court : une preview vérifiée il y a 2 minutes ne dit rien de ce qui est en ligne, et une intégration qui afficherait son score comme celui du site se tromperait sans jamais le savoir. Même règle que l'Aperçu et que le résumé hebdomadaire.

curl -sS https://postship.fr/api/v1/projects/3f1c…/last-ship \
  -H "Authorization: Bearer $POSTSHIP_TOKEN"
{
  "lastShip": {
    "provider": "vercel",
    "sha": "a1b2c3d",
    "at": "2026-09-11T08:39:51.000Z",
    "outcome": "pass",
    "failedChecks": 0,
    "score": 100,
    "scoreReason": null
  }
}
ChampTypeCe qu'il contient
providerstringL'origine du déploiement : vercel, netlify, cloudflare, generic (le webhook générique) ou empreinte (la détection sans webhook)
shastring ou nullLe commit, quand l'hébergeur l'a transmis
atstringLe début du déploiement, ISO 8601
outcomestringLe verdict de la vérification qui a suivi
failedChecksnumberLe nombre de vérifications en échec
scorenumber ou nullLe Ship Score, null tant que la notation n'a pas eu lieu
scoreReasonstring ou nullLa retenue principale, null quand tout est passé

Un projet sans déploiement de production suivi rend {"lastShip":null} — pas un 404, qui voudrait dire « projet introuvable ».

GET /api/v1/me

Le plan, le quota de vérifications du mois et le jeton qui parle. Rien du compte lui-même : pas d'adresse email, pas de nom.

curl -sS https://postship.fr/api/v1/me \
  -H "Authorization: Bearer $POSTSHIP_TOKEN"
{
  "plan": "pro",
  "quota": { "used": 12, "limit": 500, "remaining": 488 },
  "token": { "prefix": "psk_ab12cd", "name": "CI du site", "lastUsedAt": "2026-09-16T08:42:00.000Z" }
}

GET /api/v1/projects/{id}

Le détail d'un projet : ses URLs surveillées, sa page de statut, s'il est en pause.

curl -sS https://postship.fr/api/v1/projects/3f1c… \
  -H "Authorization: Bearer $POSTSHIP_TOKEN"
{
  "project": {
    "id": "3f1c…",
    "name": "Boutique",
    "url": "https://boutique.fr",
    "status": "pass",
    "lastCheckedAt": "2026-09-16T08:42:00.000Z",
    "paused": false,
    "createdAt": "2026-06-01T10:00:00.000Z",
    "statusPage": "boutique",
    "urls": [
      { "id": "…", "url": "https://boutique.fr/checkout", "kind": "http", "enabled": true, "outcome": "pass", "lastCheckedAt": "2026-09-16T08:42:00.000Z" }
    ]
  }
}

statusPage est le slug de la page publiée (/s/<slug>), null sans page. Un projet d'un autre compte rend le même 404 qu'un projet inexistant.

GET /api/v1/projects/{id}/ships

L'historique des déploiements de production, les plus récents d'abord — pas les previews. ?limit=20 par défaut, 100 au plus.

curl -sS "https://postship.fr/api/v1/projects/3f1c…/ships?limit=20" \
  -H "Authorization: Bearer $POSTSHIP_TOKEN"
{ "ships": [ { "id": "…", "provider": "vercel", "sha": "a1b2c3d", "at": "2026-09-11T08:39:51.000Z", "outcome": "pass", "failedChecks": 0, "score": 100, "scoreReason": null } ] }

Les champs sont ceux de last-ship, plus id.

Codes et erreurs

CodeQuand
401Clé invalide ou révoquée
404Projet inconnu, ou que ce jeton n'a pas le droit de voir — même réponse dans les deux cas

Les réponses portent Cache-Control: no-store. Pas de pagination : un compte possède 10 projets au plus, et un projet 50 URL au plus.

Limites et plans

Aucune limite propre : les lectures ne sont pas comptées. Le nombre de projets et d'URL visibles est celui du plan (voir les plans).

Dépannage

Pourquoi status est-il fail alors que toutes mes URL sont vertes ?

Les contrôles du site comptent aussi : un contrôle en error (annuaire des certificats injoignable, page en délai) suffit. La route incidents dit lequel.

Pourquoi lastShip est-il null alors que je déploie ?

Aucun déploiement de production n'a été reçu : ni webhook, ni détection par empreinte. Les previews ne comptent pas ici.

Pourquoi les incidents de l'API ne correspondent-ils pas à ma page de statut ?

Ce ne sont pas les mêmes objets. L'API rend les cibles en échec maintenant ; la page de statut montre les incidents que vous avez publiés, avec un résumé et un état. Un incident publié puis résolu reste sur la page, pas dans l'API.

Les 6 vérifications d'une URL

Ce que l'audit d'une URL seule regarde — celui de l'API et de postship check —, et comment il la note.

Une URL seule, sans projet : c'est ce que vérifient l'API et la commande postship check. 6 lignes et un Ship Score, calculés par les mêmes fonctions que le cycle de vérification et notés comme un vrai déploiement.

Ce qui est vérifié

6 vérifications, lancées en parallèle sous un budget partagé de 40 requêtes vers le site visé — la forme d'un vrai passage, et la raison pour laquelle 6 vérifications répondent dans le temps de la plus lente plutôt que dans la somme des 6.

LigneCe qui est regardéCe que dit le détail
Page et ressourcesLa page répond 200, et ses fichiers JS et CSS déclarés existent (HTTP et assets)« Statut 200 · 412 ms », ou « 3 ressources déclarées mais absentes »
Indexabilitérobots.txt, meta robots, X-Robots-Tag, canonical (Indexabilité)« Crawlable, canonical cohérent », ou les codes bloquants
Visibilité IACe que robots.txt autorise aux robots des moteurs de réponse, et le texte présent sans JavaScript (Visibilité IA)« ChatGPT ne peut pas vous lire », « 312 caractères seulement sans JavaScript », « Citation interdite (nosnippet) »
Carte socialeLes balises Open Graph et l'image de partage (Open Graph)« Titre et image valides », ou « Manque : og:image »
SitemapLe sitemap déclaré dans robots.txt (Sitemap:), sinon /sitemap.xml (Sitemap et SSL)« 48 URL déclarées », « 48 URL déclarées, 2 injoignables », « Aucun sitemap déclaré »
Certificat SSLLe certificat servi et sa date de fin« 61 jours avant expiration »

Le sitemap est cherché là où la réponse est écrite — robots.txt — avant de retomber sur /sitemap.xml. Deviner le chemin racine se tromperait sur tout site qui le déclare ailleurs, et un audit qui diffame le site qu'il regarde est pire que pas d'audit. Un site sans sitemap (404) est marqué « skip », pas en échec : ne rien avoir à vérifier n'est pas une faute, et la ligne ne pèse pas sur la note. Le sitemap déclaré doit être sur la même origine : un robots.txt qui pointe ailleurs n'est pas une licence pour aller chercher un tiers.

Aucune assertion « pages de paiement » ici : on ne sait pas laquelle des pages d'un inconnu encaisse, et deviner appliquerait la plus lourde pénalité du barème à une page qui n'a jamais vu un paiement.

La note

Le Ship Score : 100 moins les retenues des lignes en échec, avec la raison principale (« −25 asset manquant », « −30 site non indexable »). La réponse porte aussi outcome (pass si aucune ligne n'est en fail ou error) et le nombre de lignes en échec.

Aller plus loin

Un projet PostShip rejoue ces 6 vérifications sur toutes vos URL à chaque déploiement, y ajoute les contrôles du site, et ne vous écrit que lorsqu'une passe au rouge. Depuis votre CI, le même audit se lance avec une clé d'API, par l'API ou postship check ; il compte dans le quota de vérifications du mois.

Dépannage

Pourquoi mon sitemap est-il « Aucun sitemap déclaré » alors qu'il existe ?

Il n'est ni déclaré dans votre robots.txt par une ligne Sitemap:, ni à /sitemap.xml, ni sur la même origine. Déclarez-le dans robots.txt : c'est aussi là que les moteurs le cherchent.

Pourquoi la note diffère-t-elle de celle de mon projet ?

L'audit ne connaît ni vos pages de paiement, ni vos seuils, ni votre parcours : il note une seule URL, sans assertions. Dans un projet, les pages de paiement et les contrôles du site pèsent en plus.

Exports

Les fichiers que vous pouvez télécharger depuis un projet — incidents, journal et performance en CSV, dernier déploiement en JSON — et le format exact de chacun.

Un client demande, en fin de trimestre, ce qui s'est passé ; un prestataire conteste que « c'est plus lent depuis la refonte » ; un rapport a besoin d'une pièce jointe. La réponse ne doit pas être une capture d'écran d'un tableau de bord. Chaque page du projet qui porte une histoire a son export : un fichier, dans un format qu'un tableur ou un script lit sans surprise.

Ce que PostShip exporte

ExportOùFormatFenêtre
Les incidentsProjet → Incidents → « Exporter les incidents (CSV) »CSVLa rétention du plan
Le journalProjet → Surveillance → Journal → « CSV »CSVTout ce que la base contient, 2 500 lignes au plus
La performance par URLProjet → Surveillance → Performance → « CSV »CSVLa rétention du plan
Le dernier déploiementProjet → Déploiements → « Exporter le dernier déploiement (JSON) »JSONLe dernier déploiement de production
Le compteCompte → Résumé → « Exporter »JSONProfil, projets, URL surveillées

Les exports sont des liens directs vers /api/projects/<id>/export/… : ils passent par la même autorisation que la page (un projet qu'on n'a pas le droit de voir répond « introuvable ») et exigent le second facteur quand le compte l'a activé — le fichier sort du document qu'on joint à un rapport client, il mérite la même porte que le tableau de bord.

Les incidents (CSV)

Une ligne par incident sur la fenêtre conservée, du plus récent au plus ancien : debut, fin (vide si en cours), etat (investigating, identified, resolved), publie (oui / non), resume. Ce sont les incidents du projet, publiés ou non — pas seulement ceux racontés sur la page de statut. La fenêtre est celle du plan, pas 90 jours pour tout le monde : exporter au-delà de ce qu'il conserve rendrait un fichier vide sur sa fin, ce qui se lit comme « aucun incident » plutôt que « pas de données ».

Le journal (CSV)

Ce que la page Journal montre, sans le plafond d'affichage : date, genre, titre, detail, acteur. Les genres : deploiement, incident, alerte, equipe, note — jusqu'à 500 événements par source, 2 500 au total. Le domaine (DNS, certificats) n'y est pas : ses événements se calculent par comparaison de relevés, et l'export doit rester ce que la base contient, pas ce qu'on en déduit.

La performance (CSV)

Une ligne par URL de type http, form ou journey, classée de la plus lente à la plus rapide : url, type, mesures (le nombre de passages), mediane_ms, p95_ms, max_ms, depuis, jusqua. Le temps mesuré est celui de la page Performance, sur la fenêtre du plan.

Le dernier déploiement (JSON)

La pièce qu'on joint à un rapport : le score, ce qui a été vérifié, ce qui a échoué. De production, jamais une preview — un document qui prétend décrire ce qui est en ligne ne doit pas décrire une branche.

{
  "projet": "Boutique",
  "adresse": "https://boutique.fr",
  "deploiement": {
    "hebergeur": "vercel",
    "commit": "a1b2c3d",
    "date": "2026-09-11T08:39:51.000Z",
    "verdict": "pass",
    "verificationsEnEchec": 0,
    "score": 100,
    "raison": null
  },
  "urls": [{ "url": "https://boutique.fr/", "verdict": "pass" }],
  "exporteLe": "2026-09-11T09:00:00.000Z"
}

Un projet sans déploiement de production suivi reçoit quand même un document — deploiement: null et un message qui le dit — plutôt qu'un 404 : le navigateur n'affiche pas le corps d'une erreur sur un lien de fichier, et le téléchargement échouerait sans rien dire.

Le format CSV

Fait pour qu'Excel, Numbers, LibreOffice ou pandas le lisent sans réglage :

  • UTF-8 avec BOM : sans lui, Excel lit un fichier UTF-8 en latin-1 et affiche « résolu ». Le fichier serait juste, le tableur le lirait mal, et c'est nous qu'on accuserait.
  • Lignes en CRLF, comme la norme l'attend.
  • Chaque cellule entre guillemets, guillemets internes doublés : un résumé d'incident contient des virgules, des guillemets et des sauts de ligne, et c'est le guillemet non doublé qui casse un fichier au milieu d'une phrase.
  • Dates en ISO 8601 (UTC), durées en millisecondes.
  • Nom de fichier : postship-incidents-2026-09-11.csv, postship-journal-…, postship-performance-…, postship-ship-2026-09-11.json.
  • Cache-Control: no-store : chaque téléchargement est frais.

Ce qui déclenche une alerte

Rien : les exports lisent. Ce qu'ils contiennent vient des incidents, des alertes, des déploiements et des passages.

Limites et plans

DécouverteProPro Plus
Les 5 exportsOuiOuiOui
Fenêtre des incidents et de la performance7 jours30 jours90 jours

La fenêtre est celle de la rétention. Le journal exporte tout ce qui est encore en base. Voir les plans.

Dépannage

Pourquoi le téléchargement répond-il « Double authentification requise » ?

Votre compte a un second facteur et cette session ne l'a pas encore validé. Reconnectez-vous en validant le second facteur, puis relancez le téléchargement.

Pourquoi Excel affiche-t-il tout dans une seule colonne ?

Certaines versions localisées d'Excel attendent un point-virgule. Utilisez « Données → À partir d'un fichier texte/CSV » et choisissez la virgule comme séparateur ; le fichier lui-même est standard.

Pourquoi l'export des incidents est-il vide alors que le journal en montre ?

Le journal exporte tout ce qui est en base ; l'export des incidents se limite à la fenêtre du plan. Un incident plus ancien que la fenêtre peut encore figurer dans le journal, plus dans l'export des incidents.