GET /api/v1/projects
La référence des trois routes de lecture : vos projets, les incidents ouverts d'un projet, et son dernier déploiement de production.
Mis à jour le 11 septembre 2026
Sur cette page
- GET /api/v1/projects
- GET /api/v1/projects/{id}/incidents
- GET /api/v1/projects/{id}/last-ship
- Codes et erreurs
- Limites et plans
- Dépannage
- Pourquoi status est-il fail alors que toutes mes URL sont vertes ?
- Pourquoi lastShip est-il null alors que je déploie ?
- Pourquoi les incidents de l'API ne correspondent-ils pas à ma page de statut ?
Trois 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
}
]
}| Champ | Type | Ce qu'il contient |
|---|---|---|
id | string | L'identifiant du projet, à passer aux deux routes suivantes |
name | string | Le nom du projet |
url | string | L'adresse de production déclarée |
status | "pass", "fail" ou null | Le dernier état résumé : fail dès qu'une cible active est en fail ou en error ; null avant le premier passage |
lastCheckedAt | string ou null | La date du dernier passage complet, ISO 8601 |
paused | boolean | Le 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 deux 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" }
]
}| Champ | Type | Ce qu'il contient |
|---|---|---|
url | string | L'URL de la cible (pour un contrôle du site, l'URL de base du projet) |
kind | string | Le 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 |
since | string | Le 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 deux 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
}
}| Champ | Type | Ce qu'il contient |
|---|---|---|
provider | string | L'origine du déploiement : vercel, netlify, cloudflare, generic (le webhook générique) ou empreinte (la détection sans webhook) |
sha | string ou null | Le commit, quand l'hébergeur l'a transmis |
at | string | Le début du déploiement, ISO 8601 |
outcome | string | Le verdict de la vérification qui a suivi |
failedChecks | number | Le nombre de vérifications en échec |
score | number ou null | Le Ship Score, null tant que la notation n'a pas eu lieu |
scoreReason | string ou null | La 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 ».
Codes et erreurs
| Code | Quand |
|---|---|
401 | Jeton invalide ou révoqué |
404 | Projet 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.