Business Digital

API REST GLPI : integrer un script Python ou un portail metier

13 دقائق للقراءة

Le moment où un service desk passe de simple outil à pilier de l’écosystème IT est celui où il commence à dialoguer avec d’autres applications. Une plateforme RH crée automatiquement un ticket d’onboarding quand un contrat est signé. La supervision ouvre un incident dès qu’une alerte critique se déclenche. Un portail interne propose un raccourci « Demander une intervention » qui pousse directement dans GLPI. Tout cela passe par l’API REST de GLPI, exposée sur /apirest.php et stable depuis plusieurs versions majeures.

Ce tutoriel détaille pas à pas l’activation de l’API, l’authentification, les opérations CRUD essentielles, et finit par un script Python prêt à l’emploi pour créer un ticket depuis n’importe quel système tiers. Le contexte ITSM global est posé dans GLPI 11 helpdesk ITIL : déployer un service desk professionnel.

Étape 1 — Activer l’API REST côté serveur

L’API n’est pas active par défaut. Allez dans « Configuration » → « Générale » → « API ». Cochez :

  • Activer l’API REST sur Oui
  • Activer le mode de connexion par identifiants sur Oui (utile pour les tests, à désactiver ensuite si l’on passe sur User Token uniquement)
  • Activer le mode de connexion par user_token sur Oui — c’est la méthode recommandée pour les intégrations

Notez l’URL exposée, généralement https://glpi.example.com/apirest.php. Si vous accédez à GLPI via un reverse proxy avec un chemin spécifique, l’URL change en conséquence.

Étape 2 — Créer un App-Token dédié à l’intégration

L’App-Token identifie l’application appelante (la supervision, le portail RH, votre script Python). C’est un anti-bruit de fond utile : si trois intégrations existent, vous pouvez révoquer l’une sans casser les deux autres. Toujours dans la page « API », cliquez « Ajouter un client API ». Définissez :

  • Nom : « Script Python opérations » par exemple
  • Plage IP autorisée : restreindre à l’IP du serveur qui appellera (par exemple 10.0.5.42/32)
  • App-Token : laissez GLPI le générer, ou collez-en un de 40 caractères aléatoires
  • Active : Oui

L’App-Token sera passé dans chaque requête sous l’en-tête App-Token: <valeur>. Sans cette restriction, un attaquant qui aurait récupéré le User Token pourrait l’utiliser depuis n’importe quelle IP — l’App-Token filtre la source.

Étape 3 — Générer le User Token du compte de service

Créez un compte GLPI dédié aux intégrations, par exemple svc-integration, avec un profil Technician ou supérieur selon les opérations à autoriser. N’utilisez jamais un compte personnel : un départ casserait toutes les intégrations.

Connectez-vous avec ce compte, allez dans « Mes préférences » → onglet « Personnalisation » → « Clé d’accès à distance ». Cliquez « Régénérer » et notez la chaîne de 40 caractères. C’est votre User Token.

Ce User Token et l’App-Token sont les deux secrets à protéger jalousement : stockez-les dans le coffre-fort de votre orchestrateur (HashiCorp Vault, AWS Secrets Manager, Bitwarden Secrets) plutôt qu’en clair dans un fichier de configuration.

Étape 4 — Initier une session avec curl

Avant d’écrire du code, validez la chaîne complète avec curl. L’API GLPI suit un cycle initSession → opérations → killSession :

curl -X GET \
  -H "Content-Type: application/json" \
  -H "Authorization: user_token VotreUserToken40Caracteres" \
  -H "App-Token: VotreAppToken40Caracteres" \
  "https://glpi.example.com/apirest.php/initSession"

La réponse en cas de succès est un JSON avec un session_token. Notez-le, il valide les appels suivants.

En cas d’échec, les codes HTTP sont explicites :

  • 400 — paramètre manquant, généralement l’App-Token absent
  • 401 — User Token invalide, IP non autorisée, ou utilisateur désactivé
  • 403 — l’API est désactivée côté GLPI ou l’IP n’est pas dans la plage autorisée

Lisez aussi le corps de la réponse, GLPI renvoie souvent un tableau JSON [code, message] très explicite, par exemple ["ERROR_LOGIN_PARAMETERS_MISSING", "missing User Token in HTTP Authorization Header"].

Étape 5 — Créer un ticket en ligne de commande

Avec un session_token en main, créez un ticket de test :

