L’API
L’API REST de while sert aux CI, aux scripts et aux outils qui ne parlent pas MCP. Cette page en donne les 265 opérations.
Mis à jour le 9 novembre 2026.
curl -H "Authorization: Bearer $WHILE_TOKEN" https://app.while.sh/v1/projects
L’adresse et le format
L’API répond à https://app.while.sh, en JSON. Sa description complète, au format OpenAPI 3.1, est à https://app.while.sh/openapi.json : un client se génère depuis elle.
S’authentifier
Chaque appel porte un jeton dans l’en-tête Authorization: Bearer. Un jeton de projet sert à une CI ou à un script ; un jeton d’organisation voit les projets de l’organisation que voit sa personne ; la clé d’un compte de service (whcs_…) agit avec exactement ses droits. Un jeton de projet ou d’organisation ne dépasse jamais les droits de sa personne. Les rubriques Jetons et Droits et validations disent comment les créer.
Trois exceptions : le dépôt git prend le jeton comme mot de passe (Basic, utilisateur au choix), les SDK Sentry s’authentifient par la clé de leur DSN, et la télémétrie OTLP par la clé dans son adresse. Le serveur MCP, lui, est à https://app.while.sh/mcp.
Les erreurs
Une erreur suit la RFC 9457 (application/problem+json) : type, title, status, detail. Un refus (403, 409, 428, 429) dit en plus ce qui bloque (why), la suite (what_to_do) et, quand il existe, l’appel tout prêt (action) : l’outil MCP, la requête de l’API ou le lien à ouvrir, et qui doit le faire, l’agent, une personne ou l’équipe while.
Les validations
Un geste sensible, comme détruire la production ou rendre une appli publique, peut demander l’accord d’une personne. La réponse est alors 428, avec la demande (validation) et son lien. Une personne l’accorde dans while ; renvoyez ensuite le même appel avec approval_id. Un jeton ne valide jamais une demande.
Sans jeton
Ce qui se lit sans s’authentifier : les tarifs, le catalogue des briques, les outils MCP, le schéma de while.yaml, les adresses réseau de while, sa version et la description de l’API.
Lire la version de while
GET /v1/info
Rend la version de while et ses adresses publiques. Avec un jeton, la réponse ajoute le moteur et les briques, sans leurs adresses internes.
Lire le catalogue des briques
GET /v1/catalog
Rend le contrat d’une appli et les briques qu’un while.yaml peut déclarer, chacune avec son état : disponible, partiel ou prévu.
Lire les adresses réseau de while
GET /v1/network
Rend l’entrée de while (son nom, pour le CNAME d’un sous-domaine ou l’ALIAS d’un domaine nu, et ses adresses IPv4 et IPv6, pour les A et AAAA d’un domaine nu en dernier recours seulement : elles peuvent changer) et les adresses IPv4 par où sortent les applis (à déclarer chez un tiers qui filtre par adresse). Chacune avec le jour depuis lequel elle vaut, s’il est dit, et un changement annoncé : le jour et les nouvelles adresses. Sans jeton. La réponse est gardée cinq minutes, et un même réseau peut la lire 60 fois par minute.
Lire les tarifs publics
GET /v1/pricing
Rend la grille de prix en vigueur (sa version et sa date), ses offres et leurs prix, et le prix de chaque ressource tel que la page Facture le montre. Sans jeton. La réponse est gardée cinq minutes, et un même réseau peut la lire 60 fois par minute.
Lister les outils MCP
GET /v1/mcp/tools
Rend exactement ce que tools/list sert à l’agent d’une organisation sur /mcp, ou, avec serveur=essai, sur le serveur d’essai /essai. Sans jeton. La réponse est gardée cinq minutes, et un même réseau peut la lire 60 fois par minute.
Paramètres : server.
Lire le schéma de while.yaml
GET /schema/while.v1.json
Rend le JSON Schema de while.yaml, le fichier qui décrit une appli. Votre agent s’en sert pour vérifier son fichier avant de mettre en ligne.
Lire la description OpenAPI
GET /openapi.json
Rend la description de l’API, au format OpenAPI 3.1.
Projets
Créer, lire et détruire un projet, lister les applis d’une organisation avec leurs mesures, et changer le propriétaire ou le budget d’un projet.
Lister les applis d’une organisation, avec leurs mesures
GET /v1/teams/{slug}/apps
Les applis que votre identité voit dans cette organisation. Pour chacune, en production : la version en ligne (version.number, version.since), la dernière construction si rien n’est en ligne (build), les incidents ouverts, à qui ses services sont ouverts (open), ses requêtes des deux dernières heures par tranche de 5 minutes, la plus ancienne d’abord (traffic), le temps sous lequel 95 % des réponses sont parties (p95_ms), ses tâches et leur dernier passage, et la pause de l’organisation (stop) ; ce qu’elle a coûté ce mois-ci, en euros (null sans mesure).
Lister les projets
GET /v1/projects
Rend les projets que votre identité voit.
Paramètres : organization.
Créer un projet
POST /v1/projects
Crée un projet dans votre organisation, avec un budget mensuel de 20 € par défaut. Un budget sans plafond ou au-delà de 20 €, et le bac à sable, demandent un admin de l’organisation et la validation d’une autre personne : le projet est alors créé au budget par défaut, et la réponse 202 porte la demande. Un admin le fait sans attendre personne, au journal (son agent, au plancher, le lui fait confirmer), sauf si l’organisation a réglé deux approbateurs.
Corps : slug (obligatoire), name, budget_eur, account, sandbox, team.
Lire un projet
GET /v1/projects/{slug}
Rend le projet s’il vous est visible, sinon 404.
Détruire un projet
DELETE /v1/projects/{slug}
Détruit le projet avec ses environnements, son dépôt git et ses sources, en tâche de fond (202). Il faut le droit de détruire le projet. Un jeton d’agent le demande toujours à une personne (428, avec la demande) ; une production qui a des données se fait valider par un admin, qui la détruit lui-même dans while.
Paramètres : approval_id.
Lire l’historique d’un projet
GET /v1/projects/{slug}/history
Rend les versions, les plans et les événements du projet, mêlés, du plus récent au plus ancien.
Paramètres : limit.
Changer le propriétaire d’un projet
PUT /v1/projects/{slug}/owner
Réservé aux admins et au propriétaire actuel.
Corps : email (obligatoire).
Changer le budget d’un projet
PUT /v1/projects/{slug}/budget
Réservé aux admins. Baisser le budget mensuel s’applique tout de suite ; le relever se fait confirmer ou valider (202, avec le lien).
Corps : budget_eur (obligatoire).
Jetons
Les jetons d’un projet ou d’une organisation, pour une CI ou un script, et l’identifiant git d’un agent branché par OAuth.
Lister les jetons d’un projet
GET /v1/projects/{slug}/tokens
Rend les jetons du projet, sans leur valeur. Réservé à l’administration du projet : un jeton de projet ne les liste pas.
Créer un jeton de déploiement
POST /v1/projects/{slug}/tokens
Crée un jeton pour une CI externe ou un agent. Il faut la permission access.grant sur le projet. Le jeton agit pour vous : ses droits ne dépassent jamais les vôtres sur ce projet, et se recalculent à chaque requête.
Corps : name, days, scopes, environments.
Révoquer un jeton
DELETE /v1/tokens/{id}
La personne du jeton le révoque toujours, dans sa session ; sinon, il faut pouvoir donner des accès sur sa portée (son projet ou l’organisation). Un refus répond 404, comme un jeton qui n’existe pas.
Créer un jeton d’organisation
POST /v1/teams/{slug}/tokens
Le jeton voit les projets de l’organisation que vous voyez, et eux seuls. Sa valeur n’est montrée qu’une fois.
Corps : name, scopes, days, environments.
Fixer l’expiration d’un jeton
POST /v1/tokens/{id}/expiry
30 jours par défaut. L’appel ne peut que rapprocher l’expiration.
Corps : days.
Obtenir un identifiant git pour un agent OAuth
POST /v1/projects/{slug}/git
Un agent branché par OAuth ne crée pas de jeton : cet appel lui donne un identifiant git valable une heure, pour ce projet seul, avec les droits que sa personne a consentis. Il sert à git push et git fetch, sur les branches seulement, sans tag, sans réécrire ni supprimer de branche ; l’API et le MCP le refusent. Il se coupe quand on déconnecte l’agent, ou quand sa personne ne peut plus mettre en ligne, et cinq au plus sont en cours à la fois. Passez-le dans l’en-tête Authorization: Bearer, jamais dans l’adresse.
while.yaml et plans
Le fichier qui décrit l’appli, et le plan qui dit ce qui va changer avant de l’appliquer.
Lire le while.yaml en cours
GET /v1/projects/{slug}/intent
Rend le fichier qui décrit l’appli, tel que while l’a reçu en dernier.
Paramètres : environment.
Déposer un while.yaml
PUT /v1/projects/{slug}/intent
Enregistre le fichier qui décrit l’appli, une fois validé par le schéma de while.yaml.
Paramètres : environment.
Calculer un plan
POST /v1/projects/{slug}/environments/{env}/plan
Rend ce qui va changer dans l’environnement, sans rien appliquer. Sans intent ni from_state : le dernier while.yaml déposé.
Corps : intent, from_state.
L’offre de l’organisation
GET /v1/teams/{slug}/plan
Réservé à ses admins. Son offre (ce qu’elle comprend, l’usage face à ses limites, ses options), les offres à comparer, les prix et ce qui est compris ; le moyen de paiement quand il est obligatoire (son état, la carte en quatre chiffres) et la cause d’une pause.
Lire un plan
GET /v1/plans/{id}
Rend l’état d’un plan.
Appliquer un plan
POST /v1/plans/{id}/apply
Applique les changements du plan. Une suppression en production, ou d’une base, demande une validation humaine : la réponse est 428, avec le lien de la demande.
Corps : approval_id.
Écarter un plan
POST /v1/plans/{id}/discard
Écarte un plan que vous n’appliquerez pas. Il faut pouvoir mettre en ligne sur l’environnement du plan. Un plan déjà appliqué ou écarté rend 409.
Lire le schéma d’une appli
GET /v1/projects/{slug}/environments/{env}/schema
Ce qui compose l’appli et comment c’est relié, tiré de son while.yaml : ses entrées (internet, l’équipe), ses services, ses tâches, ses bases, ses caches, ses stockages, les bases d’autres applis qu’elle lit, ses sources de données et ses sauvegardes (briques), et leurs liens (links : de, vers, genre). Avec ce que while en mesure et que status ne dit pas : les requêtes de chaque service sur deux heures par tranche de 5 minutes (serie_2h) et leur temps de réponse, les passages du jour de chaque tâche, les appels des sources sur 24 h, la dernière sauvegarde et son essai de restauration. L’état de chaque brique se lit dans status.
Versions et mises en ligne
Les sources, les versions, les retours arrière et l’état d’un environnement.
Mettre en ligne
POST /v1/projects/{slug}/environments/{env}/deploy
Met en ligne une archive de sources (tar.gz), une image déjà construite, ou, avec un corps JSON vide, le dernier commit des sources du projet chez while, écrites par POST …/files ou poussées par git. Si ce commit est déjà en ligne, rien n’est reconstruit (200) ; si une version de ce commit est en cours, elle est rendue telle quelle. Sinon, une nouvelle version démarre (202).
Corps : image, digest, intent.
Lister les fichiers des sources
GET /v1/projects/{slug}/files
Rend les fichiers des sources du projet chez while, celles de son dépôt git : chemins, tailles et dernier commit.
Paramètres : path.
Écrire des fichiers des sources
POST /v1/projects/{slug}/files
Écrit les fichiers nommés dans un commit sur la branche du projet ; les autres ne changent pas, et delete retire des fichiers ou des dossiers. Du texte UTF-8, 2 Mio et 200 fichiers au plus par appel. Si rien ne change, aucun commit n’est créé (200) ; si un autre commit arrive pendant l’écriture, la réponse est 409. Ensuite, POST …/environments/{env}/deploy sans archive met ce commit en ligne.
Corps : files, delete, message.
Lire un fichier des sources
GET /v1/projects/{slug}/files/{path}
Rend le contenu d’un fichier texte, 256 Kio au plus. Un fichier binaire est signalé, sans son contenu.
Télécharger les sources d’une version
GET /v1/projects/{slug}/environments/{env}/releases/{number}/sources
Rend l’archive tar.gz que la construction de la version a lue. Elle est gardée 7 jours, et tant que la version est en ligne.
Lister les versions
GET /v1/projects/{slug}/environments/{env}/releases
Rend l’historique des versions de l’environnement.
Paramètres : limit.
Remettre en ligne une version construite
POST /v1/projects/{slug}/environments/{env}/releases/{number}/redeploy
Crée une nouvelle version avec la même image et les variables d’aujourd’hui, sans rien reconstruire. Quand la politique de l’organisation demande une validation, la réponse est 428 avec le lien ; une mise en production durcie s’arrête avant d’être appliquée et reprend d’elle-même une fois validée.
Lire une version
GET /v1/releases/{id}
Rend la version, avec sa construction et son plan.
Retirer une version de ses liaisons
POST /v1/projects/{slug}/environments/{env}/releases/{number}/remove-for-binding
Pour la fédération OIDC, avec le corps { reason }. Une personne approbatrice du projet, par sa session. La version ne signera plus jamais, même revenue par un retour arrière.
Corps : reason (obligatoire).
Revenir à une version précédente
POST /v1/projects/{slug}/environments/{env}/rollback
Remet en ligne une version précédente. Quand une validation est attendue, la réponse est 428 avec le lien de la demande, comme pour POST …/deploy, et une CI s’arrête là ; renvoyez l’appel avec approval_id une fois la demande accordée. Par un lien d’envoi d’agent (POST /v1/upload/{token}), la réponse est 202 avec la suite ; par l’outil MCP, « validation humaine requise ».
Corps : to, approval_id.
Redémarrer un service
POST /v1/projects/{slug}/environments/{env}/services/{service}/restart
Redémarre un service de la version en ligne, sans créer de version, et coupe les requêtes en cours. Les instances d’un service web sont recréées ; un worker redémarre en roulement. 409 si rien ne tourne.
Lire l’état d’un environnement
GET /v1/projects/{slug}/environments/{env}/status
Rend la version en ligne, son adresse, sa santé et le trafic des 15 dernières minutes (p50, p95, p99). services[].titre et taches[].titre donnent le titre du while.yaml, null sans titre. Pour chaque brique, la réponse donne ce qu’elle réserve et ce qu’elle prend, mesuré (null tant que ce n’est pas mesuré).
Paramètres : probe.
Lire ce qui a été appliqué
GET /v1/projects/{slug}/environments/{env}/state
Rend les 20 dernières versions d’état de l’environnement : ce qui a réellement été appliqué.
Créer une prévisualisation
POST /v1/projects/{slug}/previews
Crée un environnement de prévisualisation. Il faut le droit de mettre en ligne.
Corps : name, branch, from, copy_database, ttl_hours.
Détruire un environnement
DELETE /v1/projects/{slug}/environments/{env}
Il faut le droit de détruire le projet (un admin ; pas une développeuse). Détruire la production demande une validation humaine : la réponse est 428 avec le lien, et vous renvoyez ensuite l’appel avec approval_id.
Corps : approval_id.
Lire une construction
GET /v1/builds/{id}
Rend l’état d’une construction : ses temps, son cache, chaud ou froid, et ses tests.
Lire le journal d’une construction
GET /v1/builds/{id}/logs
Rend le journal en JSON, ou en flux SSE avec l’en-tête Accept: text/event-stream.
Paramètres : stream, since.
Envoyer des sources par un lien signé
POST /v1/upload/{token}
Reçoit l’archive des sources d’une mise en ligne. Le lien vient de l’outil MCP upload_source et vaut 15 minutes.
Sans jeton.
Télécharger des sources par un lien signé
GET /v1/sources/{token}
Rend l’archive tar.gz des sources d’une version. Le lien vient de l’outil MCP read_source et vaut 10 minutes.
Sans jeton.
Git et forges
Le dépôt git de chaque projet, et la liaison avec GitHub ou GitLab.
Lire l’aide du dépôt git
GET /git/{repo}
Rend les commandes pour ajouter le dépôt comme remote et y pousser.
Sans jeton.
Annoncer les références git
GET /git/{repo}/info/refs
Le protocole git intelligent. git-receive-pack demande le droit de mettre en ligne. Un projet déjà à sa limite de stockage (sources et git) reçoit 409, avec le refus du quota en texte, que git affiche.
Paramètres : service (obligatoire).
Récupérer un dépôt git
POST /git/{repo}/git-upload-pack
git fetch et git clone (stateless-rpc). Corps brut ou en gzip (Content-Encoding) ; 413 au-delà de la limite d’une archive de sources, 64 Mo, décompressé compris.
Pousser sur un dépôt git
POST /git/{repo}/git-receive-pack
git push : il faut le droit de mettre en ligne. Un push sur main met en production ; sur une autre branche, il ouvre une prévisualisation. Corps brut ou en gzip (Content-Encoding) ; 413 au-delà de la limite d’une archive de sources, 64 Mo, décompressé compris.
Lire la liaison GitHub ou GitLab
GET /v1/projects/{slug}/forge
Rend le dépôt lié au projet, sans son jeton.
Lier un dépôt GitHub ou GitLab
POST /v1/projects/{slug}/forge
Un push sur la branche par défaut met en production ; une demande de fusion ouvre une prévisualisation, commentée sur la demande ; chaque commit reçoit son statut. Le jeton de la forge est vérifié chez elle, rangé au coffre, et sert à créer le webhook.
Corps : forge (obligatoire), repository (obligatoire), token (obligatoire), base_url.
Délier le dépôt
DELETE /v1/projects/{slug}/forge
Retire la liaison, et le webhook chez la forge.
Domaines et liens d’accès
Les domaines d’un environnement, l’adresse principale d’un projet, et les liens qui montrent une appli à quelqu’un sans compte.
Lister les domaines
GET /v1/projects/{slug}/environments/{env}/domains
Rend les domaines de l’environnement : statut, enregistrements DNS à créer, constat de while et certificat.
Ajouter un domaine
POST /v1/projects/{slug}/environments/{env}/domains
Ajoute un domaine à un service (le seul qui a une adresse quand service est absent) : le while.yaml change et une nouvelle version part (statut inchangé, sans version, quand le service a déjà ce domaine). Le domaine attend ensuite son enregistrement DNS (GET domains le dit).
Corps : domain (obligatoire), service.
Vérifier un domaine
POST /v1/projects/{slug}/environments/{env}/domains/{host}/verify
Vérifie tout de suite un domaine personnalisé : sa preuve TXT et son pointage.
Donner l’adresse du projet à un autre service
PUT /v1/projects/{slug}/principal-address
Sous un domaine des applis sans région : l’adresse du projet seul passe à ce service web public, dans chaque environnement en ligne (la version en ligne est remise telle quelle). Une personne seulement, par sa session : le propriétaire de l’appli ou un admin ; un jeton reçoit 403. Sans confirmer, 409 et l’aperçu : les adresses qui partent et celles qui arrivent.
Corps : service (obligatoire), confirm.
Lister les liens d’accès
GET /v1/projects/{slug}/environments/{env}/links
Rend les liens d’accès de l’environnement : nom, échéance, mot de passe ou non, ouvertures. Le lien lui-même n’est jamais rendu.
Créer un lien d’accès
POST /v1/projects/{slug}/environments/{env}/links
Un lien d’accès montre l’appli à quelqu’un qui n’a pas de compte while. Corps : { name, days, password }, avec days de 1 à 90 et un password facultatif, de 8 caractères au moins. Le lien n’est rendu qu’une fois : url, et urls, une par adresse de l’environnement. En production, il naît inactif et s’active quand une autre personne le valide (approval : la demande). Il faut être une personne, avec project.configure : un jeton d’agent reçoit 403, et l’outil MCP request_access_link rend la page de while à ouvrir. Un admin le fait sans attendre personne, au journal (son agent, au plancher, le lui fait confirmer), sauf si l’organisation a réglé deux approbateurs.
Corps : name (obligatoire), days (obligatoire), password.
Révoquer un lien d’accès
DELETE /v1/projects/{slug}/environments/{env}/links/{id}
Le lien cesse de marcher tout de suite. Il faut être une personne, avec project.configure.
Créer un lien présigné vers un objet
POST /v1/projects/{slug}/environments/{env}/buckets/{name}/links
Rend un lien présigné vers un objet, valable 15 minutes par défaut et 24 heures au plus. Un lien d’envoi sert à un PUT et demande data.write.
Corps : key (obligatoire), upload, minutes, upstream.
Variables et secrets
Les variables d’un environnement, et le coffre, compatible avec Vault.
Lister les variables
GET /v1/projects/{slug}/environments/{env}/variables
Les noms posés dans l’environnement (secrets, variables en clair, secrets en fichier et de construction), jamais leurs valeurs.
Poser des variables
PUT /v1/projects/{slug}/environments/{env}/variables
Pose plusieurs variables d’un coup, sans toucher aux autres : au coffre par défaut, en clair avec secret: false. Elles arrivent dans l’appli à la prochaine mise en ligne.
Corps : values (obligatoire), secret, file, build.
Supprimer une variable
DELETE /v1/projects/{slug}/environments/{env}/variables/{name}
Supprime une variable ou un secret de l’environnement, et le note au journal ; sur un projet lié à une connexion fédérée, la production passe par ses approbateurs (428). Avec ?build=1, un secret de construction. Le changement vaut à la prochaine mise en ligne.
Paramètres : build.
Vérifier le coffre
GET /vault/v1/sys/health
Compatible avec l’API de Vault.
Sans jeton.
Lire un secret
GET /vault/v1/secret/data/{path}
Compatible Vault KV v2.
Paramètres : project, environment.
Écrire un secret
POST /vault/v1/secret/data/{path}
Compatible Vault KV v2. Il faut le droit de mettre en ligne.
Paramètres : project, environment.
Corps : data (obligatoire).
Supprimer un secret
DELETE /vault/v1/secret/data/{path}
Compatible Vault KV v2. Il faut le droit de mettre en ligne.
Paramètres : project, environment.
Lister les secrets sous un préfixe
GET /vault/v1/secret/metadata/{path}
Compatible Vault KV v2.
Paramètres : project, environment.
Bases et buckets
Lire une base en SQL, ses sauvegardes et ses requêtes, et les fichiers des buckets.
Lister les sauvegardes
GET /v1/projects/{slug}/environments/{env}/backups
Rend les sauvegardes des bases de l’environnement, avec le résultat de leur test de restauration. status : running, succeeded, failed, ou expired (ses objets sont effacés depuis expired_at : elle ne se restaure plus).
Restaurer une sauvegarde
POST /v1/projects/{slug}/environments/{env}/restore
Restaure une sauvegarde d’une base, en une seule transaction, après une sauvegarde de sûreté. Demande une validation humaine.
Corps : database, backup_id, instant, approval_id.
Rétablir une connexion coupée
POST /v1/teams/{slug}/connections/{connection}/restore
Il faut le même droit que pour la couper. La source reprend telle qu’elle était : phase, règles, droits. Sans effet sur une source ouverte. Pas d’outil MCP.
Lire une base en SQL
POST /v1/projects/{slug}/environments/{env}/query
Exécute une seule requête SQL de lecture (SELECT, WITH, VALUES, TABLE), plafonnée, notée au journal sans ses valeurs. Elle tourne au nom de la personne, sous le rôle PostgreSQL de son identité (while_id_…), qui n’a que ses droits sur les données : data.read sur la base, un schéma, une table ou des colonnes. Transaction READ ONLY ; 10 secondes par défaut (30 au plus), 400 lignes par défaut (2 000 au plus), 512 000 octets par défaut. Refusé (400) : plusieurs instructions, une écriture, du DDL, COPY, DO, les fonctions qui agissent, et ce qui fabrique une grosse valeur en mémoire (repeat, lpad, rpad ou format au-delà de 10 000 caractères, array_fill, generate_series au-delà de 100 000 valeurs, une agrégation sur une série plus grande). Faute de droit, PostgreSQL refuse : 403, avec la table, les colonnes lisibles et la permission (missing_permission, object, readable_columns). Une base qui n’a pas encore le rôle while_acces, avant sa prochaine mise en ligne, rend 409 ; un autre refus de la base, 422. Une base qui déclare replica: true est encore lue sur la base principale, en lecture seule, et la réponse le dit.
Corps : sql (obligatoire), database, limit, max_bytes, timeout_seconds.
Exporter une requête en CSV
POST /v1/projects/{slug}/environments/{env}/export.csv
Exporte le résultat d’une seule requête SQL de lecture, avec le même rôle, les mêmes refus et le même journal que POST …/query. 10 000 lignes et 1 000 000 octets par défaut (50 000 et 4 000 000 au plus), 10 secondes (30 au plus). Un en-tête puis les lignes, en CRLF ; NULL est vide, une chaîne vide s’écrit "". Une cellule qu’un tableur lirait comme une formule (=, +, - ou @ en tête, hors nombres) est précédée d’une apostrophe. Les en-têtes x-while-lignes et x-while-tronque (non, rows ou bytes) disent ce qui a été rendu. 429 quand l’organisation a déjà 3 lectures en cours.
Corps : sql (obligatoire), database, limit, max_bytes, timeout_seconds.
Lire un bucket
GET /v1/projects/{slug}/environments/{env}/buckets/{name}/objects
Lit un bucket par while : la liste de ses objets, 200 par page, ou, avec ?cle=, le début d’un objet texte (64 Kio). Il faut data.read.
Paramètres : key, prefix, next.
Renouveler la clé S3
POST /v1/projects/{slug}/environments/{env}/buckets/rotate-key
Crée une nouvelle clé S3 pour l’environnement. Elle part à la prochaine mise en ligne, et l’ancienne vaut jusque-là ; avec immediate, l’ancienne est supprimée tout de suite.
Corps : immediate.
Lire les requêtes SQL d’une base
GET /v1/projects/{slug}/environments/{env}/databases/{database}/queries
Rend les requêtes que l’appli envoie à sa base, d’après pg_stat_statements : les plus fréquentes et les plus lentes. L’outil MCP observe_app (vue database) rend la même chose.
Paramètres : limit, window_minutes.
Tâches planifiées
Les tâches de chaque environnement et leurs passages.
Lister les tâches planifiées
GET /v1/projects/{slug}/environments/{env}/tasks
Pour chaque tâche : son titre (celui du while.yaml, null sans titre), son planning, son dernier passage (état, durée, erreur, quoi faire), le passage en cours, le prochain et les 14 derniers.
Lister les passages d’une tâche
GET /v1/projects/{slug}/environments/{env}/tasks/{task}/runs
Rend l’historique des passages : déclenchement, auteur, arguments, début, fin, état, code de sortie, extrait du journal et Job.
Paramètres : limit.
Lancer une tâche maintenant
POST /v1/projects/{slug}/environments/{env}/tasks/{task}/runs
Lance un passage manuel, ou le rattrapage d’une période (WHILE_CATCH_UP_START et WHILE_CATCH_UP_END). Refusé si un passage tourne déjà.
Corps : args, env, catch_up.
Observer
Les journaux, les métriques, les traces, les erreurs et les événements de l’appli, et ce que les agents y ont fait.
Lire les traces
GET /v1/projects/{slug}/environments/{env}/traces
Rend les traces OpenTelemetry les plus récentes de l’appli, ou une trace par son trace_id. Elles sont gardées 30 jours. L’outil MCP observe_app (vue traces) rend la même chose.
Paramètres : trace_id, service, operation, since_minutes, min_duration, errors, limit.
Lire les menaces d’un environnement
GET /v1/projects/{slug}/environments/{env}/security
Rend ce qui menace l’environnement : les failles de ses dépendances (UpdateFOMO), son exposition (Probr), les robots qui l’appellent (Polygraphe) et les constats de sa construction (Gitleaks, Opengrep). L’outil MCP get_app_status en rend les failles et les robots (include: ["vulnerabilities"]).
Paramètres : since.
Télécharger la nomenclature de la version en ligne
GET /v1/projects/{slug}/environments/{env}/sbom
Rend la nomenclature CycloneDX de la version en ligne de l’environnement, tirée de ses fichiers de verrouillage, en fichier à télécharger ; 404 quand cette version n’en a pas.
Lire les journaux de l’appli
GET /v1/projects/{slug}/logs
Interroge les journaux de l’appli en LogsQL.
Paramètres : environment, query, limit, minutes.
Lire les métriques
GET /v1/projects/{slug}/metrics
Interroge les métriques de l’appli en PromQL, par l’API HTTP de Prometheus.
Paramètres : query, environment, start, end, step, range.
Lire les événements
GET /v1/projects/{slug}/events
Rend les événements du projet au format CloudEvents. Avec stream=1, ou l’en-tête Accept: text/event-stream, la réponse est un flux SSE. Le flux revérifie votre identité (le jeton ou la session, avec project.view) à chaque événement et toutes les 60 secondes, et se ferme dès qu’elle ne passe plus : membre retiré, jeton révoqué, session fermée.
Paramètres : limit, stream.
Lire les erreurs de l’appli
GET /v1/projects/{slug}/errors
Rend les erreurs de l’appli regroupées par empreinte, 50 groupes au plus : le nombre d’occurrences, la première et la dernière fois, la version déclarée.
Paramètres : environment, since.
Lire la consommation en CloudEvents
GET /v1/usage/events
Rend la consommation des projets que vous voyez, en CloudEvents au format OpenMeter.
Lire ce que consomme chaque service
GET /v1/projects/{slug}/environments/{env}/resources
Le processeur (vCPU), la mémoire (octets) et le nombre de copies de chaque service sur les dernières heures (1, 6, 24 ou 168), une centaine de points par courbe ([instant en ms, valeur]). Un service endormi n’a pas de point. mesure : false quand les mesures n’ont pas répondu. Ce que chaque service réserve se lit dans status (sizes).
Paramètres : hours.
Lire le trafic dans le temps
GET /v1/projects/{slug}/environments/{env}/traffic
Par tranche (1 min sur 1 heure, 5 min sur 6 heures, 15 min sur 24 heures, 2 heures sur 7 jours) : les requêtes, celles en erreur, la médiane et le 95e centile de la réponse en ms, la version qui a servi le plus. Avec les mises en ligne et les incidents de la plage, et le seuil d’erreurs de l’alerte par défaut en % (null en sourdine).
Paramètres : hours.
Lire la ligne de temps
GET /v1/projects/{slug}/timeline
Rend sur une seule ligne les événements de while, les erreurs nouvelles et les actions des agents par MCP.
Paramètres : environment, since, until, families, limit.
Lire l’impact d’une version
GET /v1/projects/{slug}/environments/{env}/impact
Compare le trafic, les erreurs et la latence avant et après la version, et rend un verdict et des propositions.
Paramètres : version, window_minutes.
Poser une question sur la production
POST /v1/projects/{slug}/environments/{env}/ask
Une question comme « pourquoi c’est lent depuis 14 h ? ». Rend les faits, les suspects et des propositions.
Corps : question (obligatoire).
Lister les actions des agents par MCP
GET /v1/projects/{slug}/mcp-actions
Rend ce que les agents ont fait par MCP : l’outil, ses paramètres (valeurs sensibles masquées) et le résultat.
Paramètres : since, limit.
Lire les points d’entrée de la télémétrie
GET /v1/projects/{slug}/telemetry
Rend le DSN Sentry et les points d’entrée OpenTelemetry du projet. La clé du DSN se crée à la première lecture.
Lire une erreur et sa pile
GET /v1/projects/{slug}/errors/{fingerprint}
Une erreur regroupée par son empreinte : ses occurrences, la première et la dernière fois, et la pile de son dernier événement (fonction, fichier, ligne), avec l’adresse demandée.
Lister les webhooks
GET /v1/projects/{slug}/webhooks
Rend les webhooks du projet, sans leur secret.
Abonner un webhook
POST /v1/projects/{slug}/webhooks
Abonne une adresse aux événements du projet : il faut le droit de configurer le projet, et une URL https:// qui se résout vers une adresse publique. Les envois sont signés, au format CloudEvents 1.0, selon Standard Webhooks.
Corps : url (obligatoire), types, secret.
Retirer un webhook
DELETE /v1/projects/{slug}/webhooks/{id}
Il faut la permission project.configure. Les livraisons en attente partent avec lui.
Envoyer des erreurs au format Sentry
POST /api/{projectRef}/envelope/
Reçoit les enveloppes des SDK Sentry, tels quels. Authentifié par la clé publique du DSN (X-Sentry-Auth, Authorization ou ?sentry_key), pas par un jeton. 50 événements et 512 Ko au plus par enveloppe.
Envoyer de la télémétrie OTLP
POST /otlp/{key}/{environment}/v1/{signal}
Relaie les journaux et les métriques OTLP/HTTP de l’appli. Le projet et l’environnement sont imposés aux données relayées ; 502 si le collecteur refuse.
Sans jeton.
Alertes et incidents
Les règles, les incidents, les canaux et la page de statut.
Lire les alertes d’un projet
GET /v1/projects/{slug}/alerts
Rend les alertes par défaut (état, sourdine), les règles écrites (condition en clair, dernier état), les incidents ouverts et ceux des 30 derniers jours, les canaux, et l’origine de la mesure de disponibilité.
Créer ou modifier une règle d’alerte
POST /v1/projects/{slug}/alerts/rules
Par son nom : une source, une condition structurée (ni PromQL ni LogsQL), une fenêtre, une gravité, quoi faire et les canaux. Noté au journal.
Corps : name (obligatoire), source (obligatoire), condition, window_minutes, severity, message (obligatoire), channels, environment, active.
Supprimer une règle d’alerte
DELETE /v1/projects/{slug}/alerts/rules/{rule}
Par son identifiant ou son nom. Ses incidents ouverts sont clos.
Mettre une alerte par défaut en sourdine
PUT /v1/projects/{slug}/alerts/defaults/{default}
Met en sourdine, ou réactive, une alerte par défaut pour ce projet, parmi : task, unreachable, restarts, errors, latency, budget, vulnerabilities, disk.
Corps : mute (obligatoire).
Lister les incidents
GET /v1/projects/{slug}/incidents
Rend les incidents ouverts ou acquittés, et ceux clos dans les 30 derniers jours : quoi, depuis quand, quoi faire, et les envois.
Acquitter un incident
POST /v1/projects/{slug}/incidents/{id}/acknowledge
Dit que quelqu’un s’en occupe. L’incident se clôt de lui-même au retour à la normale. Noté au journal.
Corps : reason.
Lire la page de statut
GET /v1/projects/{slug}/status-page
Rend les données de la page de statut (/statut/<organisation>/<projet>) : ouverte au public ou non, état, disponibilité sur 30 jours, temps de réponse et incidents récents.
Ouvrir ou fermer la page de statut
PUT /v1/projects/{slug}/status-page
public: true l’ouvre, false la ferme ; elle est fermée par défaut. Ouverte, tout le monde y lit le nom affiché, l’état et les incidents en cours, sans détail technique. Noté au journal.
Corps : public (obligatoire).
Lister les canaux d’alerte
GET /v1/teams/{slug}/alert-channels
Rend les canaux de l’organisation, sans leurs adresses, qui sont des secrets, et le réveil des agents, toujours actif.
Ajouter un canal d’alerte
POST /v1/teams/{slug}/alert-channels
Réservé aux admins. Un courriel (l’adresse d’un membre de l’organisation, sinon 403), Slack (l’adresse du webhook entrant) ou un webhook générique (CloudEvents signés ; la clé de signature n’est rendue qu’une fois). 10 canaux par organisation ; au-delà, 409 quota-exceeded.
Corps : type (obligatoire), name, address, url, min_severity.
Retirer un canal d’alerte
DELETE /v1/teams/{slug}/alert-channels/{channel}
Réservé aux admins. Son adresse est détruite dans le coffre.
Tester un canal d’alerte
POST /v1/teams/{slug}/alert-channels/{channel}/test
Envoie un message d’essai par ce canal. Réservé aux admins ; un par minute et par canal, sinon 429 avec Retry-After.
Lire la page de statut d’une appli
GET /v1/status/{organization}/{project}
La page de statut publique d’une appli, sans compte quand son projet l’a ouverte : le nom affiché, l’état, les incidents en cours, sans détail technique. Qui voit le projet la lit entière (chaque adresse, ses 30 jours, la page ouverte ou non). Sinon 404, la même réponse qu’une appli inconnue.
Sans jeton.
Applis internes
Qui entre dans une appli réservée à l’organisation, l’accès de son agent, et la clé qui signe son identité.
Lister qui entre dans les applis internes
GET /v1/projects/{slug}/sign-ins
Rend, pour chaque appli interne du projet, la règle qui dit qui peut entrer, et qui est entré, avec la date. Il faut pouvoir lire le journal du projet.
Lister les accès des agents aux applis internes
GET /v1/projects/{slug}/app-access
Rend les identifiants en cours que vos agents ont ouverts pour entrer dans une appli du projet. L’identifiant lui-même n’est jamais rendu, seulement son id, pour le couper.
Ouvrir une appli interne à l’agent d’une personne
POST /v1/projects/{slug}/app-access
Donne à l’agent d’une personne un identifiant d’une heure pour entrer dans une appli interne (access: internal). L’agent passe par son branchement OAuth ou par un jeton de sa personne ; un compte de service ou une session est refusé. L’appli le reçoit comme la personne : mêmes droits, sa règle relue à chaque requête, et while_agent dans l’en-tête X-While-Identity. L’identifiant vaut pour cette adresse seule, cinq au plus en cours par personne, et passe dans l’en-tête Cookie (__Host-while-agent=…), jamais dans l’adresse. Avec read_only, seuls GET et HEAD passent. Il se coupe quand on déconnecte l’agent, ou par DELETE. Quand le rôle de la personne demande une validation pour « Ouvrir une appli interne par son agent », la réponse est 428 avec la demande ; renvoyez ensuite l’appel avec approval_id.
Corps : service, environment, address, read_only, approval_id.
Couper l’accès d’un agent à une appli
DELETE /v1/projects/{slug}/app-access/{id}
Coupe l’identifiant tout de suite. Sa personne ou un admin de l’organisation peut le faire.
Lire la clé des jetons d’identité
GET /.well-known/jwks.json
Rend la clé publique (JWKS, ES256) qui signe le jeton d’identité X-While-Identity transmis aux applis internes.
Sans jeton.
Connexions
Les API externes que les applis appellent par while : leurs règles, leurs secrets, leurs plafonds et leur journal.
Lister les connexions
GET /v1/teams/{slug}/connections
Rend les connexions de l’organisation : phase (déclaration à valider, déclarée, apprentissage, verrouillée), authentification (sans secret), appels et refus des dernières 24 heures, et la variable <NOM>_URL.
Déclarer une connexion
POST /v1/teams/{slug}/connections
La déclaration est validée par un approbateur, ou passe à votre nom quand les règles de l’organisation vous laissent autonome (201). Elle se fait sans secret, saisi ensuite par PUT …/secret. La connexion démarre en apprentissage pendant 7 jours : les écritures y sont bloquées, sauf les lectures en POST (post_read).
Corps : name (obligatoire), label, domain, model, secondary_domains, authentication, post_read, rules, learning_days, rate_per_minute, owner, project, apps, direction.
Lire une connexion
GET /v1/teams/{slug}/connections/{connection}
Rend ses règles (sa surface : méthode, motif, validation à chaque appel) ; qui peut l’appeler (attributions connection.read et connection.write, en phrases) ; qui l’a appelée cette semaine, et par quelle attribution ; les refus de la semaine ; les changements de règles et d’accès ; les appels observés et la proposition de verrouillage ; les derniers appels (métadonnées) et les appels retenus ; les approbateurs, et comment l’appeler.
Saisir le secret d’une connexion
PUT /v1/teams/{slug}/connections/{connection}/secret
Qui peut configurer la connexion (un admin, ou une attribution qui le donne) saisit ou change le secret. Il est rangé au coffre, jamais rendu ni noté au journal ; une connexion déclarée entre alors en apprentissage. Les champs suivent la recette : value ; user et password (basic) ; client_id et client_secret (oauth2) ; identifier et password (session).
Lire la proposition de verrouillage
GET /v1/teams/{slug}/connections/{connection}/lock
Rend, sans rien demander, les règles que while calcule depuis les appels observés (identifiants généralisés en *) et le diff. Qui peut appeler reste l’affaire des attributions.
Verrouiller une connexion sur ce qui a servi
POST /v1/teams/{slug}/connections/{connection}/lock
while calcule les règles depuis les appels observés et crée la demande de validation, avec le diff ; un admin n’attend personne : verrouillée tout de suite (200). Une fois validée, tout appel hors des règles reçoit 403 (règle manquante), et l’appelant est prévenu.
Couper une connexion
POST /v1/teams/{slug}/connections/{connection}/revoke
Le geste d’urgence d’une personne qui en répond (connection.configure), sans validation. Le relais refuse ensuite tout appel vers la source (code « coupee »), avant même les droits. Sans effet sur une source déjà coupée. Pas d’outil MCP.
Lister les plafonds d’appels
GET /v1/teams/{slug}/call-limits
Rend les plafonds d’appels par appelant : ceux d’une source (?connexion=) et ceux de toute l’organisation, qui valent aussi pour elle ; sans connexion, tous. Pour chacun : l’appelant, la fenêtre, le nombre, les appels de la fenêtre en cours et quand elle repart. Il faut org.view.
Paramètres : connection.
Poser un plafond d’appels
POST /v1/teams/{slug}/call-limits
Pose un plafond, ou change son nombre : un appelant, une fenêtre (minute, heure, jour, mois) et un nombre d’appels, sur une source (connexion) ou sur toute l’organisation. L’appelant est appli:<projet>/<service>, task:<projet>/<tâche>, personne:<e-mail>, agent:<identifiant>, compte_service:<nom> ou groupe:<nom>, qui compte ses membres et leurs agents ensemble. Au-delà, le relais refuse l’appel (429, code « plafond », Retry-After) ; une alerte part à 80 %, une autre au premier refus, une fois par fenêtre. Il faut connection.configure, et l’offre Entreprise pour une organisation qui a une offre.
Corps : connection, caller (obligatoire), window (obligatoire), calls (obligatoire).
Retirer un plafond d’appels
DELETE /v1/teams/{slug}/call-limits/{limit}
Il faut le même droit que pour le poser (connection.configure), quelle que soit l’offre. Noté au journal.
Lister les liaisons d’une connexion fédérée
GET /v1/teams/{slug}/connections/{connection}/bindings
Pour la fédération OIDC : chaque liaison, avec son sub (b:<uuid>), son état (demandee, validee, suspendue ou retiree), ce qu’elle fige (audience, hôte d’échange, hôtes d’API) et ses validations.
Demander une liaison à une connexion fédérée
POST /v1/teams/{slug}/connections/{connection}/bindings
Lie une appli de production, un service ou task:<nom>, à une connexion fédérée, en figeant ses paramètres et l’empreinte de ses règles. La liaison demande une validation stricte des approbateurs de la connexion, jamais par la plateforme ni en force, et, quand la case est cochée, celle de chaque version par les approbateurs du projet, sur une mise en production. 409 si la fédération n’est pas en service, si la connexion n’est pas fédérée et verrouillée, si l’appelant a déjà une liaison vivante, ou si la version en ligne a une image sans digest. Une liaison tombe d’elle-même (version de production sans son appelant, environnement détruit, projet supprimé, connexion refusée ou redéclarée, retrait) et ne revient jamais.
Corps : project (obligatoire), caller (obligatoire), approve_production_deploys.
Reprendre une liaison suspendue
POST /v1/teams/{slug}/connections/{connection}/bindings/{binding}/resume
Un retour arrière automatique suspend la liaison. Cet appel crée une demande stricte aux approbateurs du projet ; validée, la liaison reprend si la version en ligne est validée pour elle et n’en a pas été retirée.
Faire valider chaque mise en production d’une liaison
POST /v1/teams/{slug}/connections/{connection}/bindings/{binding}/case
La case « Faire valider chaque mise en production », avec le corps { approve: boolean, reason }. La cocher prend effet tout de suite (200) ; la décocher est une demande stricte aux approbateurs du projet (202).
Corps : approve (obligatoire), reason (obligatoire).
Retirer une liaison
DELETE /v1/teams/{slug}/connections/{connection}/bindings/{binding}
Pour de bon, avec le corps { reason }. Il faut pouvoir configurer le projet ou la connexion. Noté au journal de l’organisation.
Corps : reason (obligatoire).
Changer les lectures en POST d’une connexion
PUT /v1/teams/{slug}/connections/{connection}/post-read
Envoie la liste voulue des chemins où un POST est une lecture. Un chemin retiré vaut tout de suite : un POST y redevient une écriture, qui demande connection.write et une règle. Un chemin ajouté se fait valider, comme une règle ; un admin autonome passe sans attendre.
Corps : post_read, reason.
Demander une règle de plus
POST /v1/teams/{slug}/connections/{connection}/rules
Une règle donne une méthode, un motif (* pour un segment, ** en dernier pour le reste) et approve_each_call ; elle passe par une validation, sauf pour un admin, qui n’attend personne : appliquée tout de suite (200). Qui peut appeler se donne par une attribution (appel-connexion, appel-connexion-ecriture), pas par la règle.
Corps : method (obligatoire), pattern (obligatoire), approve_each_call, read, reason.
Lire le journal des appels d’une connexion
GET /v1/teams/{slug}/connections/{connection}/calls
Rend chaque appel et chaque refus : quand, qui et par où, méthode, chemin normalisé, statut, durée, taille du corps envoyé en octets, raison du refus, et l’attribution qui l’a permis (rôle, donnée par qui, quand) ; jamais le contenu. Rend aussi les appels retenus. 7 jours par défaut ; au-delà de 30 jours, il faut log.read sur la connexion. Gardé selon la conservation de l’organisation.
Paramètres : since, until, refusal, limit.
Lire un appel retenu
GET /v1/teams/{slug}/connections/{connection}/calls/{call}
Un appel d’une règle « valider chaque appel » : en attente, exécuté (statut et réponse, bornée), refusé ou expiré. Refusé par le relais à son exécution, il porte le refus de while : refusal, refused_by, message, what_to_do, detail.
Appeler une connexion depuis un poste
GET /sorties/{organization}/{connection}/{path}
Depuis un poste de développement ou un script, avec votre jeton personnel. while ajoute la clé, applique les règles, relaie en flux (SSE et gros envois compris) et réécrit les adresses du fournisseur vers cette adresse. Les applis hébergées par while, elles, appellent <NOM>_URL.
Appeler une connexion depuis un poste (POST)
POST /sorties/{organization}/{connection}/{path}
Mêmes règles qu’en GET. Les écritures sont bloquées pendant l’apprentissage, et une règle « valider chaque appel » rend 202.
Appeler une connexion depuis un poste (PUT)
PUT /sorties/{organization}/{connection}/{path}
Mêmes règles qu’en GET. Les écritures sont bloquées pendant l’apprentissage, et une règle « valider chaque appel » rend 202.
Appeler une connexion depuis un poste (PATCH)
PATCH /sorties/{organization}/{connection}/{path}
Mêmes règles qu’en GET. Les écritures sont bloquées pendant l’apprentissage, et une règle « valider chaque appel » rend 202.
Appeler une connexion depuis un poste (DELETE)
DELETE /sorties/{organization}/{connection}/{path}
Mêmes règles qu’en GET. Les écritures sont bloquées pendant l’apprentissage, et une règle « valider chaque appel » rend 202.
Découvrir l’émetteur OIDC d’une organisation
GET /oidc/o/{organization}/.well-known/openid-configuration
Pour la fédération OIDC : iss est l’adresse de while suivie de /oidc/o/<uuid>, avec son JWKS, en RS256. Servi dès qu’une connexion fédérée est déclarée, avant même la première clé ; 404 sans émetteur.
Sans jeton.
Lire les clés de l’émetteur OIDC d’une organisation
GET /oidc/o/{organization}/.well-known/jwks.json
Rend les clés publiques RS256 de l’organisation, jamais celles d’une autre ; kid est la version de la clé. { keys: [] } avant la première clé, 404 sans émetteur, 503 si les clés sont illisibles.
Sans jeton.
Votre compte et vos agents
Votre compte et sa langue, vos agents branchés et leurs droits, vos annonces, et la déconnexion des agents d’une personne.
Lire mes notifications : chaque sorte de courriel ou d’alerte, et si je la reçois
GET /v1/me/notifications
Régler mes notifications
PUT /v1/me/notifications
Corps { notifications: { <kind>: true | false } } (alerts, approvals, access_requests, audit_streams) ; les sortes absentes ne changent pas. Depuis la session de la personne seulement, jamais par un agent.
Corps : notifications (obligatoire).
Lire mon compte
GET /v1/me
Rend la personne connectée : son adresse, son nom s’il en a donné un, la langue de while pour elle (null : celle de son organisation), platform (true : la session du back-office d’un administrateur nommé de la plateforme) et platform_administrator (true : un administrateur de la plateforme, qui peut entrer au back-office par le SSO). Par sa session ou un jeton de son compte.
Changer la langue de mon compte
PUT /v1/me
Corps { language } : l’une des langues de while, ou vide pour celle de son organisation (400 sinon).
Corps : language.
Lire mes applis dans une organisation
GET /v1/me/apps/{organization}
Les applis internes que la personne de la session peut ouvrir dans cette organisation (la règle de chacune, comme à l’ouverture), et les invitations de cette organisation qui attendent son accord. Une organisation où rien ne lui est ouvert, ou qui n’est pas la sienne, répond comme une adresse inconnue : organization vaut null, sans son nom ; home : ses applis dans l’organisation de sa connexion d’entreprise. Depuis une session seulement.
Lister mes agents
GET /v1/me/agents
Rend les agents de la personne, de tous genres : ses agents branchés par OAuth, les jetons de son compte qui ont servi, les clients vus au journal par sa session. Chacun avec où il travaille, ce qu’il peut faire (permissions null : comme elle), quand il a été vu, ses actions des 14 derniers jours (lire, agir), sa journée heure par heure et les sources qu’il appelle. Paramètre organization (son adresse) : ceux de cette organisation, et le nombre d’agents des autres membres (other_agents). Depuis la session de la personne seulement.
Paramètres : organization.
Lire mes annonces
GET /v1/me/announcements
Les annonces en cours de l’équipe while pour la personne. Par sa session : son bandeau, moins celles qu’elle a fermées ou accusées ; ?organization= : le bandeau de cette organisation seule (404 si elle n’en est pas membre). Par son jeton : toutes celles en cours de son organisation, avec acknowledged (son accusé). read_receipt : l’annonce demande un accusé de lecture (POST /v1/announcements/{id}/acknowledge).
Paramètres : organization.
Lire un de mes agents
GET /v1/me/agents/{id}
Rend l’agent (son id : o-<famille>, j-<jeton>, s-<empreinte>), ses 25 dernières actions et ses appels aux sources, les applis où il agit, ses demandes dans son organisation (validations, droits), et les choix pour changer ses droits (change_permissions, null pour une session ou un agent qui crée son projet). Depuis la session de la personne seulement.
Déconnecter un de mes agents
DELETE /v1/me/agents/{id}
Un agent branché par OAuth (o-<famille>, ou sa famille) : ses jetons tombent, ses droits restent, il se rebranche par OAuth. Un jeton se révoque par DELETE /v1/tokens/{id}. Depuis la session de la personne seulement : un jeton ou un agent reçoit 403.
Changer les droits d’un de mes agents
PUT /v1/me/agents/{id}/permissions
Corps { level, scope, project } : level read, act ou admin ; scope app (avec project, une appli de son organisation) ou organization (pour qui y donne des accès ; admin seulement là). Jamais plus que ce que la personne peut là où il travaille ; vaut tout de suite, et c’est noté au journal. Une famille OAuth ou un jeton de son compte, depuis sa session.
Corps : level (obligatoire), scope (obligatoire), project.
Régler les groupes d’outils d’un de mes agents
PUT /v1/me/agents/{id}/tool-groups
Corps { tool_groups } : la liste entière des groupes d’outils MCP que l’agent garde (alerts, feedback_and_docs, environments_and_storage, administer), ceux qu’il a chargés par load_tools. Un groupe ne donne aucun droit : il ne fait que lister ses outils. Noté au journal ; une famille OAuth ou un jeton de son compte, depuis sa session.
Corps : tool_groups (obligatoire).
Déconnecter les agents d’une personne
POST /v1/teams/{slug}/agents/disconnect
Révoque tout de suite les familles d’accès données (agents[].familles de la liste des membres) ; la personne garde ses droits. Elle-même, ou qui administre l’organisation ; chacune au journal.
Corps : families (obligatoire).
Organisation et membres
Les organisations, leurs membres, les invitations, les groupes et la connexion d’entreprise.
Lister les organisations
GET /v1/teams
Rend vos organisations avec votre rôle, ou celle du jeton. Chacune vient avec son offre, le niveau de son abonnement du mois ({ key, label, since }), ou null sans abonnement.
Créer une organisation
POST /v1/teams
Crée une organisation depuis une session. La personne qui la crée en est propriétaire. moyen_de_paiement: "a_enregistrer" est réservé à la plateforme, pour une organisation jetable des tests (e2e-…, mode test de Mollie) : elle naît sans dérogation, son moyen de paiement à enregistrer.
Corps : slug (obligatoire), name, payment_method, language.
Lire une organisation
GET /v1/teams/{slug}
Rend la même fiche que la liste, avec votre rôle et l’offre. Une organisation qui ne vous est pas visible rend 404.
Changer la langue d’une organisation
PATCH /v1/teams/{slug}
Sa langue (langue) : celle de while pour ses membres qui n’ont pas choisi la leur, pour ses agents et ses courriels ; ses propriétaires et ses admins la changent. Une organisation ne se renomme pas : un corps qui porte slug ou nom rend 400, sans rien changer. Une organisation renommée avant garde chaque ancienne adresse 90 jours : l’API y répond sans rediriger, l’interface y redirige (302), personne d’autre ne la prend.
Corps : language, slug, name.
Lire la carte de l’organisation
GET /v1/teams/{slug}/card
Rend, en faits, les projets, leurs services (publics ou internes), leurs bases, leurs tâches et leurs connexions, et qui lit quelle base ou appelle quelle connexion. Seulement ce que vous voyez : rien d’un projet invisible, ni de ce qui le lie aux autres. L’outil MCP get_organization { view: "map" } rend la même chose.
Lister les personnes entrées par la connexion d’entreprise
GET /v1/teams/{slug}/enterprise-people
Rend les personnes entrées par la connexion d’entreprise sans être membres : adresse, nom de l’émetteur, groupes reçus, applis ouvertes et la règle qui les y laisse, dates et session. Elles n’ont aucun droit dans while.
Fermer les sessions d’une personne d’entreprise
POST /v1/teams/{slug}/enterprise-people/{id}/close-sessions
Ferme ses sessions dans while, dans le realm et dans les applis ouvertes. Elle revient tant que la règle d’une appli la laisse passer : la réponse dit lesquelles, et comment l’en empêcher.
Lister les membres
GET /v1/teams/{slug}/members
Rend les membres de l’organisation : leur rôle, depuis quand, leur nom, leur dernière connexion, s’ils entrent par le SSO, leurs groupes et leurs agents branchés. Pour qui administre, en plus : les clés de comptes de service que chacun a créées (révoquées s’il part) et l’échéance de son invitation.
Inviter une personne
POST /v1/teams/{slug}/members
Réservé aux propriétaires et aux admins. La réponse est la même, que la personne ait déjà un compte while ou non : 202 { status, email, role, invitation: null, note }. status vaut « invitation envoyée », ou « invitation enregistrée » quand aucun courriel n’est parti : envoi impossible, ou adresse de test ou d’exemple, à laquelle while n’écrit jamais. Le lien part par courriel à l’adresse invitée, jamais à qui invite. Un rôle admin ou propriétaire s’applique après la validation d’une autre personne. 10 invitations d’adresses non membres par heure et par organisation (429, retry_after_s). Un admin le fait sans attendre personne, au journal (son agent, au plancher, le lui fait confirmer), sauf si l’organisation a réglé deux approbateurs.
Corps : email (obligatoire), role, reason.
Renvoyer une invitation
POST /v1/teams/{slug}/members/{email}/resend
Envoie un nouveau lien par courriel à l’adresse invitée ; l’ancien ne sert plus. Une fois par heure au plus.
Lire un lien de rattachement à la connexion d’entreprise
GET /v1/sso/link
Le lien reçu à l’adresse d’un compte while après sa première connexion par la connexion d’entreprise de son organisation (le SSO des membres, 30 minutes) : l’adresse du compte, l’organisation et l’émetteur. Un lien qui ne sert plus : 410.
Sans jeton.
Paramètres : j (obligatoire).
Relier son compte à la connexion d’entreprise
POST /v1/sso/link
Le titulaire confirme, une fois : son compte entre ensuite par la connexion d’entreprise. Aucune session ne s’ouvre ici ; né d’une session par mot de passe, le lien demande cette même session. to : la page où aller. Depuis une page de while (contrôle d’origine) ; un lien qui ne sert plus : 410.
Sans jeton.
Corps : j (obligatoire).
Lister les groupes
GET /v1/teams/{slug}/groups
Rend les groupes de l’organisation, faits dans while ou venus de la connexion d’entreprise, et leurs membres.
Créer un groupe
POST /v1/teams/{slug}/groups
Réservé aux admins.
Corps : name (obligatoire), sso, enterprise.
Relier un groupe à un groupe d’entreprise
PUT /v1/teams/{slug}/groups/{group}/enterprise
Relie un groupe while à un groupe de l’émetteur de la connexion d’entreprise, par l’identifiant stable du groupe chez l’émetteur, jamais par son nom ; entreprise: null le détache. Réservé à une personne admin, par sa session : un jeton reçoit 403. Relier fait entrer dans le groupe ceux que l’émetteur y annonce : il faut donc avoir soi-même ce que le groupe donne. Un groupe qui administre, ou désigné approbateur, attend une validation (428). Noté au journal.
Corps : enterprise.
Lier un groupe à un groupe du SSO
PUT /v1/teams/{slug}/groups/{group}/sso
Réservé aux admins ; sso: null le détache. À chaque connexion par le SSO, si le jeton d’identité porte la revendication groups, la personne entre dans les groupes while dont le sso y figure, et sort de ceux dont il n’y figure plus, sans tenir compte de la casse ni d’un « / » initial. Noté au journal.
Corps : sso.
Changer le rôle d’un membre
PUT /v1/teams/{slug}/members/{email}/role
Donne le nouveau rôle sur l’organisation et retire l’ancien, comme les outils MCP grant_role et revoke_role, et le note au journal. access.grant suffit, puisque vous ne donnez que ce que vous avez. Nommer un admin ou un propriétaire attend la validation d’une autre personne (202) : d’ici là, la personne garde son rôle, et l’ancien part une fois validé. Le rôle externe retire tout rôle sur l’organisation entière. Un admin le fait sans attendre personne, au journal (son agent, au plancher, le lui fait confirmer), sauf si l’organisation a réglé deux approbateurs.
Corps : role (obligatoire), reason.
Supprimer un groupe
DELETE /v1/teams/{slug}/groups/{group}
Réservé aux admins. Ses désignations d’approbateur partent avec lui ; un groupe désigné approbateur demande d’abord une validation (428).
Ajouter un membre à un groupe
POST /v1/teams/{slug}/groups/{group}/members
Réservé aux admins, pour un membre de l’organisation, et pas pour un groupe de la connexion d’entreprise. Un groupe qui administre, ou désigné approbateur, demande d’abord une validation (428).
Corps : email (obligatoire).
Retirer quelqu’un d’un groupe
DELETE /v1/teams/{slug}/groups/{group}/members/{email}
Réservé aux admins. Un groupe désigné approbateur demande d’abord une validation (428).
Retirer une personne de l’organisation
DELETE /v1/teams/{slug}/members/{email}
Réservé aux admins. Ses jetons et ses agents branchés sont révoqués. Seul un propriétaire retire un propriétaire, et le dernier propriétaire ne peut pas être retiré (409).
Lire la connexion d’entreprise
GET /v1/teams/{slug}/sso
Réservé aux admins. Rend l’émetteur OpenID, le client, les domaines et la revendication des groupes. Le secret du client est au coffre : seule sa présence est dite (secret: true). domain_proofs dit, pour chaque domaine, s’il est prouvé, et l’enregistrement DNS TXT à créer (_while-challenge.<domaine>, while-verification=<jeton>). Sans preuve, aucune adresse de ce domaine n’entre.
Régler la connexion d’entreprise
PUT /v1/teams/{slug}/sso
Une connexion OpenID Connect générique : Keycloak, Google Workspace, Microsoft Entra… while lit tout de suite sa découverte (/.well-known/openid-configuration, en https, à une adresse publique). Seules les adresses des domaines donnés entrent par cette connexion, une fois chaque domaine prouvé par un enregistrement DNS TXT (domain_proofs). L’adresse de retour à déclarer chez l’émetteur est https://app.while.sh/access/sso/callback. Noté au journal.
Corps : name, issuer, client_id, secret, domains, groups_claim, active, member_sso, member_passwords, provider, tenant_id.
Retirer la connexion d’entreprise
DELETE /v1/teams/{slug}/sso
Son secret est détruit, et les sessions ouvertes par elle sont révoquées.
Lire où en est la connexion d’entreprise
GET /v1/teams/{slug}/sso/setup
Réservé aux admins, même sans connexion (connection null) : le réglage et son fournisseur, l’adresse de retour à déclarer chez lui, la preuve de chaque domaine et son enregistrement TXT, la validation en cours et qui peut la donner, les groupes reliés, les applis déjà ouvertes, le dernier essai de la personne, et les membres qui perdraient l’organisation sans mot de passe.
Vérifier les domaines maintenant
POST /v1/teams/{slug}/sso/verify
Relit tout de suite l’enregistrement TXT de chaque domaine (une fois toutes les 15 secondes au plus) et rend leurs preuves. Réservé aux admins.
Faire entrer les membres par la connexion d’entreprise
PUT /v1/teams/{slug}/sso/members
Corps { member_sso, member_passwords, confirm } : les membres entrent avec leur compte d’entreprise, et le mot de passe leur reste permis ou non (seuls les propriétaires le gardent alors). confirm est exigé quand des membres perdraient l’organisation. Une personne admin, par sa session ; noté au journal.
Corps : member_sso, member_passwords, confirm.
Essayer la connexion d’entreprise
POST /v1/teams/{slug}/sso/trial
Rend l’adresse du fournisseur où la personne admin se connecte avec son propre compte ; rien n’est ouvert ni créé. Le navigateur garde la demande (un cookie) ; au retour, while revient à la page de la connexion d’entreprise avec ce que l’essai a vu. Depuis sa session seulement.
Lister mes invitations
GET /v1/invitations
Rend les organisations où votre compte est invité. Depuis la session de la personne invitée seulement, ni jeton ni agent. Une adresse pas encore prouvée, ni par le SSO ni par un lien reçu par courriel, n’en voit aucune : address_verified: false.
Accepter une invitation
POST /v1/invitations/{organization}/accept
La personne entre dans l’organisation avec le rôle proposé, donné au nom de qui l’a invitée, dans la limite de ses droits d’aujourd’hui (sinon granted_role: false). Un rôle admin ou propriétaire attend une validation. Depuis une session, avec une adresse prouvée : un jeton, un agent ou une adresse non prouvée reçoit 403 (adresse_a_prouver : ouvrir le lien reçu par courriel, ou se connecter par le SSO).
Décliner une invitation
POST /v1/invitations/{organization}/decline
L’invitation disparaît, et le journal de l’organisation le note. Depuis une session, avec une adresse prouvée.
Accuser réception d’une annonce
POST /v1/announcements/{id}/acknowledge
La personne dit avoir pris connaissance d’une annonce de l’équipe while ; c’est daté, et son bandeau se ferme. Une personne, par sa session ou son jeton ; une clé de compte de service reçoit 403. 404 si ce n’est pas une annonce en cours de ses organisations ; 409 si elle ne demande pas d’accusé. La deuxième fois, la première date reste.
Fermer une annonce pour soi
POST /v1/announcements/{id}/close
Le bandeau ne montre plus cette annonce à la personne. Par sa session seulement (403 par un jeton). Une urgente ne se ferme pas avant sa fin (403) ; une qui demande un accusé reste jusqu’à l’accusé (POST /v1/announcements/{id}/acknowledge). 404 si ce n’est pas une annonce en cours de ses organisations.
Droits et validations
Qui peut faire quoi, les demandes d’accès, les comptes de service, les approbateurs et les règles de validation.
Lister les identités
GET /v1/teams/{slug}/identities
Les personnes, les groupes, les comptes de service et les applis qui ont une attribution, chacune avec ses accès directs en cours. Qui voit l’organisation les voit toutes ; sinon, soi seulement.
La grille des accès aux sources
GET /v1/teams/{slug}/access/grid
Ce que peut chacun sur chaque source de données, d’après ses droits effectifs : les agents (avec les droits de leur personne), les applis, les tâches et les comptes de service en lignes, les sources en colonnes ; pour chaque case, lire et écrire (sur toute la source, ou une partie de ses chemins) et la régler. Toutes les sources pour qui donne des accès, sinon celles qu’on voit.
Changer qui ouvre un service
PUT /v1/projects/{slug}/environments/{env}/services/{service}/access
ouvert : public (tout internet), organization (ses membres) ou people (qui : des adresses, des @domaines, des groupes ; membres : true pour garder aussi les membres). Le while.yaml change et une nouvelle version part (statut inchangé, sans version, quand l’accès est déjà celui demandé) ; ouvrir à tout internet ou au-delà de l’organisation demande une validation par défaut (428), que les règles de l’organisation peuvent assouplir.
Corps : open (obligatoire), who, members.
Lire les règles de validation et le budget
GET /v1/teams/{slug}/rules
rules est la liste ordonnée des règles, chacune en clair : la première qui correspond l’emporte. budget_eur est le budget mensuel (null : sans plafond). defaults dit ce qui vaut sans règle : autonome dans le budget, même en production ; validation au-delà ; validation pour rendre une appli publique. floor liste ce qui demande toujours une validation. pending montre un assouplissement qui attend sa validation.
Changer les règles et le budget
PUT /v1/teams/{slug}/rules
Réservé aux admins. Envoie la liste entière des règles, le budget, ou les deux. Ce qui durcit s’applique tout de suite (200, status « appliquées »). Ce qui assouplit, même un seul cas, ou relève le budget (null : plus de plafond) passe en entier par une validation (202, status « validation humaine requise », avec la demande). Une règle sur un geste du plancher, comme détruire des données de production, changer les accès ou la politique, ou un appel « valider chaque appel », est refusée (400, avec la raison). Le journal note ce qui assouplit et ce qui durcit.
Corps : rules, budget_eur, required_approvals.
Lire qui a accès à un projet
GET /v1/projects/{slug}/access
Rend chaque attribution du projet, ou d’une de ses bases ou tables, en une phrase : « Léa Martin lit la table ventes.commandes (entrepot, pilotage) jusqu’au 30 novembre. Donné par Oscar le 21 octobre : audit du T4. » Avec ?qui=, tout ce que cette identité peut faire ; avec ?qui= et ?permission=, oui ou non, et la chaîne qui le permet : attribution, groupe, rôle, qui l’a donnée, quand et pourquoi. Les droits des autres se lisent là où vous avez access.grant.
Paramètres : activity, project, environment, database, schema, table, columns, connection, paths, who, permission.
Lire qui a accès à une ressource de l’organisation
GET /v1/teams/{slug}/access
Comme pour un projet, sur une ressource de l’organisation, ou sur l’organisation elle-même sans ressource : qui a accès, ce que peut faire une identité, et si elle peut faire une chose.
Paramètres : activity, project, environment, database, schema, table, columns, connection, paths, who, permission.
Donner un accès
POST /v1/teams/{slug}/attributions
Donne à une identité un rôle sur une portée, jusqu’à une date, pour une raison, comme l’outil MCP grant_role. Vous ne donnez que ce que vous avez (access.grant, et chaque permission du rôle sur la portée) : jamais à vous-même, ni par votre agent, ni à un groupe dont vous êtes membre, ni à un compte de service que vous utilisez. Sans échéance : seulement pour un admin de la portée, sinon 90 jours au plus. Donner le droit d’administrer des accès attend une validation (202). Un refus (403) dit ce qui manque. Tout va au journal (famille access).
Corps : who (obligatoire), role (obligatoire), scope, until, days, reason (obligatoire).
Retirer une attribution
DELETE /v1/teams/{slug}/attributions/{id}
L’attribution ne compte plus, tout de suite. La raison est obligatoire, et va au journal.
Paramètres : reason.
Corps : reason.
Lister les attributions inutilisées
GET /v1/teams/{slug}/attributions/unused
Rend les attributions que vous pouvez retirer, sans usage depuis 60 jours : ni action permise, ni appel. Le travail périodique les signale une fois, au journal. Pour en retirer une : DELETE …/attributions/{id} ; pour la garder : POST …/attributions/{id}/garder.
Garder une attribution inutilisée
POST /v1/teams/{slug}/attributions/{id}/keep
Son compte de 60 jours repart, sans inventer d’usage, et la raison va au journal. Qui peut retirer l’attribution peut la garder, jamais la sienne.
Corps : reason (obligatoire).
Exporter les attributions pour un auditeur
GET /v1/teams/{slug}/attributions/export
Il faut log.read sur l’organisation. En JSON : chaque attribution (en cours, échue ou retirée), ses entrées du journal (numéro, empreinte, précédente, contenu haché), la tête de la chaîne et sa vérification. En CSV : une ligne par attribution, puis une ligne « verification ». L’export est noté au journal (famille security).
Paramètres : format.
Lister les rôles
GET /v1/teams/{slug}/roles
Rend les rôles fournis par while et ceux de l’organisation, leurs permissions en clair, où ils se donnent et qui les tient, et ce que vous pouvez composer.
Lire un rôle
GET /v1/teams/{slug}/roles/{role}
Rend un rôle, fourni ou de l’organisation, par sa clé.
Créer ou modifier un rôle
PUT /v1/teams/{slug}/roles/{role}
Compose un rôle de l’organisation à partir du catalogue des permissions. Il faut roles.define, et vous ne composez qu’avec ce que vous avez : chacune des permissions du rôle sur l’organisation. Modifier un rôle tenu revient à le redonner à ses titulaires : jamais pour un rôle que vous tenez vous-même (403), et un rôle tenu ne gagne jamais access.grant, org.admin ni roles.define (409). Tout va au journal (famille access), refus compris.
Corps : name, description, permissions (obligatoire), reason (obligatoire).
Supprimer un rôle
DELETE /v1/teams/{slug}/roles/{role}
Il faut roles.define. Seulement quand plus aucune attribution en cours ne le donne.
Paramètres : reason.
Corps : reason.
Lister les demandes d’accès
GET /v1/teams/{slug}/access-requests
Rend les demandes que vous pouvez trancher, les vôtres, et vos attributions qui arrivent à échéance, avec l’appel qui les renouvelle.
Demander un accès
POST /v1/teams/{slug}/access-requests
Demande un droit pour soi : une personne, son agent pour elle, ou un compte de service par sa clé. Sert aussi à renouveler une de ses attributions (renew), ou à demander l’appel d’une connexion pour une appli (for). Se fait après un 403 qui porte missing : le plus petit rôle, la plus petite portée, l’appel tout prêt. Champs : role, ou permission (while prend le plus petit rôle qui la donne), scope, reason (obligatoire), days (7 par défaut, 90 au plus). Ceux qui peuvent l’accorder sont prévenus (À traiter, courriel, et leurs agents sur while://access/events) ; sans réponse en 72 heures, elle expire. Une demande identique encore ouverte est rendue telle quelle (200), et 10 demandes au plus restent ouvertes (429). Notée au journal (famille access).
Corps : role, permission, scope, days, reason (obligatoire), renew, for.
Lire une demande d’accès
GET /v1/teams/{slug}/access-requests/{id}
Rend sa phrase, qui peut l’accorder, sa décision et ce que vous pouvez en faire. Visible par qui l’a faite et par qui donne des accès sur sa portée (access.grant) ; sinon 404.
Annuler sa demande d’accès
DELETE /v1/teams/{slug}/access-requests/{id}
Seulement tant qu’elle est ouverte.
Paramètres : reason.
Accorder une demande d’accès
POST /v1/teams/{slug}/access-requests/{id}/grant
Une personne qui peut donner ce droit l’accorde, au plus ce qui est demandé, et la demande devient une attribution bornée. Jamais sa propre demande, jamais par un agent ni un compte de service (403). Champs : role (ses permissions parmi celles demandées), scope (contenue dans celle demandée), until ou days (au plus la durée demandée, 90 jours, toujours une échéance), reason (obligatoire). Une demande de niveau admin va aux propriétaires : un admin de la portée qui n’est pas propriétaire la refuse, ou donne le rôle lui-même, et une autre personne le valide. Accorder un renouvellement prolonge l’attribution. Noté au journal.
Corps : role, scope, until, days, reason (obligatoire).
Refuser une demande d’accès
POST /v1/teams/{slug}/access-requests/{id}/deny
Une personne qui pourrait l’accorder la refuse, avec une raison, qui part à qui a demandé.
Corps : reason (obligatoire).
Lister les comptes de service
GET /v1/teams/{slug}/service-accounts
Rend chaque compte de service de l’organisation : sa phrase, ses droits, ses clés (préfixe, échéance, dernier usage) et qui l’utilise. Qui voit les membres (org.view) les voit tous ; sinon, ceux qu’il gère (access.grant sur leur portée). Un compte lit le sien par sa clé.
Créer un compte de service
POST /v1/teams/{slug}/service-accounts
Crée une identité non humaine (tableau de bord, script, agent autonome), sans droit ni clé. Il faut être une personne, ou son agent, avec access.grant sur sa portée : l’organisation, ou le projet donné. Ses droits se donnent ensuite par une attribution (qui : compte_service:<nom>), par une autre personne que celles qui l’utilisent, puis une clé. Noté au journal.
Corps : name (obligatoire), description, reason (obligatoire), project.
Lire un compte de service
GET /v1/teams/{slug}/service-accounts/{account}
Rend sa phrase, ses droits en phrases et ses clés.
Supprimer un compte de service
DELETE /v1/teams/{slug}/service-accounts/{account}
Ses attributions sont retirées (au journal), ses clés partent et son nom se libère.
Paramètres : reason.
Désactiver un compte de service
POST /v1/teams/{slug}/service-accounts/{account}/disable
Ses clés ne passent plus, ses droits ne comptent plus, et ses sessions SQL sont coupées.
Corps : reason (obligatoire).
Réactiver un compte de service
POST /v1/teams/{slug}/service-accounts/{account}/reactivate
Ses clés repartent. Il faut avoir déjà chacun de ses droits.
Corps : reason (obligatoire).
Créer une clé de compte de service
POST /v1/teams/{slug}/service-accounts/{account}/keys
Crée une clé whcs_…, montrée une seule fois, toujours à échéance : 90 jours au plus, un an pour un admin de la portée du compte. La clé donne à qui la tient tout ce que le compte peut faire : il faut gérer le compte (access.grant sur sa portée) et avoir déjà chacun de ses droits. Elle agit avec exactement ses attributions, sur l’API et le MCP, dans l’en-tête Authorization: Bearer. Le journal note la création, jamais le secret.
Corps : name, until, days, reason.
Tourner une clé
POST /v1/teams/{slug}/service-accounts/{account}/keys/{key}/rotation
Crée une nouvelle clé, aux mêmes règles qu’une création. L’ancienne vaut encore le temps du chevauchement : 24 heures par défaut, de 0 à 168.
Corps : name, until, days, overlap_hours.
Révoquer une clé
DELETE /v1/teams/{slug}/service-accounts/{account}/keys/{key}
Elle est refusée dès la requête suivante. La raison va au journal.
Paramètres : reason.
Lister qui valide quoi
GET /v1/teams/{slug}/approvers
Rend, pour chaque ressource (organisation, projets, bases, connexions), son propriétaire et ses approbateurs. Sans désignation, valident le propriétaire de la ressource et les admins de l’organisation ; une base hérite de son projet.
Désigner un approbateur
POST /v1/teams/{slug}/approvers
Désigne une personne ou un groupe comme approbateur d’une ressource. Réservé aux admins.
Corps : resource_type (obligatoire), resource, subject_type (obligatoire), subject (obligatoire).
Retirer un approbateur
DELETE /v1/teams/{slug}/approvers/{id}
Retire une désignation d’approbateur. Réservé aux admins.
Revoir les accès
GET /v1/teams/{slug}/access/review
Réservé aux admins. Rend qui lit, met en ligne et valide chaque ressource, les jetons à revoir et les agents branchés. Un agent hérite des droits de sa personne. Un jeton est « à revoir » quand il n’expire pas, qu’il n’a pas servi depuis 30 jours, ou qu’il a plus de droits que sa personne (ils sont alors plafonnés).
Lire une demande de validation
GET /v1/approvals/{id}
Rend la demande : son niveau, son empreinte, son expiration, ses approbateurs, et ce que vous pouvez en faire.
Lire le corps d’un appel retenu
GET /v1/approvals/{id}/body
Le corps d’un appel retenu (« valider chaque appel »), déchiffré pour une personne qui peut décider cette demande, connectée à while : jamais l’agent qui l’a faite, jamais un jeton. Son texte en UTF-8 (null s’il est binaire), borné à 32 000 caractères (truncated au-delà), son type, sa taille et son empreinte (la même que celle de la demande). Chaque lecture va au journal de l’organisation, sans le contenu. 404 pour qui ne peut pas décider, et une fois la demande tranchée ou expirée.
Valider une demande
POST /v1/approvals/{id}/approve
Une demande se tranche par une autre personne, approbatrice de la ressource, connectée à while : jamais sa propre demande, ni celle de son agent (même compte, 403). Un jeton (d’agent, OAuth ou de compte de service) ne tranche ni ne force jamais : 403, raison « agent », avec le lien de la demande à transmettre à sa personne (action.lien). Refuser et passer en force demandent un motif (400 sans motif) ; passer en force est réservé aux admins de l’organisation et émet l’événement sh.while.approval.forced. Une demande déjà tranchée ou expirée rend 409.
Corps : reason.
Refuser une demande
POST /v1/approvals/{id}/reject
Une demande se tranche par une autre personne, approbatrice de la ressource, connectée à while : jamais sa propre demande, ni celle de son agent (même compte, 403). Un jeton (d’agent, OAuth ou de compte de service) ne tranche ni ne force jamais : 403, raison « agent », avec le lien de la demande à transmettre à sa personne (action.lien). Refuser et passer en force demandent un motif (400 sans motif) ; passer en force est réservé aux admins de l’organisation et émet l’événement sh.while.approval.forced. Une demande déjà tranchée ou expirée rend 409.
Corps : reason.
Passer une demande en force
POST /v1/approvals/{id}/force
Une demande se tranche par une autre personne, approbatrice de la ressource, connectée à while : jamais sa propre demande, ni celle de son agent (même compte, 403). Un jeton (d’agent, OAuth ou de compte de service) ne tranche ni ne force jamais : 403, raison « agent », avec le lien de la demande à transmettre à sa personne (action.lien). Refuser et passer en force demandent un motif (400 sans motif) ; passer en force est réservé aux admins de l’organisation et émet l’événement sh.while.approval.forced. Une demande déjà tranchée ou expirée rend 409.
Corps : reason.
Lister les demandes en attente
GET /v1/approvals
Rend les demandes des projets que vous voyez, et celles de vos organisations selon votre rôle. Un jeton de projet ne voit que celles de son projet.
Paramètres : organization.
Lister les demandes de validation d’une organisation
GET /v1/teams/{slug}/approvals
Les demandes de validation de cette organisation que votre identité voit, en attente et tranchées, les plus récentes d’abord (50 au plus) ; chacune comme GET /v1/approvals/{id} la rend : qui l’a tranchée (decided_by), quand (decided_at), son motif (decision_reason). Une demande passée sans réponse est rendue expirée.
Journal
Le journal de l’organisation : le lire, l’exporter, le vérifier et l’envoyer à un SIEM.
Lire le journal de l’organisation
GET /v1/teams/{slug}/activity-log
Qui a fait quoi, par quoi, sur quoi, du plus récent au plus ancien. Le journal s’écrit en ajout seul, chaîné par empreinte, et se garde 13 mois par défaut. Un admin de l’organisation lit tout ; un membre lit les entrées des projets qu’il voit et ses propres actions ; un jeton de projet, son projet. Les appels des connexions et les lectures SQL n’y laissent que des métadonnées : la requête normalisée sans ses valeurs, jamais de résultat.
Paramètres : tab, person, via, family, project, resource, since, until, cursor, limit.
Exporter le journal en JSON Lines
GET /v1/teams/{slug}/activity-log.jsonl
Une entrée par ligne, avec les mêmes filtres que la lecture ; il faut le droit d’exporter le journal, plus large que celui de le lire. L’export est noté au journal.
Paramètres : tab, person, via, family, project, resource, since, until, cursor.
Exporter le journal vérifiable
GET /v1/teams/{slug}/activity-log/verifiable.jsonl
Toute la chaîne de l’organisation, revérifiable hors de while. En JSONL : un en-tête (l’ancre de départ, les caviardages), chaque entrée avec son rang (seq), son empreinte, la précédente et le contenu haché, puis une fin, la tête et sa signature Ed25519. ?depuis=<rang> donne la suite d’un export précédent. Il faut log.export sur l’organisation entière.
Paramètres : since.
Lire les clés publiques du journal
GET /journal/o/{organization}/cles.json
Rend chaque version des clés publiques du journal d’une organisation, l’ancienne comprise, par l’identifiant stable de l’organisation.
Lister les flux vers un SIEM
GET /v1/teams/{slug}/activity-log/streams
Réservé aux admins. Rend chaque flux du journal vers un SIEM et son état : curseur, dernier envoi, retard, erreurs.
Ajouter un flux vers un SIEM
POST /v1/teams/{slug}/activity-log/streams
Une personne admin, par sa session, avec l’offre Entreprise. Corps : { name, url, since, delay_threshold_minutes }, avec une url en https, publique, et since à maintenant ou à start. while envoie des lots JSONL signés comme les alertes (Standard Webhooks) ; le rang fait foi. La clé de signature n’est rendue qu’une fois.
Corps : name, url, since, delay_threshold_minutes.
Retirer un flux vers un SIEM
DELETE /v1/teams/{slug}/activity-log/streams/{stream}
Réservé aux admins, dans leur session : un jeton ne retire pas un flux.
Vérifier la chaîne du journal
GET /v1/teams/{slug}/activity-log/verification
Toute personne qui lit le journal. Rend ok, ou la première entrée qui ne colle pas. Après une purge de conservation, la chaîne repart de l’empreinte de la dernière entrée purgée (since_purge).
Régler la conservation du journal
PUT /v1/teams/{slug}/activity-log/retention
Réservé aux admins : de 1 à 120 mois, 13 par défaut. La purge passe chaque jour.
Corps : month (obligatoire).
Lire la conservation des appels des connexions
GET /v1/teams/{slug}/activity-log/call-retention
Rend la durée, en jours, pendant laquelle le journal des appels des connexions est gardé.
Régler la conservation des appels des connexions
PUT /v1/teams/{slug}/activity-log/call-retention
Il faut org.admin. De 90 jours à 5 ans, 400 jours par défaut ; la durée vaut aussi pour les appels déjà gardés.
Corps : days (obligatoire).
Consommation et quotas
Ce que consomment les applis, ce que coûte un mois, et les limites.
Lire la consommation d’un projet
GET /v1/projects/{slug}/usage
Rend la consommation du mois (CPU, mémoire, requêtes, constructions, bases, caches), son coût, la projection des alertes et le budget. per_month_euros est ce que coûterait un mois normal à ce rythme : les bases et les caches à leur réservation d’aujourd’hui, l’appli à sa consommation moyenne des 7 derniers jours (ou depuis sa mise en ligne), sur un mois entier, sans le forfait de l’offre, qui est celui de l’organisation. Le coût suit les prix de l’organisation, ceux de son abonnement (sa grille, son niveau, ses remises) ou, sans abonnement, la grille de référence à son niveau par défaut ; il est donné à ce jour et projeté, et detail le donne par ligne de la grille. pricing donne ces prix : price_list, subscription, level, levels[], resources[] { key, label, unit, price_cents, by, text, negocie?, prix_grille_centimes? }, options[], discounts[] { target, text }, included[] et examples.
Lire le relevé mensuel
GET /v1/teams/{slug}/statement
Rend les quantités du mois qu’un modèle de prix facturerait, sans les prix : le calcul consommé (vCPU·h, Gio·h) des applis, des caches et des bases ; ce que les bases réservent (taille, haute disponibilité, disque) ; le stockage objet ; les requêtes ; les constructions ; les connexions avec et sans clé, et leurs appels ; les développeurs, lecteurs, membres et comptes de service ; les réglages (SSO, droits fins, conservation). Le relevé est provisoire pendant le mois, recalculé chaque heure, et clos une heure après sa fin. Réservé aux admins de l’organisation.
Paramètres : month, recompute.
Lire la consommation de l’organisation
GET /v1/teams/{slug}/usage
Réservé aux admins de l’organisation. Le montant principal est euros_per_month, en euros HT : ce que coûterait un mois normal à ce rythme, le même que la page Consommation et l’outil MCP get_organization. per_month le détaille : le forfait de l’offre, les bases et les caches à leur réservation d’aujourd’hui, les applis à leur consommation moyenne des 7 derniers jours, sur un mois entier ; calculation dit comment. since_start est ce qui est dû depuis le 1er du mois, ou depuis la création (since), c’est-à-dire ce qui sera facturé pour ce mois. estimated_month_end est la projection des alertes de budget, et per_app détaille chaque appli, brique par brique. Les lignes de per_month et de since_start sont en centimes HT, avec leur devise.
Lire les quotas
GET /v1/teams/{slug}/quotas
Réservé aux admins de l’organisation. Pour chaque ressource : la limite, par défaut ou relevée, l’usage, et si elle est atteinte. Une limite se relève sur demande à l’équipe while. Au-delà d’une limite, la création est refusée : 409 pour un stock, 429 pour un débit (avec retry_after_s), avec un Problem de type https://while.sh/problems/quota-exceeded et l’extension quota { resource, label, scope, unit, usage, request, limit, default, raise }.
Retours à l’équipe while
Un bug, un blocage ou une idée envoyés à l’équipe while, et ce que des personnes pointent sur une appli.
Lister vos retours
GET /v1/feedback
Rend vos retours à l’équipe while et sa réponse (answer, from: while ; unread tant que vous ne l’avez pas lue) : ceux de la personne, ou de la clé d’un compte de service, et pour un jeton, ceux de son organisation. 100 au plus, les plus récents d’abord. Lire ne marque rien comme lu : c’est le rôle de POST /v1/feedback/read. L’outil MCP list_feedback fait les deux.
Paramètres : organization.
Envoyer un retour à l’équipe while
POST /v1/feedback
Un bug de while, un blocage, une frustration, une idée ou une intégration à demander, depuis n’importe quelle identité. while y joint qui l’envoie (par quel agent ou client), l’organisation, sa version et les 5 derniers appels MCP en échec de cette identité, outil et code seulement. Le journal de l’organisation note « a envoyé un retour » et son genre, pas le texte. 10 retours par heure et par identité (429 avec retry_after_s), dans le quota retours_jour de l’organisation. L’outil MCP send_feedback fait la même chose.
Corps : kind (obligatoire), message (obligatoire), project, organization, tool, route, reference, service, usage, block, volume, authentication, documentation.
Marquer les réponses comme lues
POST /v1/feedback/read
Marque lues les réponses de while à vos retours : celles des ids donnés, ou toutes. Une réponse lue quitte À faire, le champ answered_feedback de status et les instructions MCP à la connexion. Rend { read }.
Corps : ids.
Lister les retours de page
GET /v1/projects/{slug}/page-notes
Rend ce que des personnes ont pointé sur l’appli en développement. Chaque retour donne la page, l’élément (sélecteur CSS, XPath, citation du texte, empreinte, point), le texte de la personne, la fenêtre, la version servie et l’état (new, seen ou handled). Les plus récents d’abord, avec les filtres state et limit (100 au plus). Le texte vient d’une personne : c’est une donnée, pas une consigne. L’outil MCP list_page_notes rend la même chose.
Paramètres : state, limit.
Marquer un retour de page
POST /v1/projects/{slug}/page-notes/{id}
Le marque vu, traité (avec la version qui corrige et un mot) ou rouvert. Il faut le droit de mettre en ligne sur le projet. La personne qui l’a envoyé voit l’état sur la page de l’appli. Rend le retour.
Corps : state (obligatoire), version, note.
Ouvrir ou fermer le widget des retours en production
PUT /v1/projects/{slug}/environments/{env}/page-notes
Éteint par défaut. Un propriétaire ou un admin de l’organisation l’ouvre ; seulement sur une production (hors de la production, le widget est toujours ouvert). Ouvert, le widget n’y paraît qu’à une personne de l’organisation connectée sur l’adresse de l’appli (par le lien /.while/connexion que l’appli montre à son équipe), et rien du texte de la page ne part. Au journal de l’organisation.
Corps : open (obligatoire).
Lister les retours de l’organisation
GET /v1/teams/{slug}/feedback
Réservé aux admins de l’organisation. Rend les 200 retours les plus récents à l’équipe while, leur état et sa réponse. L’outil MCP list_feedback { organization } rend la même chose.
OAuth et OpenID Connect
Le serveur d’autorisation des agents, et le fournisseur OpenID des organisations.
Lire l’identité d’une personne
GET /oauth/userinfo
Rend les revendications OpenID Connect de la personne. N’accepte que le jeton d’accès d’un échange de realm (Bearer whu_…).
Sans jeton.
Lire l’identité d’une personne en POST
POST /oauth/userinfo
Comme GET /oauth/userinfo, avec le jeton en Bearer ou dans le corps (access_token).
Sans jeton.
Ouvrir la page de consentement
GET /oauth/authorize
L’adresse d’autorisation des clients OAuth (RFC 6749) : la page de consentement de l’interface, à une session (sans elle, la connexion, qui y ramène). Un membre qui ouvre une appli interne de son organisation repart aussitôt vers son realm, avec son code.
Sans jeton.
Enregistrer un client OAuth
POST /oauth/register
Enregistre dynamiquement un client public (RFC 7591). PKCE est obligatoire.
Sans jeton.
Corps : client_name, redirect_uris (obligatoire), token_endpoint_auth_method.
Obtenir un jeton OAuth
POST /oauth/token
Échange un code d’autorisation, avec son code_verifier PKCE, ou fait tourner un jeton de rafraîchissement. Un jeton de rafraîchissement déjà utilisé qui revient révoque toute la session. Le client confidentiel du realm d’une organisation (realm-org-<n>, ouvert par while) s’authentifie en client_secret_basic ou client_secret_post, et reçoit un id_token ES256 sans jeton de rafraîchissement.
Révoquer un jeton OAuth
POST /oauth/revoke
Révoque un jeton (RFC 7009). Révoquer un jeton de rafraîchissement révoque toute sa session.
Sans jeton.
Lire les métadonnées du serveur OAuth
GET /.well-known/oauth-authorization-server
Rend les métadonnées du serveur d’autorisation OAuth 2.1 de while (RFC 8414), aussi servies sous /.well-known/openid-configuration.
Sans jeton.
Découvrir la configuration OpenID Connect
GET /.well-known/openid-configuration
Rend les métadonnées OAuth des agents, et celles du fournisseur OpenID des realms des organisations : userinfo, jetons d’identité ES256, portées openid, email et profile.
Sans jeton.
Lire les métadonnées de la ressource MCP
GET /.well-known/oauth-protected-resource
Rend les métadonnées de la ressource protégée MCP (RFC 9728) : ses serveurs d’autorisation et ses droits.
Sans jeton.