Référence
API REST
Lire tes projets, factures, documents et clients depuis ton code, y écrire des étapes, des tâches, des messages, du temps et des prospects, et gérer tes webhooks, avec une clé d'API de l'espace.
L’API de Portal donne accès aux projets, factures, documents et clients d’un espace. Elle permet aussi d’y écrire, comme le serveur MCP, et de gérer les webhooks qui préviennent ton outil. Elle passe par les mêmes contrôles que l’interface. Pour un agent IA, utilise plutôt le serveur MCP, voir Connecter un agent IA.
La description complète, au format OpenAPI 3.1, est publique :
https://app.hgdc.ch/portal/api/v1/openapi.jsonAdresse et clé
Toutes les routes commencent par https://app.hgdc.ch/portal/api/v1. Chaque requête porte une clé d’API :
curl https://app.hgdc.ch/portal/api/v1/projects \ -H "Authorization: Bearer hgdc_portal_..."Tu crées la clé dans Réglages, section Clés d’API. Donne-lui un nom, choisis les droits et la durée (7, 30 ou 90 jours, ou 1 an). Copie-la : elle ne s’affiche qu’une fois. Portal n’en garde que l’empreinte : une clé perdue se remplace, elle ne se retrouve pas.
| Droits | Portée | Ce qu’elle permet |
|---|---|---|
| Lecture seule | portal:read | Les routes GET |
| Lecture et écriture | portal:read portal:write | Toutes les routes |
Une clé est à toi et à un seul espace. Elle agit avec tes droits, dans cet espace seulement : une ressource d’un autre espace répond comme une ressource inconnue. Tu as au plus 10 clés actives par espace.
Elle s’arrête quand elle expire, quand tu la révoques, ou quand tu quittes l’équipe de l’espace. Un propriétaire ou un admin voit les clés actives des membres dans Réglages et peut en révoquer une, par exemple après la perte d’un ordinateur.
L’API est réservée à l’équipe. Un client invité reçoit 403.
Routes
| Méthode | Route | Droits | Ce qu’elle fait |
|---|---|---|---|
GET | /projects | Lecture | Liste les projets. Filtre status : active, paused, done, archived |
GET | /projects/{id} | Lecture | Lit un projet |
GET | /invoices | Lecture | Liste les factures. Filtre status : draft, issued, paid, cancelled |
GET | /invoices/{id} | Lecture | Lit une facture, avec ses lignes. Montants en centimes |
GET | /documents?project_id= | Lecture | Liste les documents d’un projet |
GET | /clients | Lecture | Liste les clients. Filtre archived : true ou false |
GET | /clients/{id} | Lecture | Lit une fiche client |
GET | /webhooks | Lecture, admin | Liste les adresses qui reçoivent les événements |
POST | /webhooks | Écriture, admin | Ajoute une adresse : url, events, description facultative |
DELETE | /webhooks/{id} | Écriture, admin | Supprime une adresse |
POST | /projects/{id}/messages | Écriture | Écrit dans le fil du projet : body, action_id facultatif. L’équipe et les clients du projet sont prévenus |
POST | /projects/{id}/time-entries | Écriture | Saisit du temps : date (AAAA-MM-JJ), minutes, phase_id et note facultatifs. Le client ne le voit pas |
POST | /projects/{id}/phases | Écriture | Ajoute une étape : name, description et due_date facultatifs. Le client la voit |
POST | /phases/{id}/steps | Écriture | Ajoute une tâche à une étape : title, description, due_date, internal (tâche cachée au client) |
POST | /projects/{id}/client-actions | Écriture | Demande une action au client : title, description, due_date, phase_id. Les clients du projet reçoivent un e-mail |
POST | /prospects | Écriture | Ajoute un prospect à l’espace de la clé : company, puis contact_name, email, phone, notes facultatifs |
Les webhooks sont réservés aux propriétaires et aux admins de l’espace : la clé d’un membre reçoit 403. Un espace a au plus 20 adresses. Le secret de signature d’un webhook créé par l’API n’est rendu qu’une fois, dans la réponse du POST. Les événements et la vérification de la signature sont décrits dans Événements des webhooks.
Écrire
Les écritures prennent un corps JSON (Content-Type: application/json, 64 Ko au plus) et rendent 201 avec l’identifiant créé :
curl https://app.hgdc.ch/portal/api/v1/projects/k57.../phases -H "Authorization: Bearer hgdc_portal_..." -H "Idempotency-Key: maquettes-2026-11" -H "Content-Type: application/json" -d '{ "name": "Maquettes" }'{ "id": "k97…", "object": "phase", "summary": "Étape « Maquettes » ajoutée." }Elles font exactement ce que fait le serveur MCP, avec tes droits : un champ inconnu est refusé, et un rôle insuffisant reçoit 403. Un message ou une action client prévient les clients : une clé en écriture vaut ton accord, sans confirmation.
Rejouer sans écrire deux fois
Ajoute Idempotency-Key (1 à 255 caractères, sans espace) pour pouvoir renvoyer une requête qui a échoué sans savoir si elle est passée. Avec la même clé et la même requête, Portal rend le résultat du premier appel (en-tête Idempotent-Replayed: true) et n’écrit rien de plus. Avec la même clé et une autre requête, il répond 409. La clé est retenue 24 heures. Elle ne s’applique pas à la création d’un webhook.
Pagination
Les listes rendent une page à la fois :
{ "data": [{ "id": "k57…", "name": "Site vitrine", "status": "active" }], "has_more": true, "next_cursor": "eyJ…"}limit choisit la taille de la page (20 par défaut, 100 au plus). Pour la suivante, renvoie next_cursor dans cursor, avec les mêmes filtres.
Erreurs
Les erreurs suivent le format application/problem+json (RFC 9457) :
{ "type": "https://hgdc.ch/problems/not-found", "title": "Ressource introuvable", "status": 404, "detail": "Ressource introuvable." }| Code | Ce qu’il veut dire |
|---|---|
400 | limit ou cursor invalide, ou corps qui n’est pas du JSON |
401 | Clé absente, mal copiée, expirée ou révoquée. La réponse porte l’en-tête WWW-Authenticate. Crée une autre clé |
403 | Clé ou jeton sans la portée demandée (insufficient_scope, par exemple une écriture avec la lecture seule), webhooks sans être admin, ou client invité. Le corps est du JSON d’erreur et l’en-tête WWW-Authenticate nomme la portée qui manque (portal:write) |
404 | Ressource inconnue, ou d’un autre espace |
405 | Méthode inconnue sur cette route |
409 | Idempotency-Key déjà utilisée pour une autre requête |
415 | POST sans Content-Type: application/json |
422 | Filtre ou corps refusé. Le détail, champ par champ, est dans errors |
429 | Trop d’appels. Attends la durée de l’en-tête Retry-After |
Limites
| Quoi | Limite |
|---|---|
| Lectures par clé | 600 par minute, rafale de 120 |
| Écritures par clé | 120 par minute, rafale de 30 |
| Échecs d’authentification par adresse IP | 20 par 10 minutes |
Une réponse 429 porte l’en-tête Retry-After et les en-têtes RateLimit de la limite atteinte.
Cette page t'a aidé ?
Merci, c'est noté.