SESSION="VotreSessionTokenObtenuJusteAvant"
curl -X POST \
  -H "Content-Type: application/json" \
  -H "Session-Token: $SESSION" \
  -H "App-Token: VotreAppToken40Caracteres" \
  -d '{"input": {"name":"Test API curl","content":"Ouverture via API","type":1,"itilcategories_id":0}}' \
  "https://glpi.example.com/apirest.php/Ticket"

La réponse est {"id": 12345, "message": ""}. Allez vérifier dans GLPI que le ticket est bien apparu avec le titre attendu. Le champ type vaut 1 pour Incident, 2 pour Demande. Les itilcategories_id, urgency, impact, requesterusers_id sont des entiers correspondant aux IDs internes que vous récupérez via d’autres appels API (par exemple GET /apirest.php/ITILCategory pour lister les catégories).

Fermez ensuite votre session :

curl -X GET \
  -H "Session-Token: $SESSION" \
  -H "App-Token: VotreAppToken40Caracteres" \
  "https://glpi.example.com/apirest.php/killSession"

Garder une session ouverte trop longtemps épuise le pool côté serveur. La bonne pratique : initSession → opération → killSession, ou réutiliser une session pendant un script court mais la tuer à la fin.

Étape 6 — Script Python prêt à l’emploi

Voici un script Python autonome qui crée un ticket en respectant les bonnes pratiques (gestion d’erreurs, contexte manager pour killSession garanti, secrets via variables d’environnement) :

import os
import sys
import requests
from contextlib import contextmanager

GLPI_URL = os.environ["GLPI_URL"].rstrip("/")
USER_TOKEN = os.environ["GLPI_USER_TOKEN"]
APP_TOKEN = os.environ["GLPI_APP_TOKEN"]

@contextmanager
def glpi_session():
    headers = {
        "Content-Type": "application/json",
        "Authorization": f"user_token {USER_TOKEN}",
        "App-Token": APP_TOKEN,
    }
    r = requests.get(f"{GLPI_URL}/apirest.php/initSession", headers=headers, timeout=10)
    r.raise_for_status()
    session_token = r.json()["session_token"]
    auth_headers = {
        "Content-Type": "application/json",
        "Session-Token": session_token,
        "App-Token": APP_TOKEN,
    }
    try:
        yield auth_headers
    finally:
        requests.get(
            f"{GLPI_URL}/apirest.php/killSession",
            headers=auth_headers,
            timeout=5,
        )

def create_ticket(title: str, body: str, urgency: int = 3) -> int:
    payload = {
        "input": {
            "name": title,
            "content": body,
            "type": 1,
            "urgency": urgency,
        }
    }
    with glpi_session() as headers:
        r = requests.post(
            f"{GLPI_URL}/apirest.php/Ticket",
            headers=headers,
            json=payload,
            timeout=10,
        )
        r.raise_for_status()
        return r.json()["id"]

if __name__ == "__main__":
    ticket_id = create_ticket(
        title="Alerte CPU serveur app01 supérieur 95 pourcent",
        body="Détecté par Zabbix à 14h32 - investigation en cours",
        urgency=4,
    )
    print(f"Ticket #{ticket_id} créé")

Définissez les variables d’environnement avant l’exécution :

export GLPI_URL="https://glpi.example.com"
export GLPI_USER_TOKEN="VotreUserToken40Caracteres"
export GLPI_APP_TOKEN="VotreAppToken40Caracteres"
python3 create_ticket.py

La sortie attendue est Ticket #12346 créé. Vérifiez immédiatement dans GLPI que le ticket existe avec la bonne urgence (4 = Élevée dans la valeur d’urgence GLPI standard).

Étape 7 — Opérations CRUD au-delà du Ticket

La même mécanique fonctionne pour tous les objets GLPI. Quelques exemples utiles :

Opération Méthode URL
Lister les tickets GET /apirest.php/Ticket?range=0-19&forcedisplay[0]=1&forcedisplay[1]=12
Lire un ticket GET /apirest.php/Ticket/12345
Mettre à jour un ticket PUT /apirest.php/Ticket/12345
Supprimer un ticket DELETE /apirest.php/Ticket/12345?force_purge=true
Ajouter un suivi POST /apirest.php/Ticket/12345/ITILFollowup
Ajouter un document POST /apirest.php/Document — payload multipart
Récupérer un utilisateur GET /apirest.php/User/42
Rechercher des actifs GET /apirest.php/search/Computer?criteria[0][field]=1&criteria[0][searchtype]=contains&criteria[0][value]=srv-prod

