Aller au contenu principal
Version: Prochaine version

Connecter vos outils (API)

Tout ce que vos utilisateurs font à l'écran, un programme peut le faire à leur place : lire des fiches, en créer, en modifier, en supprimer. C'est ce que permet l'API de GesHoms, à l'adresse /api/v1/.

Les usages les plus courants : alimenter un objet depuis votre site web (un formulaire de contact qui crée une fiche), synchroniser avec un logiciel existant (ERP, caisse, comptabilité), brancher un outil d'automatisation (Make, n8n, Zapier), ou sortir vos données vers un tableau de bord.

Vous n'avez qu'un fichier à reprendre ?

Pour un import ponctuel depuis Excel ou CSV, l'API est un détour inutile. Utilisez l'import de fichier, qui devine la correspondance des colonnes et annonce les erreurs avant d'écrire.

Le principe : un jeton porte des rôles

L'API n'a pas de droits à elle. Un jeton reçoit un ou plusieurs rôles, exactement les mêmes que ceux de vos utilisateurs internes (Droits d'accès), et il peut faire ce que ces rôles autorisent : ni plus, ni moins.

La conséquence est importante : un jeton sans rôle ne voit rien. Il n'y a pas de mode « accès complet ». Pour donner accès à un objet, il faut un rôle qui l'accorde, objet par objet et action par action.

Ce choix a trois avantages :

  • vous réglez les droits d'un programme au même endroit et de la même façon que ceux d'une personne ;
  • un champ masqué à un rôle l'est aussi pour l'API, y compris à travers un champ calculé qui s'appuierait dessus ;
  • un périmètre par enregistrement (« seulement les fiches de tel magasin ») s'applique aussi aux appels du programme.

1. Préparer un rôle dédié

N'accordez pas à un outil tiers le rôle de vos commerciaux. Créez-lui le sien, avec le strict nécessaire.

  1. Administration → onglet Utilisateurs & droitsRôlesNouveau rôle, par exemple Intégration site web.
  2. Ouvrir l'objet concerné dans le Studio → onglet Permissions, et cocher sur la ligne de ce rôle les seules actions utiles. Pour un formulaire de contact qui dépose des demandes : Créer, rien d'autre.
  3. Toujours dans les permissions, restreindre les champs si l'outil n'a pas à tout voir.

2. Créer le jeton

Administration → onglet Applications → section 🔌 API (outils tiers)Nouveau jeton.

RéglageÀ quoi il sert
NomReconnaître l'outil dans la liste et dans le journal. Écrivez à quoi il sert, pas « test ».
Rôles accordésLes droits du jeton. Au moins un, sinon la création est refusée.
Limite d'appels / minGarde-fou contre un script emballé. 0 signifie illimité.
ExpirationDate au-delà de laquelle le jeton cesse de fonctionner. Recommandée pour un prestataire.
IP autoriséesListe d'adresses, séparées par des virgules. Vide signifie « depuis n'importe où ».
Le secret n'est affiché qu'une fois

À la création, GesHoms affiche le jeton en clair, une seule fois. Il n'est pas stocké en clair et personne ne peut le relire ensuite, pas même vous. Copiez-le immédiatement dans le coffre de mots de passe de l'outil. Perdu, il ne se récupère pas : on en crée un autre et on révoque l'ancien.

Dans la liste, chaque jeton affiche son état (Actif, Expiré, Révoqué), son préfixe public, le nombre de rôles et la date de dernier usage. Le bouton Révoquer coupe l'accès immédiatement, sans rien supprimer de vos données.

3. Appeler l'API

Toutes les requêtes portent le jeton dans un en-tête :

Authorization: Bearer <votre-jeton>

Quatre routes suffisent à tout faire.

RouteMéthodeEffet
/api/v1/health/GETCe que le jeton peut faire : objets accessibles, actions autorisées, expiration
/api/v1/openapi.jsonGETLa description technique de votre API, limitée aux droits du jeton
/api/v1/data/<objet>/GETLister les fiches
/api/v1/data/<objet>/POSTCréer une fiche
/api/v1/data/<objet>/<id>/GETLire une fiche
/api/v1/data/<objet>/<id>/PATCHModifier une fiche (seuls les champs envoyés changent)
/api/v1/data/<objet>/<id>/DELETEMettre une fiche à la corbeille

<objet> est le code de l'objet, pas son libellé : client, commande, ligne_commande. Vous le lisez dans le Studio, sous le nom de l'objet.

Commencer par se présenter

curl -H "Authorization: Bearer ght_xxx…" \
https://votre-domaine/api/v1/health/
{
"ok": true,
"token": "Intégration site web",
"expires_at": null,
"rate_limit_per_min": 60,
"objects": [
{"code": "client", "name": "Client", "actions": ["create", "read"]}
]
}

C'est le premier appel à faire quand quelque chose ne marche pas : il répond à la question « ce jeton a-t-il vraiment le droit que je crois ? ».

Créer une fiche

curl -X POST https://votre-domaine/api/v1/data/client/ \
-H "Authorization: Bearer ght_xxx…" \
-H "Content-Type: application/json" \
-d '{"nom": "Boulangerie Martin", "email": "contact@martin.fr", "ville": "Nantes"}'

La réponse est la fiche créée, avec son id et ses valeurs telles que GesHoms les a enregistrées :

{"id": 42, "created_at": "2026-08-20T08:21:12+00:00", "nom": "Boulangerie Martin",
"email": "contact@martin.fr", "ville": "Nantes", "magasin": null}

Lister, chercher, paginer

curl -H "Authorization: Bearer ght_xxx…" \
"https://votre-domaine/api/v1/data/client/?search=martin&limit=50&offset=0"
{"count": 137, "results": []}
ParamètreRôleDéfaut
searchRecherche libre sur les champs texte lisibles par le jeton, champs sensibles exclusvide
filtersFiltres précis, en JSON (section suivante)aucun
order_byChamp de triles plus récentes d'abord
order_dirasc ou descasc
limitNombre de fiches par page, plafonné à 20050
offsetRang de départ, pour parcourir page par page0

count est le total qui correspond à la recherche et aux filtres, pas le nombre de lignes renvoyées : c'est lui qui vous dit quand vous arrêter de paginer.

Filtrer et trier

search cherche un mot partout ; filters pose des conditions précises. Le paramètre attend du JSON, une liste de triplets ["champ", "opérateur", "valeur"] :

curl -G https://votre-domaine/api/v1/data/devis/ \
-H "Authorization: Bearer ght_xxx…" \
--data-urlencode 'filters=[["statut","eq","envoye"],["total_ht","gt",1000]]' \
--data-urlencode 'order_by=date' --data-urlencode 'order_dir=desc'

Les conditions se cumulent : toutes doivent être vraies. La forme longue [{"field": "statut", "op": "eq", "value": "envoye"}] est acceptée aussi.

Type de champOpérateurs
Texte, texte longeq, neq, contains, starts
Nombre, décimaleq, neq, gt, gte, lt, lte, between
Date, date et heureon, before, after, between, in_next, in_last
Liste de choixeq, neq, in, not_in
Relationeq, in
Oui / Nonis_true, is_false
Tousempty, not_empty
Colonnes système id, created_at, updated_atcomme un nombre ou une date

between attend deux valeurs (["total_ht","between",[1000,5000]]). in_last et in_next comptent des jours (["date","in_last",30]), ce qui évite de calculer une date pivot à chaque appel.

Ne resynchroniser que ce qui a changé

updated_at se filtre comme une date. Une synchronisation qui tourne chaque nuit demande donc [["updated_at","in_last",1]] plutôt que de relire la table entière, et le tri order_by=updated_at lui rend les fiches dans l'ordre où elles ont bougé.

Un filtre incompris échoue, il n'est jamais ignoré

Un champ inconnu, un opérateur qui ne va pas avec le type, un JSON mal formé : la réponse est un 400 qui dit lequel. C'est délibéré. Ignorer un critère incompris renverrait toute la table à un programme persuadé d'avoir filtré, et le bug ne se verrait que le jour où quelqu'un compte les lignes.

Ce qui n'est ni filtrable ni triable

Un champ calculé (formule, cumul) est évalué à la lecture, après la requête : le filtrer fausserait count et la pagination. Un champ chiffré ne peut pas être comparé en base. Dans les deux cas, la réponse est un 400 explicite plutôt qu'un résultat approximatif. Enfin, un champ que le jeton n'a pas le droit de lire ne peut pas non plus servir de critère : sinon l'ordre du classement suffirait à en deviner les valeurs.

La liste exacte des champs triables de votre objet est dans openapi.json, sur le paramètre order_by.

Modifier, supprimer

curl -X PATCH https://votre-domaine/api/v1/data/client/42/ \
-H "Authorization: Bearer ght_xxx…" -H "Content-Type: application/json" \
-d '{"ville": "Rennes"}'

curl -X DELETE https://votre-domaine/api/v1/data/client/42/ \
-H "Authorization: Bearer ght_xxx…"

PATCH ne touche que les champs envoyés, les autres gardent leur valeur. DELETE met la fiche à la corbeille, d'où un administrateur peut la restaurer.

En Python

import requests

API = "https://votre-domaine/api/v1"
H = {"Authorization": "Bearer ght_xxx…"}

r = requests.post(f"{API}/data/client/", headers=H, timeout=10,
json={"nom": "Boulangerie Martin", "email": "contact@martin.fr"})
r.raise_for_status()
print("fiche créée :", r.json()["id"])

Quelle valeur envoyer pour quel champ

Le nom de la clé JSON est toujours le code du champ, celui qui sert aussi dans les formules.

Type de champCe que l'API attendExemple
Texte, texte longune chaîne"Boulangerie Martin"
Nombre entierun entier12
Nombre décimalun nombre1250.50 (point décimal, pas de virgule ni d'espace)
Oui / Nonun booléentrue
DateAAAA-MM-JJ"2026-08-20"
Date et heuredate et heure ISO"2026-08-20T14:30:00"
Liste de choixle code de l'option, pas son libellé"envoye"
Relation vers un objetl'identifiant de la fiche liée7

Une valeur vide s'envoie avec null. Un champ absent du corps est simplement laissé tel quel en modification, et laissé vide à la création.

Les valeurs calculées sont en lecture seule

Un champ calculé (formule) ou un cumul apparaît dans les réponses, mais l'envoyer en écriture n'a aucun effet : sa valeur découle des données, elle ne se pose pas. Voir Relations & calculs.

Un champ marqué sensible est chiffré dans la base et restitué en clair aux appels autorisés, sans que vous ayez rien à faire.

Comprendre les réponses

CodeSignificationQuoi faire
200Lecture ou modification réussie
201Fiche crééel'id est dans la réponse
204Fiche suppriméerien à lire, le corps est vide
400Donnée refuséele message dit quel champ et pourquoi (obligatoire manquant, valeur invalide)
401Jeton absent, invalide, expiré ou révoquévérifier l'en-tête, puis l'état du jeton dans l'écran Applications
403Action non autorisée sur cet objet, ou IP non autoriséeajouter l'action au rôle, ou l'adresse à la liste blanche
404Objet ou fiche introuvablevoir l'encadré ci-dessous
429Trop d'appels par minuteralentir, ou relever la limite du jeton
Un 404 ne veut pas toujours dire « ça n'existe pas »

Si le jeton n'a aucun rôle sur un objet, l'API répond 404, pas 403. C'est volontaire : un 403 révélerait qu'un objet nommé salaire existe chez vous. Devant un 404 inattendu, appelez /api/v1/health/ : si l'objet n'y figure pas, le problème est un rôle manquant, pas une adresse erronée.

Explorer sans écrire une ligne de code

Deux façons de voir votre API telle qu'elle est, avec vos objets et vos champs :

  • l'explorateur d'API de cette documentation : collez l'adresse de votre GesHoms et un jeton, il affiche les objets accessibles, les champs de chacun, teste les lectures et vous donne la commande curl toute faite pour les écritures ;
  • GET /api/v1/openapi.json, qui renvoie une description OpenAPI 3 de votre API, limitée à ce que le jeton peut faire. Ce fichier s'importe directement dans Postman, Insomnia ou Swagger, et sert de source à la plupart des générateurs de code.
Appels depuis un navigateur

Un programme sur un serveur appelle l'API sans contrainte particulière. Une page web, elle, est soumise aux règles du navigateur : l'origine qui appelle doit être déclarée côté serveur (variable DJANGO_CORS_ALLOWED_ORIGINS). Si l'explorateur affiche « appel bloqué par le navigateur », c'est cette déclaration qui manque, pas votre jeton. Votre administrateur technique trouvera le détail dans DEPLOY.md.

Bonnes pratiques

  • Un jeton par outil. Révoquer celui de la boutique en ligne ne doit pas couper la comptabilité, et le journal doit dire qui a fait quoi.
  • Le rôle le plus étroit possible. Un formulaire de contact n'a besoin que de Créer sur un seul objet. Il n'a pas besoin de lire les clients existants.
  • Une expiration sur les accès prestataires. Un jeton sans date de fin survit à la fin de la mission.
  • Une limite d'appels. Un script en boucle est vite arrivé, et la limite est ce qui protège vos utilisateurs de son emballement.
  • Vérifier avant d'écrire en masse. Testez sur une fiche, lisez la réponse, puis lancez le traitement complet.
  • Ne mettez jamais un jeton dans une page web publique. Ce qui est envoyé au navigateur est lisible par tout le monde. Un jeton vit sur un serveur, dans une variable d'environnement.

Ce que l'API ne fait pas encore

Autant le savoir avant de concevoir votre intégration :

  • pas de webhook sortant : GesHoms ne vient pas frapper à la porte de votre outil quand une fiche change. C'est votre programme qui interroge l'API ;
  • pas de création d'objets ni de champs par l'API : elle porte les données, pas la structure. La structure se construit dans le Studio.

Suite

L'atelier 6 construit une intégration complète, du rôle jusqu'à la révocation, avec les erreurs volontaires qui apprennent le plus.