API
Les projets et les jetons de sauvegarde se gèrent non seulement dans le portail,
mais aussi via une API HTTP — pour votre propre automatisation ou avec le
fournisseur Terraform. L'API parle JSON, se trouve à
https://api.lionbackup.cloud/api/v1 et applique exactement le même contrôle
des droits que le portail.
Créer une clé
Dans le portail, sous Développeurs, vous créez un compte de service et une clé d'API associée. La clé n'est affichée qu'une seule fois — conservez-la en lieu sûr.
Un compte de service possède exactement les droits de la personne à qui il appartient. Qui ne peut pas créer de projets dans le portail ne le peut pas davantage via l'API ; si le compte est désactivé ou la clé supprimée, l'accès est fermé immédiatement.
Échanger la clé contre un jeton d'accès
La clé n'est pas un jeton bearer : vous l'échangez d'abord contre un jeton d'accès de courte durée (un JWT, valable 15 minutes).
ACCESS_TOKEN=$(curl -s https://authentik.prod.lionbackup.cloud/application/o/token/ \
-d grant_type=client_credentials \
-d client_id=lionbackup-api \
-d client_secret="$LIONBACKUP_API_KEY" \
-d scope="profile lionbackup_api" | jq -r .access_token)
Utilisez toujours l'hôte authentik.prod.lionbackup.cloud pour l'échange : le
nom court authentik.lionbackup.cloud répond par une redirection, et un POST
ne suit pas une redirection — l'appel ne renvoie alors aucun jeton.
Vous envoyez ensuite le jeton dans l'en-tête Authorization :
API=https://api.lionbackup.cloud/api/v1
curl -s "$API/organizations" -H "Authorization: Bearer $ACCESS_TOKEN"
Pour l'environnement de développement, utilisez
https://api.dev.lionbackup.cloud/api/v1 et
https://authentik.dev.lionbackup.cloud/application/o/token/. Une clé n'est
valable que dans l'environnement où elle a été créée.
Pas à pas : créer un projet et un jeton de sauvegarde
Les appels suivants s'enchaînent et supposent ACCESS_TOKEN et API de la
section précédente. Les identifiants dans les réponses sont des exemples.
1. Interroger les zones
Un projet a besoin de l'identifiant (UUID) de la zone dans laquelle ses
données seront stockées. Seules les zones avec status = active peuvent
être réservées.
curl -s "$API/zones" -H "Authorization: Bearer $ACCESS_TOKEN"
{
"zones": [
{
"id": "3f0c2a4e-8b1d-4c6a-9e2f-5d7b1a9c0e31",
"name": "de01-1",
"status": "active",
"provider": "Hetzner",
"location_city": "Nürnberg",
"storage_type": "managed object storage"
},
{
"id": "7a9d4b2c-1e5f-4a83-b6c0-2f8e9d1c4a57",
"name": "de01-2",
"status": "preparing",
"provider": "Hetzner",
"location_city": "Falkenstein",
"storage_type": "managed object storage"
}
]
}
L'identifiant de la zone souhaitée peut être placé directement dans une variable :
ZONE_ID=$(curl -s "$API/zones" -H "Authorization: Bearer $ACCESS_TOKEN" \
| jq -r '.zones[] | select(.name == "de01-1") | .id')
2. Déterminer l'organisation
Les projets appartiennent à une organisation. La liste montre chaque
organisation dont vous êtes membre, avec votre rôle — owner et admin
peuvent créer des projets.
curl -s "$API/organizations" -H "Authorization: Bearer $ACCESS_TOKEN"
{
"organizations": [
{
"id": "9b2e6c1a-4d3f-4e8b-a7c5-0f1d2e3a4b5c",
"name": "Example Ltd",
"status": "approved",
"role": "owner"
}
]
}
ORG_ID=$(curl -s "$API/organizations" -H "Authorization: Bearer $ACCESS_TOKEN" \
| jq -r '.organizations[] | select(.name == "Example Ltd") | .id')
Le choix par nom est volontaire : le compte de service voit toutes les organisations de son propriétaire et l'ordre de la liste n'est pas garanti.
3. Créer le projet
Les champs obligatoires sont name (100 caractères au maximum) et
availability_zone_id. Sont facultatifs alert_email, billing_reference,
immutable_storage (par défaut false) et — uniquement pour le stockage
immuable — retention_days (1 à 365, par défaut 30).
curl -s -X POST "$API/organizations/$ORG_ID/projects" \
-H "Authorization: Bearer $ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d "{\"name\":\"web-servers\",\"availability_zone_id\":\"$ZONE_ID\",\"alert_email\":\"ops@example.com\"}"
Réponse avec le statut 201 :
{
"project": {
"id": "ea1296ad-5c7b-4f2e-8a1d-3b6c9e0f7d24",
"name": "web-servers",
"status": "active",
"organization_id": "9b2e6c1a-4d3f-4e8b-a7c5-0f1d2e3a4b5c",
"availability_zone_id": "3f0c2a4e-8b1d-4c6a-9e2f-5d7b1a9c0e31",
"alert_email": "ops@example.com",
"billing_reference": null,
"immutable_storage": false,
"retention_days": null,
"created_at": "2026-09-24 09:41:12.418273"
}
}
PROJECT_ID=ea1296ad-5c7b-4f2e-8a1d-3b6c9e0f7d24
4. Créer un jeton de sauvegarde
Un jeton de sauvegarde appartient à exactement un projet. Avec type =
write, le client sauvegarde ; avec type = read, il restaure. Sans
indication, un jeton d'écriture pour Linux est créé ; operating_system
connaît Linux, Windows et macOS. En option, usage_count_limit,
rate_limit_per_minute et rate_limit_per_hour limitent l'utilisation.
curl -s -X POST "$API/projects/$PROJECT_ID/tokens" \
-H "Authorization: Bearer $ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{"type":"write","operating_system":"Linux"}'
Réponse avec le statut 201 :
{
"token": {
"id": "c4d1e8f2-6a3b-4c9d-8e7f-1a2b3c4d5e6f",
"type": "write",
"secret": "9f3e7b1c…a41c"
}
}
secret est le véritable jeton de sauvegarde (128 caractères hexadécimaux).
Il n'est délivré qu'une seule fois et ne peut plus être récupéré par la suite —
la plateforme n'en conserve qu'un hachage. Déposez-le immédiatement dans votre
gestionnaire de secrets.
Un jeton de lecture pour les restaurations se crée de la même manière :
curl -s -X POST "$API/projects/$PROJECT_ID/tokens" \
-H "Authorization: Bearer $ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{"type":"read"}'
{
"token": {
"id": "5e6f7a8b-9c0d-4e1f-a2b3-c4d5e6f7a8b9",
"type": "read",
"secret": "d27c0a8e…5b93"
}
}
5. Lister les jetons
La liste ne contient que des métadonnées — jamais un secret. Les jetons révoqués n'y apparaissent plus.
curl -s "$API/projects/$PROJECT_ID/tokens" -H "Authorization: Bearer $ACCESS_TOKEN"
{
"tokens": [
{
"id": "5e6f7a8b-9c0d-4e1f-a2b3-c4d5e6f7a8b9",
"type": "read",
"operating_system": "Linux",
"is_active": true,
"usage_count": 0,
"usage_count_limit": null,
"created_at": "2026-09-24 09:43:05.102944",
"expire": null
},
{
"id": "c4d1e8f2-6a3b-4c9d-8e7f-1a2b3c4d5e6f",
"type": "write",
"operating_system": "Linux",
"is_active": true,
"usage_count": 0,
"usage_count_limit": null,
"created_at": "2026-09-24 09:42:37.556210",
"expire": null
}
]
}
6. Révoquer un jeton
TOKEN_ID=c4d1e8f2-6a3b-4c9d-8e7f-1a2b3c4d5e6f
curl -s -X DELETE "$API/projects/$PROJECT_ID/tokens/$TOKEN_ID" \
-H "Authorization: Bearer $ACCESS_TOKEN"
{ "deleted": true }
7. Fermer le projet
Un projet n'est pas supprimé mais fermé : le statut passe à closing, tous
les jetons d'écriture sont révoqués immédiatement, la réponse en indique le
nombre. L'appel est idempotent — un projet déjà fermé répond de nouveau 200.
curl -s -X POST "$API/projects/$PROJECT_ID/close" \
-H "Authorization: Bearer $ACCESS_TOKEN"
{
"project": {
"id": "ea1296ad-5c7b-4f2e-8a1d-3b6c9e0f7d24",
"name": "web-servers",
"status": "closing",
"organization_id": "9b2e6c1a-4d3f-4e8b-a7c5-0f1d2e3a4b5c",
"availability_zone_id": "3f0c2a4e-8b1d-4c6a-9e2f-5d7b1a9c0e31",
"alert_email": "ops@example.com",
"billing_reference": null,
"immutable_storage": false,
"retention_days": null,
"created_at": "2026-09-24 09:41:12.418273"
},
"write_tokens_revoked": 1
}
Ce qu'il faut savoir
Droits par action
L'API vérifie les mêmes rôles que le portail :
| Action | Rôle |
|---|---|
| Lire un projet, lister les jetons | tout rôle dans le projet |
| Modifier un projet, créer un jeton | owner, admin, writer |
| Révoquer un jeton | owner, admin |
| Créer un projet, fermer un projet | owner ou admin de l'organisation |
404 au lieu de 403
Une ressource qui n'existe pas et une ressource sur laquelle vous n'avez aucun
rôle répondent de la même façon : 404 avec {"error":"not_found"}. L'API ne
révèle ainsi pas quels identifiants existent. Vous ne recevez un 403 avec
permission_denied que si vous êtes autorisé à voir la ressource, mais pas à
effectuer l'action.
La publication vers la zone est asynchrone
Un nouveau jeton est transmis à la Storage Zone après sa création. Tant que ce
n'est pas fait, la zone rejette le jeton avec 401 — en général quelques
secondes, en cas d'incident jusqu'à la prochaine synchronisation. Ne recréez
pas le jeton dans ce cas, mais réessayez plus tard. Inversement, un jeton
révoqué peut rester brièvement valable dans la zone.
Fermeture d'un projet
La fermeture révoque immédiatement tous les jetons d'écriture et fait passer le
projet à closing. Les jetons de lecture restent valables pendant la durée de
rétention et, tant qu'une sauvegarde est encore dans sa durée de rétention,
vous pouvez aussi créer de nouveaux jetons de lecture pour continuer à
restaurer les sauvegardes stockées. Un projet closing refuse les nouveaux
jetons d'écriture (409 project_closed) ; une fois closed, il n'accepte plus
aucun jeton. De même, une organisation fermée refuse les nouveaux projets (409 organization_closed).
Limites de débit
| Limite | Valeur | S'applique à |
|---|---|---|
| Requêtes par adresse IP | 60/minute | chaque requête vers l'API |
| Requêtes par compte de service | 60/minute | chaque requête authentifiée |
| Taille d'une requête | 1 Mo | le contenu envoyé |
Chaque réponse authentifiée porte X-RateLimit-Limit,
X-RateLimit-Remaining et X-RateLimit-Reset (heure Unix à laquelle la
fenêtre d'une minute en cours se termine). Au-delà de la limite, l'API répond
429 avec {"error":"rate_limited"} et l'en-tête Retry-After — attendez ce
nombre de secondes puis répétez la requête. Le fournisseur Terraform le fait de
lui-même.
Les en-têtes X-RateLimit-* peuvent manquer : si le cache de compteurs de la
plateforme tombe en panne, l'API ne compte temporairement plus par compte de
service et n'annonce alors aucun budget. Dans votre automatisation, fiez-vous
au statut 429 et à Retry-After, pas aux en-têtes.
Format des erreurs
Chaque erreur est un objet JSON avec exactement un champ : {"error":"<code>"}.
Le code est stable et destiné aux programmes ; basez vos branchements sur lui,
pas sur le seul statut HTTP.
| Statut | Code | Signification |
|---|---|---|
400 | invalid_request | le contenu n'est pas du JSON, un champ obligatoire manque ou une valeur est invalide |
400 | invalid_zone | availability_zone_id est inconnu ou la zone n'est pas active |
400 | retention_out_of_range | retention_days est en dehors de 1 à 365 |
401 | invalid_token | jeton d'accès absent, invalide ou expiré, compte de service supprimé |
403 | owner_inactive | la personne à qui appartient le compte de service est désactivée |
403 | permission_denied | votre rôle n'autorise pas cette action |
404 | not_found | ressource inconnue ou invisible pour vous |
405 | method_not_allowed | le chemin existe, pas la méthode HTTP |
409 | organization_closed | l'organisation est en cours de fermeture ou fermée |
409 | project_closed | le projet est closed, ou closing et un jeton d'écriture a été demandé |
429 | rate_limited | limite de débit — respecter Retry-After |
500 | internal_error | erreur inattendue sur la plateforme |
503 | service_unavailable | temporairement indisponible — réessayer plus tard |
Terraform
Pour Terraform et OpenTofu, il existe un fournisseur qui utilise la même API et gère les projets ainsi que les jetons de sauvegarde comme des ressources. Vous trouverez la source d'installation, la configuration et un exemple complet sur la page Terraform.
Référence
La spécification complète est disponible sous forme de document OpenAPI 3.1 :
openapi.yaml. L'API elle-même sert le même fichier
sur /api/v1/openapi.yaml — elle décrit donc toujours exactement la version en
cours d'exécution.
Loading the API reference…