La syntaxe de recherche est riche mais demande de la rigueur. Pour identifier le numéro de champ associé à un attribut (le « 1 » dans field=1), passez d’abord par /apirest.php/listSearchOptions/Computer qui retourne le mapping nom de champ → ID interne.

Étape 8 — Sécuriser et limiter l’exposition

Une API exposée à Internet est une surface d’attaque. Quatre garde-fous obligatoires :

HTTPS exclusif. Le serveur web doit refuser tout appel HTTP à /apirest.php. La configuration Let’s Encrypt mise en place dans l’installation Ubuntu couvre déjà ce point.

Filtrage IP côté GLPI. L’App-Token doit être restreint aux IPs des systèmes qui légitiment l’usage. Pas besoin qu’un script de comptabilité puisse appeler l’API depuis n’importe où.

Rate limiting au reverse proxy. Nginx ou Apache peuvent limiter le nombre de requêtes par seconde sur /apirest.php pour éviter qu’un bug client n’écroule l’API. Une règle Nginx limit_req zone=apirest burst=20 nodelay; couplée à limit_req_zone $binary_remote_addr zone=apirest:10m rate=10r/s; tient la charge.

Audit logs. GLPI journalise les sessions API dans files/_log/api.log. Pensez à le faire tourner avec logrotate et à l’envoyer vers votre SIEM si vous en avez un.

Étape 9 — Cas typiques d’intégration

Trois cas qui couvrent 80 % des intégrations réelles :

Ouverture automatique sur alerte supervision. Zabbix, Centreon, Prometheus + Alertmanager déclenchent un webhook vers un script qui crée un ticket. Le payload de l’alerte est mappé sur le titre, la description et la priorité du ticket. Le ticket est attribué au groupe SOC et l’identifiant de l’alerte est stocké dans un champ personnalisé pour le rapprochement lors de la résolution.

Onboarding utilisateur depuis la plateforme RH. Au moment où un contrat est signé, la plateforme RH (Lucca, SuccessFactors, BambooHR) appelle l’API GLPI pour créer un ticket d’onboarding avec une checklist (créer compte AD, attribuer poste, fournir badge, planifier formation). Le ticket est suivi par le service desk jusqu’à la fin du processus.

Portail métier qui pré-renseigne les tickets. Un portail interne (Symfony, Laravel, .NET) propose un formulaire spécifique au métier (par exemple « Réserver une salle équipée »). Le portail valide les règles métier propres à l’application, puis pousse vers GLPI un ticket pré-typé, déjà attribué au bon groupe.

Erreurs fréquentes

Symptôme Cause Solution
HTTP 400 « missing user token » En-tête mal écrit Vérifier Authorization: user_token TOKEN avec un espace
HTTP 401 sans message clair App-Token désactivé ou IP non autorisée Vérifier l’IP du client et la plage autorisée
HTTP 200 mais aucun ticket créé Champ obligatoire manquant côté GLPI Inspecter la réponse JSON pour le message d’erreur
Timeout sur initSession Serveur GLPI saturé ou base lente Optimiser les indexes MariaDB, augmenter le timeout client
Session expirée en plein script Inactivité supérieure à 1 heure Faire un killSession + initSession pour chaque batch

Articles associés

Références

Pagination et performances sur les listes massives

Quand un parc dépasse les 5 000 actifs ou que les tickets se comptent en dizaines de milliers, un GET /Computer sans pagination saturera la base et expirera côté client. GLPI propose nativement la pagination via les paramètres range :

curl -X GET \
  -H "Session-Token: $SESSION" \
  -H "App-Token: $APPTOKEN" \
  "https://glpi.example.com/apirest.php/Computer?range=0-49"

La réponse contient un en-tête Content-Range du type 0-49/3217 qui indique le total. Bouclez en incrémentant la plage de 50 en 50 jusqu’à atteindre le total. En Python :

def list_all_computers(headers, batch=50):
    items, offset = [], 0
    while True:
        r = requests.get(
            f"{GLPI_URL}/apirest.php/Computer",
            headers=headers,
            params={"range": f"{offset}-{offset + batch - 1}"},
            timeout=30,
        )
        if r.status_code == 206 or r.status_code == 200:
            page = r.json()
            if not page:
                break
            items.extend(page)
            content_range = r.headers.get("Content-Range", "")
            total = int(content_range.split("/")[-1]) if "/" in content_range else len(items)
            if len(items) >= total:
                break
            offset += batch
        else:
            r.raise_for_status()
    return items

