glpi-rest
A modern, fully typed Python client for the GLPI REST API — with automatic session recovery.
Integration-tested against live GLPI 10 and GLPI 11 servers.
Why another GLPI client?
The GLPI REST API works, but using it from Python is unpleasant: search criteria must be
hand-serialized into criteria[0][field]-style parameters, responses are untyped
dictionaries, and sessions silently expire — leaving your automation to crash with a
401 at 3 a.m.
The landscape, checked against PyPI and GitHub in September 2026:
| Package | Last release | Typed | Recovers an expired session |
|---|---|---|---|
glpi_py (Grupo Parawa) |
0.4.2, Mar 2026 | partial | ❌ see note |
python-glpi-api (unistra) |
0.7.0, Mar 2025 | ❌ | ❌ |
mcphargus/python-glpi |
2018 | ❌ | ❌ |
AnatomicJC/glpi-client |
2017 | ❌ | ❌ |
glpi-rest |
active | ✅ strict | ✅ |
glpi_py is the one worth knowing about: recent, actively maintained, and it
covers more item types than this package does — documents, SLAs, entities,
categories. If you need that breadth, use it.
It also implements session recovery, in a request decorator that catches an
Unauthorized exception and retries the call. That exception is documented as
"Raised if a request produces a 401 error" — but the code that raises it
checks for 403:
# glpi_py/connection.py, v0.4.2 — abridged
class Unauthorized(Exception):
# docstring says: raised if a request produces a 401 error
...
class _Session(Session):
def request(self, *args, **kwargs):
response = super().request(*args, **kwargs)
if response.status_code == 403: # 401 never reaches the handler
raise Unauthorized
return response
GLPI answers 401 ERROR_SESSION_TOKEN_INVALID when a session expires, so the
retry never fires for the case it was written for. Measured on v0.4.2 against a
mocked server returning 401 then 200: the caller receives the raw 401 and no
re-authentication is attempted. The identical scenario against this package
returns the ticket.
Two smaller things found while testing v0.4.2: typing_extensions, arrow and
leopards are imported but not declared as dependencies, so a clean install
fails on import; and item URLs are built with a double slash
(apirest.php/Ticket//42).
These are fixable bugs, not design flaws, and they may already be fixed by the time you read this — verify before relying on the comparison.
Installation
pip install glpi-rest
Quickstart
from glpi_rest import GLPIClient, SearchCriterion
with GLPIClient(
"https://glpi.example.com/apirest.php",
app_token="your-app-token",
user_token="your-user-token",
) as glpi:
# Fetch one item
ticket = glpi.get_item("Ticket", 42)
print(ticket["name"])
# List items
for computer in glpi.get_items("Computer", range="0-19"):
print(computer["name"])
# Multi-criteria search — no manual parameter juggling
result = glpi.search(
"Ticket",
criteria=[
SearchCriterion(field=12, value=1, searchtype="equals"), # status = new
],
)
print(f"{result.total_count} matching tickets")
# Create, update, delete
created = glpi.add_item(
"Ticket", {"name": "Printer offline", "content": "3rd floor"}
)
glpi.update_item("Ticket", created["id"], {"priority": 4})
glpi.delete_item("Ticket", created["id"])
The session is opened on with and always closed on exit — even if your code raises.
Authentication
Either a user token (recommended) or username/password:
GLPIClient(url, app_token=..., user_token=...) # recommended
GLPIClient(url, app_token=..., username=..., password=...) # basic auth
Features
- Automatic session recovery. GLPI expires idle sessions. When a call returns
401,glpi-resttransparently re-authenticates and replays the exact same request — once. Your code never sees the interruption, and a bad credential can never cause a retry loop. - Strict typing throughout. Ships a
py.typedmarker; your IDE autocompletes methods andmypy --strictpasses. Typos are caught before runtime instead of in production. - Readable search.
SearchCriterionobjects replace hand-builtcriteria[0][searchtype]parameter soup, and results come back as a typedSearchResultwithtotal_count,countanddata. - Typed exceptions.
GLPIAuthError,GLPINotFoundError,GLPISessionError— catch what you actually care about instead of parsing error strings. - Secure by default. TLS verification on, request timeouts set, credentials sent as headers (never in URLs, which end up in server logs).
- No dependencies beyond
requests.
Architecture
graph TB
subgraph APP["Your application"]
SCRIPT["Automation script<br/>or business application"]
end
subgraph LIB["glpi-rest"]
CLIENT["<b>GLPIClient</b><br/>single entry point"]
subgraph INTERNAL["Internal layer"]
SESSION["<b>Session</b><br/>init · kill · auto-reconnect"]
HTTP["<b>_request()</b><br/>headers · timeout · TLS<br/>401 detection → replay"]
ERR["<b>Typed exceptions</b><br/>AuthError · NotFoundError<br/>SessionError"]
end
subgraph API["Public interface"]
CRUD["<b>CRUD</b><br/>get · add · update · delete"]
SEARCH["<b>Search</b><br/>serialized multi-criteria"]
MODELS["<b>Typed models</b><br/>SearchCriterion<br/>SearchResult"]
end
end
subgraph SRV["GLPI server (self-hosted)"]
REST["apirest.php<br/>GLPI 10 · GLPI 11"]
DB[("Database<br/>tickets · assets · users")]
end
SCRIPT -->|"import glpi_rest"| CLIENT
CLIENT --> CRUD
CLIENT --> SEARCH
CRUD --> HTTP
SEARCH --> MODELS
MODELS --> HTTP
CLIENT --> SESSION
SESSION --> HTTP
HTTP -->|"HTTPS + tokens"| REST
HTTP -.->|"on error"| ERR
ERR -.->|"clear exception"| SCRIPT
REST --> DB
style LIB fill:#e8f0fe,stroke:#1a73e8,stroke-width:2px
style SRV fill:#fef7e0,stroke:#f9ab00,stroke-width:2px
style APP fill:#e6f4ea,stroke:#1e8e3e,stroke-width:2px
style CLIENT fill:#1a73e8,color:#fff
How automatic reconnection works
sequenceDiagram
participant U as Your script
participant C as GLPIClient
participant G as GLPI server
U->>C: glpi.get_item("Ticket", 42)
C->>G: GET /Ticket/42 (Session-Token: tok-1)
G-->>C: 401 — session expired
Note over C: Detected automatically.<br/>Your script is not interrupted.
C->>G: GET /initSession
G-->>C: new token (tok-2)
C->>G: GET /Ticket/42 (Session-Token: tok-2)
G-->>C: 200 — ticket data
C-->>U: {"id": 42, ...}
Note over U,G: Replayed only once. If the retry<br/>fails, a clear exception is raised.<br/>Never an infinite loop.
Enabling the GLPI API
In your GLPI instance, as a super-admin:
- Setup → General → API — enable Enable Rest API.
- Add an API client and copy its App token.
- For a user token: Administration → Users → <your user> → Settings, then Regenerate under API token.
Use a dedicated GLPI account with only the rights your automation needs — not a super-admin account.
Security
glpi-rest talks only to the GLPI server you point it at. It collects no telemetry, contacts
no third party, and stores nothing on disk. Everything it does is auditable in this
repository.
Defaults are set for production use: TLS certificate verification is on, every request carries a timeout, tokens travel in headers rather than URLs, and sessions are closed deterministically.
Never commit tokens to source control — pass them via environment variables.
To report a vulnerability, please see SECURITY.md.
Compatibility
| Supported | Verified by | |
|---|---|---|
| GLPI 11.x | ✅ | full integration suite against live 11.0.2 and 11.0.8 |
| GLPI 10.x | ✅ | full integration suite against a live 10.0.26 |
| Python 3.10 – 3.13 | ✅ | unit suite on every version |
| Linux · macOS · Windows | ✅ | pure-Python, requests only |
Running the integration tests
The unit suite needs no server. To exercise the client against a real GLPI:
docker compose -f docker-compose.test.yml up -d
./scripts/enable-api.sh glpi11 db11 8011 # prints the env to export
pytest tests/test_integration.py -v
The stack brings up GLPI 10 and GLPI 11 side by side on ports 8010 and 8011, each with its own throwaway database.
Contributing
Contributions are welcome — see CONTRIBUTING.md.
git clone https://github.com/novagiosAI/glpi-rest.git
cd glpi-rest
python -m venv .venv && source .venv/bin/activate # Windows: .venv\Scripts\activate
pip install -e ".[dev]"
pytest
Tests run against a mocked GLPI API, so no server is required.
License
Apache License 2.0 — free for commercial use.
Built and maintained by Novagios — IT services, AI and ITSM.
Metadata
Release files for glpi-rest 0.1.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| glpi_rest-0.1.0.tar.gz | 23.4 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| glpi_rest-0.1.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 37.6 kB
Release files / glpi_rest-0.1.0.tar.gz
| Download URL | glpi_rest-0.1.0.tar.gz |
|---|---|
| Size | 23.4 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
336fb4de4f287410972290dd973f890f0c30999c71c825cf9f1e421aa22c319b
|
|
BLAKE2b-256 checksum How to use checksums |
7b1717b3c9f94cdb98fd028457e8d4419ee6a2218ee9587af09fe89140fab7c6
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 11, 2026.
Transparency logRelease files / glpi_rest-0.1.0-py3-none-any.whl
| Download URL | glpi_rest-0.1.0-py3-none-any.whl |
|---|---|
| Size | 14.2 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
df6fec421cdce8457423a70330d45eb93b54d3d97f43c4ce782cd1aa96f68512
|
|
BLAKE2b-256 checksum How to use checksums |
35219a62f15092512e80962d18597a782463e83a507d9aa0afe7d08b844f6ce5
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 11, 2026.
Transparency log