Aller au contenu

Tape un mot pour chercher dans les pages.

↑↓ Choisir↵ OuvrirÉchap Fermer
Ouvrir Portal

Référence

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.json

Adresse 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.

DroitsPortéeCe qu’elle permet
Lecture seuleportal:readLes routes GET
Lecture et écritureportal:read portal:writeToutes 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éthodeRouteDroitsCe qu’elle fait
GET/projectsLectureListe les projets. Filtre status : active, paused, done, archived
GET/projects/{id}LectureLit un projet
GET/invoicesLectureListe les factures. Filtre status : draft, issued, paid, cancelled
GET/invoices/{id}LectureLit une facture, avec ses lignes. Montants en centimes
GET/documents?project_id=LectureListe les documents d’un projet
GET/clientsLectureListe les clients. Filtre archived : true ou false
GET/clients/{id}LectureLit une fiche client
GET/webhooksLecture, adminListe les adresses qui reçoivent les événements
POST/webhooksÉcriture, adminAjoute une adresse : url, events, description facultative
DELETE/webhooks/{id}Écriture, adminSupprime 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ÉcritureSaisit du temps : date (AAAA-MM-JJ), minutes, phase_id et note facultatifs. Le client ne le voit pas
POST/projects/{id}/phasesÉcritureAjoute une étape : name, description et due_date facultatifs. Le client la voit
POST/phases/{id}/stepsÉcritureAjoute une tâche à une étape : title, description, due_date, internal (tâche cachée au client)
POST/projects/{id}/client-actionsÉcritureDemande une action au client : title, description, due_date, phase_id. Les clients du projet reçoivent un e-mail
POST/prospectsÉcritureAjoute 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." }
CodeCe qu’il veut dire
400limit ou cursor invalide, ou corps qui n’est pas du JSON
401Clé 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é
403Clé 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)
404Ressource inconnue, ou d’un autre espace
405Méthode inconnue sur cette route
409Idempotency-Key déjà utilisée pour une autre requête
415POST sans Content-Type: application/json
422Filtre ou corps refusé. Le détail, champ par champ, est dans errors
429Trop d’appels. Attends la durée de l’en-tête Retry-After

Limites

QuoiLimite
Lectures par clé600 par minute, rafale de 120
Écritures par clé120 par minute, rafale de 30
Échecs d’authentification par adresse IP20 par 10 minutes

Une réponse 429 porte l’en-tête Retry-After et les en-têtes RateLimit de la limite atteinte.