Le code 206 (Partial Content) est la réponse HTTP correcte de l’API GLPI quand une pagination est en cours. Beaucoup de scripts cassent en testant uniquement 200 et ignorent les pages suivantes — le bug se manifeste alors par un sous-comptage silencieux.

Ouvrir un ticket depuis un système externe (Alertmanager, Zabbix)

L’autre sens du dialogue — laisser un système externe créer un ticket dans GLPI — passe lui aussi par l’API REST. À ce jour GLPI 11 n’expose pas d’endpoint « webhook entrant » natif au sens où on l’entend chez Slack ou GitHub : c’est votre script de pont qui reçoit la notification émetteur, la traduit en payload GLPI et appelle POST /apirest.php/Ticket.

Le motif typique tient en quatre composants : un récepteur webhook (Nginx + petit service Python ou Node), une logique de mapping (alerte → champs GLPI), un appel API GLPI (avec User Token + App-Token), une journalisation locale pour rejouer si GLPI est temporairement indisponible.

Côté Prometheus Alertmanager, on pointe la webhook_configs.url vers ce service de pont :

receivers:
  - name: 'glpi-bridge'
    webhook_configs:
      - url: 'https://glpi-bridge.exemple.lan/alert'
        send_resolved: true
        http_config:
          tls_config:
            insecure_skip_verify: false

Le service glpi-bridge.exemple.lan reçoit le payload Alertmanager (JSON normalisé), extrait le titre, la sévérité et le résumé, puis enchaîne initSessionPOST /TicketkillSession avec le helper Python présenté plus haut. L’option send_resolved: true notifie le pont de la résolution automatique d’une alerte, ce qui peut clore le ticket associé sans intervention humaine via PUT /Ticket/<id> avec status=5 (Résolu) ou 6 (Clos).

Le même schéma s’applique pour Zabbix (média de type « Webhook » qui pousse vers le pont), Centreon, Grafana OnCall ou tout outil capable d’émettre un HTTP POST. Le pont reste petit (~50 lignes Python), versionnable, testable, et il évite d’exposer directement les tokens GLPI à des dizaines d’outils tiers.

Tester l’API avec Postman ou Insomnia

Avant d’industrialiser des appels, validez chaque endpoint dans un outil graphique. Postman propose même un « collection runner » qui chaîne initSession, plusieurs opérations, et killSession en une seule séquence reproductible.

Créez une collection « GLPI API » avec trois variables d’environnement ({{glpi_url}}, {{user_token}}, {{app_token}}) puis trois requêtes :

  1. « Init Session » — GET {{glpi_url}}/apirest.php/initSession avec les headers Authorization et App-Token. Script de test qui capture session_token dans la variable de collection
  2. « Create Ticket » — POST avec le body JSON. Utilise {{session_token}} de l’étape précédente
  3. « Kill Session » — GET {{glpi_url}}/apirest.php/killSession

Avec cette collection, le développeur d’une intégration valide en 30 secondes que ses paramètres fonctionnent, avant d’écrire la moindre ligne de code applicatif. Le gain de temps en phase d’intégration est significatif.

Versions de l’API et compatibilité

L’API REST GLPI est stable depuis la branche 9.4. La majorité des endpoints utilisés dans cet article fonctionnent à l’identique sur GLPI 10 et GLPI 11. Quelques nuances à connaître :

  • GLPI 11 a ajouté les endpoints /Form et /CustomAsset pour les nouveautés Native Custom Assets et Integrated Forms
  • GLPI 11 introduit OAuth 2.0 en version stable côté serveur. Le flux Client Credentials est utilisable pour le scope inventory (typiquement appelé par GLPI Agent ≥ 1.10). Pour les endpoints API généraux, un utilisateur réel doit toujours être authentifié — l’OAuth 2.0 ne remplace donc pas l’User Token pour toutes les intégrations
  • Le webhook sortant côté GLPI utilise un payload différent selon la version : prévoir un mapping configurable côté consommateur pour ne pas réécrire le code à chaque montée de version

Pour les intégrations à fort impact, isolez le client GLPI dans un module ou un microservice dédié plutôt que d’éparpiller les appels dans tout le code applicatif. Une montée de version de l’API se répare alors en un endroit unique.

Service ITSkillsCenter

Application mobile Android et iOS

Création d'application mobile Android et iOS. À partir de 350 000 FCFA.

Démarrer mon projet
Publicité