7.3 KiB
Guide d'utilisation de l'API Imago
Bienvenue dans la documentation officielle de l'API REST d'Imago v2.0.0.
Note : Tous les endpoints sont servis sous le préfixe /api/v1/.
Sommaire
- Authentification
- Scopes (Permissions)
- Plans et Rate Limiting
- Multi-tenancy et Isolation
- Gestion des Clients (Admin)
- Référence des Endpoints
- Exemples Rapides
Authentification
Tous les endpoints (sauf /health, /, /metrics) nécessitent une clé API.
Authorization: Bearer VOTRE_CLE_API
Ou via le header alternatif : X-API-Key: VOTRE_CLE_API
La clé API est hashée en SHA-256 + pepper (SECRET_KEY) avant stockage. Les comparaisons sont timing-safe.
Clé Master Admin
Définie par ADMIN_API_KEY dans .env. Cette clé spéciale a tous les droits sans être en base de données.
Scopes (Permissions)
| Scope | Accès |
|---|---|
images:read |
Lister, voir détails, EXIF, OCR, AI, tags |
images:write |
Uploader, relancer le pipeline |
images:delete |
Supprimer des images |
ai:use |
Résumé d'URL, rédaction de tâches |
admin |
Gérer clients, voir stats, DLQ, docs |
Les scopes sont validés à la création du client — les valeurs invalides sont rejetées.
Plans et Rate Limiting
Les limites sont dynamiques par plan et isolées par client. Support Redis pour la persistence.
| Plan | Uploads/h | AI req/h |
|---|---|---|
free |
20 | 50 |
standard |
100 | 200 |
premium |
500 | 1000 |
Config : `RATE_LIMIT_STORAGE_URL=redis://redis:***@## Gestion des Clients (Admin)
# Créer un client
curl -X POST http://localhost:8000/api/v1/auth/clients \
-H "Authorization: Bearer *** \
-H "Content-Type: application/json" \
-d '{"name":"App Mobile","scopes":["images:read","images:write","ai:use"],"plan":"standard"}'
# Rotation de clé
curl -X POST http://localhost:8000/api/v1/auth/clients/{id}/rotate-key \
-H "Authorization: Bearer ***
La clé API n'est affichée qu'une seule fois à la création. Stockez-la immédiatement.
Multi-tenancy et Isolation
- Chaque client voit uniquement ses propres images (filtrage
WHERE client_id = X) - Les IDs sont globaux mais l'accès est vérifié → un client B qui tente l'ID du client A reçoit
404 - Fichiers stockés dans
uploads/{client_id}/etthumbnails/{client_id}/
Reference des Endpoints
Gestion des Images
| Méthode | Endpoint | Scope | Description |
|---|---|---|---|
POST |
/api/v1/images/upload |
images:write |
Upload (multipart) + lancement pipeline AI |
GET |
/api/v1/images |
images:read |
Lister (pagination, filtres tag/status/search) |
GET |
/api/v1/images/{id} |
images:read |
Détail complet (EXIF + OCR + AI) |
GET |
/api/v1/images/{id}/status |
images:read |
Statut du pipeline (pending→done/error) |
GET |
/api/v1/images/{id}/exif |
images:read |
Métadonnées EXIF + GPS |
GET |
/api/v1/images/{id}/ocr |
images:read |
Texte extrait par OCR |
GET |
/api/v1/images/{id}/ai |
images:read |
Description AI + tags + tokens consommés |
POST |
/api/v1/images/{id}/reprocess |
images:write |
Relancer le pipeline AI |
DELETE |
/api/v1/images/{id} |
images:delete |
Supprimer image + fichiers |
GET |
/api/v1/images/{id}/download-url |
images:read |
URL signée temporaire (fichier original) |
GET |
/api/v1/images/{id}/thumbnail-url |
images:read |
URL signée temporaire (thumbnail) |
GET |
/api/v1/images/tags/all |
images:read |
Tous les tags uniques du client |
Recherche : GET /api/v1/images?search=motcle&tag=nature&status=done&page=1&page_size=20
Intelligence Artificielle
| Méthode | Endpoint | Scope | Description |
|---|---|---|---|
POST |
/api/v1/ai/summarize |
ai:use |
Résumé AI d'une URL (scraping + résumé + tags) |
POST |
/api/v1/ai/draft-task |
ai:use |
Génération de tâche structurée |
L'AI utilise le provider configuré (Gemini ou OpenRouter) avec circuit breaker : timeout configurable (AI_REQUEST_TIMEOUT) et retry exponentiel (AI_MAX_RETRIES).
Administration (Admin)
| Méthode | Endpoint | Description |
|---|---|---|
GET |
/admin/api/stats |
Stats globales (images, stockage, tokens, clients) |
GET |
/admin/api/clients |
Liste des clients |
POST |
/admin/api/clients/{id}/toggle |
Activer/désactiver un client |
POST |
/admin/api/clients/{id}/reset-quota |
Remettre le quota à zéro |
GET |
/admin/api/queue/status |
File d'attente ARQ (pending + dead jobs) |
GET |
/admin/api/docs |
Liste des documents disponibles |
GET |
/admin/api/docs/{filename} |
Contenu d'un document |
POST |
/api/v1/auth/clients |
Créer un client (retourne la clé) |
GET |
/api/v1/auth/clients |
Lister tous les clients |
PATCH |
/api/v1/auth/clients/{id} |
Modifier un client |
DELETE |
/api/v1/auth/clients/{id} |
Désactiver un client |
Dead Letter Queue (Admin)
Jobs échoués après PIPELINE_MAX_RETRIES tentatives.
| Méthode | Endpoint | Description |
|---|---|---|
GET |
/admin/api/queue/dead?limit=50 |
Lister les jobs morts |
POST |
/admin/api/queue/dead/{index}/retry |
Relancer un job mort |
DELETE |
/admin/api/queue/dead |
Vider la DLQ |
Santé et Status
Endpoints publics (pas d'authentification).
| Méthode | Endpoint | Description |
|---|---|---|
GET |
/ |
Version et statut |
GET |
/health |
Santé (AI, OCR, provider) |
GET |
/health/detailed |
Diagnostic complet (BDD, Redis, ARQ, MinIO, OCR, AI, worker) |
GET |
/metrics |
Métriques Prometheus |
WebSocket (Temps Réel)
| Endpoint | Auth | Description |
|---|---|---|
ws://host/ws/pipeline/{image_id}?token=API_KEY |
API Key | Événements live du pipeline + buffer 60s |
ws://host/ws/admin/monitor?token=ADMIN_KEY |
Admin | Monitoring global de tous les pipelines |
Exemples Rapides
Upload + suivi pipeline (Python)
import httpx, asyncio, websockets, json
API = "http://localhost:8000"
KEY = "ma_cle_api"
headers = {"Authorization": f"Bearer {KEY}"}
async def main():
# Upload
files = {"file": open("photo.jpg", "rb")}
r = httpx.post(f"{API}/api/v1/images/upload", files=files, headers=headers)
img = r.json()
print(f"Uploaded: {img['id']}")
# Suivi WebSocket du pipeline
async with websockets.connect(
f"ws://localhost:8000/ws/pipeline/{img['id']}?token={KEY}"
) as ws:
async for msg in ws:
event = json.loads(msg)
print(f"Pipeline: {event['event']}")
if event["event"] in ("pipeline.done", "pipeline.error"):
break
# Résultat final
detail = httpx.get(f"{API}/api/v1/images/{img['id']}/ai", headers=headers).json()
print(f"Description: {detail['description']}")
print(f"Tags: {detail['tags']}")
asyncio.run(main())