Aller au contenu principal
QualiForma
CatalogueDevenir formateurQualiopiIADéveloppeurs
Connexion
  • Catalogue
  • Devenir formateur
  • Qualiopi
  • IA
  • Développeurs
  • Connexion
  • Vue d'ensemble

Démarrage

  • Quickstart
  • Authentification

Référence

  • API Reference (Scalar)

Endpoints

  • Tous les endpoints

Cœur LMS

  • Tenants
  • Utilisateurs
  • Formations
  • Inscriptions
  • Sessions live

Conformité Qualiopi

  • Dashboard Qualiopi
  • Conformité
  • Émargement
  • Questionnaires
  • Réclamations
  • Plans d'amélioration
  • Parcours adaptatifs
  • Compétences formateurs
  • BPF
  • Médiateurs

Paiements & Facturation

  • Paiements
  • Facturation Factur-X
  • Webhooks

Design System

  • Vue d'ensemble
  • Couleurs
  • Typographie
  • Espacement
  • Elevation
  • Motion
  • Radius
  • Composants
  • · Formulaires
  • · Feedback
  • · Navigation
  • · Progression
  • · Données
Swagger UI (s'ouvre dans un nouvel onglet)
  1. Développeurs
  2. Endpoints
  3. Tenants

Tenants

QualiForma est une plateforme multi-tenant. Chaque organisation cliente (organisme de formation, cabinet RH, école) dispose de son propre espace isolé : utilisateurs, formations, factures, statistiques Qualiopi.

Résolution du tenant — règle critique

Toute requête API standard doit inclure le header X-Tenant-ID avec le slug du tenant (par exemple qualiforma-demo). Les endpoints sous /admin/* font exception : ils opèrent en cross-tenant et requièrent un JWT super-administrateur.

Endpoints

get/api/v1/tenants/current

Tenant courant

Retourne le tenant résolu via le header X-Tenant-ID. Endpoint utile pour récupérer la configuration de branding, le plan tarifaire et les feature flags activés.

  • Tenants

Réponses

  • 200Tenant courant résolu
    Réponse 200 · JSON
    {
      "data": {
        "id": "tnt_8f3b1c20-4d5e-4a9b-9c20-2c5d8e7f0a1b",
        "slug": "qualiforma-demo",
        "name": "QualiForma Demo",
        "plan": "PRO",
        "status": "ACTIVE",
        "branding": {
          "primaryColor": "#6366f1",
          "logoUrl": "https://cdn.qualiforma.site/tenants/demo/logo.svg"
        },
        "features": [
          "LIVE_SESSIONS",
          "AI_COPILOT",
          "QUALIOPI_AUDIT"
        ],
        "createdAt": "2025-09-12T08:30:00.000Z"
      }
    }
  • 401Token JWT manquant ou expiré
    Réponse 401 · JSON
    {
      "statusCode": 401,
      "message": "Unauthorized"
    }
  • 404Header X-Tenant-ID absent ou tenant introuvable
    Réponse 404 · JSON
    {
      "statusCode": 404,
      "message": "Tenant not found"
    }

Exemples

GET /api/v1/tenants/current · cURL / Shell
curl -X GET https://api.qualiforma.site/api/v1/tenants/current \
  -H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
  -H "X-Tenant-ID: qualiforma-demo"
GET /api/v1/tenants/current · JavaScript
const response = await fetch('https://api.qualiforma.site/api/v1/tenants/current', {
  method: 'GET',
  headers: {
    'Authorization': 'Bearer YOUR_ACCESS_TOKEN',
    'X-Tenant-ID': 'qualiforma-demo',
  },
});

if (!response.ok) {
  throw new Error(`HTTP ${response.status}: ${await response.text()}`);
}

const data = await response.json();
console.log(data);
GET /api/v1/tenants/current · Python
import requests

response = requests.get(
    'https://api.qualiforma.site/api/v1/tenants/current',
    headers={
        'Authorization': 'Bearer YOUR_ACCESS_TOKEN',
        'X-Tenant-ID': 'qualiforma-demo',
    },
    timeout=30,
)
response.raise_for_status()
data = response.json()
print(data)
GET /api/v1/tenants/current · PHP
<?php

use GuzzleHttp\Client;
use GuzzleHttp\Exception\GuzzleException;

$client = new Client(['base_uri' => 'https://api.qualiforma.site/api/v1/']);

try {
    $response = $client->get('tenants/current', [
        'headers' => [
            'Authorization' => 'Bearer YOUR_ACCESS_TOKEN',
            'X-Tenant-ID' => 'qualiforma-demo',
        ],
    ]);
    $data = json_decode($response->getBody()->getContents(), true);
    var_dump($data);
} catch (GuzzleException $e) {
    fwrite(STDERR, $e->getMessage());
}
get/api/v1/admin/tenants

Lister tous les tenants (super-admin)

Endpoint cross-tenant réservé aux super-administrateurs de la plateforme. Retourne la liste paginée de tous les tenants avec leurs métriques agrégées (nombre d'utilisateurs, formations actives, MRR).

  • Tenants
  • Admin

Paramètres

NomTypeRequisExempleDescription
pagequerynon1Numéro de page (défaut 1)
limitquerynon25Nombre par page (max 100)
statusquerynonACTIVEFiltre par statut : ACTIVE, SUSPENDED, ARCHIVED
planquerynonPROFiltre par plan : STARTER, PRO, ENTERPRISE
qquerynonacmeRecherche plein texte sur nom ou slug

Réponses

  • 200Liste paginée des tenants
    Réponse 200 · JSON
    {
      "data": [
        {
          "id": "tnt_8f3b1c20-4d5e-4a9b-9c20-2c5d8e7f0a1b",
          "slug": "acme-formation",
          "name": "ACME Formation",
          "plan": "ENTERPRISE",
          "status": "ACTIVE",
          "usersCount": 142,
          "coursesCount": 38,
          "createdAt": "2025-04-12T10:14:23.000Z"
        },
        {
          "id": "tnt_b2c3d4e5-f6a7-4b8c-9d0e-1f2a3b4c5d6e",
          "slug": "cabinet-rh-plus",
          "name": "Cabinet RH Plus",
          "plan": "PRO",
          "status": "ACTIVE",
          "usersCount": 28,
          "coursesCount": 12,
          "createdAt": "2025-11-03T15:42:00.000Z"
        }
      ],
      "meta": {
        "total": 47,
        "page": 1,
        "limit": 25,
        "totalPages": 2
      }
    }
  • 403Rôle super-admin requis
    Réponse 403 · JSON
    {
      "statusCode": 403,
      "message": "Forbidden — super-admin required"
    }

Exemples

GET /api/v1/admin/tenants · cURL / Shell
curl -X GET https://api.qualiforma.site/api/v1/admin/tenants?page=1&limit=25&status=ACTIVE&plan=PRO&q=acme \
  -H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
  -H "X-Tenant-ID: qualiforma-demo"
GET /api/v1/admin/tenants · JavaScript
const response = await fetch('https://api.qualiforma.site/api/v1/admin/tenants?page=1&limit=25&status=ACTIVE&plan=PRO&q=acme', {
  method: 'GET',
  headers: {
    'Authorization': 'Bearer YOUR_ACCESS_TOKEN',
    'X-Tenant-ID': 'qualiforma-demo',
  },
});

if (!response.ok) {
  throw new Error(`HTTP ${response.status}: ${await response.text()}`);
}

const data = await response.json();
console.log(data);
GET /api/v1/admin/tenants · Python
import requests

response = requests.get(
    'https://api.qualiforma.site/api/v1/admin/tenants?page=1&limit=25&status=ACTIVE&plan=PRO&q=acme',
    headers={
        'Authorization': 'Bearer YOUR_ACCESS_TOKEN',
        'X-Tenant-ID': 'qualiforma-demo',
    },
    timeout=30,
)
response.raise_for_status()
data = response.json()
print(data)
GET /api/v1/admin/tenants · PHP
<?php

use GuzzleHttp\Client;
use GuzzleHttp\Exception\GuzzleException;

$client = new Client(['base_uri' => 'https://api.qualiforma.site/api/v1/']);

try {
    $response = $client->get('admin/tenants?page=1&limit=25&status=ACTIVE&plan=PRO&q=acme', [
        'headers' => [
            'Authorization' => 'Bearer YOUR_ACCESS_TOKEN',
            'X-Tenant-ID' => 'qualiforma-demo',
        ],
    ]);
    $data = json_decode($response->getBody()->getContents(), true);
    var_dump($data);
} catch (GuzzleException $e) {
    fwrite(STDERR, $e->getMessage());
}
post/api/v1/admin/tenants

Créer un tenant (super-admin)

Provisionne un nouveau tenant avec son administrateur initial. Le slug doit être unique et URL-safe (kebab-case). Le mot de passe administrateur doit respecter les règles de complexité (min. 12 caractères, mixte).

  • Tenants
  • Admin

Corps de requête

Content-Type : application/json

Body · JSON
{
  "name": "ACME Formation",
  "slug": "acme-formation",
  "plan": "PRO",
  "adminEmail": "admin@acme-formation.fr",
  "adminPassword": "Bootstrap2026!Strong",
  "adminFirstName": "Sophie",
  "adminLastName": "Durand",
  "branding": {
    "primaryColor": "#0ea5e9",
    "logoUrl": "https://cdn.acme-formation.fr/logo.svg"
  }
}

Réponses

  • 201Tenant créé avec son administrateur
    Réponse 201 · JSON
    {
      "data": {
        "id": "tnt_c4d5e6f7-a8b9-4c0d-1e2f-3a4b5c6d7e8f",
        "slug": "acme-formation",
        "name": "ACME Formation",
        "plan": "PRO",
        "status": "ACTIVE",
        "adminUserId": "usr_a1b2c3d4-e5f6-7890-abcd-ef1234567890",
        "createdAt": "2026-05-15T09:00:00.000Z"
      }
    }
  • 409Slug déjà utilisé
    Réponse 409 · JSON
    {
      "statusCode": 409,
      "message": "Slug already exists"
    }
  • 422Validation échouée
    Réponse 422 · JSON
    {
      "statusCode": 422,
      "message": "Validation failed",
      "errors": {
        "slug": [
          "Slug must match /^[a-z0-9-]+$/"
        ],
        "adminPassword": [
          "Password must be at least 12 characters"
        ]
      }
    }

Exemples

POST /api/v1/admin/tenants · cURL / Shell
curl -X POST https://api.qualiforma.site/api/v1/admin/tenants \
  -H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
  -H "X-Tenant-ID: qualiforma-demo" \
  -H "Content-Type: application/json" \
  -d '{
  "name": "ACME Formation",
  "slug": "acme-formation",
  "plan": "PRO",
  "adminEmail": "admin@acme-formation.fr",
  "adminPassword": "Bootstrap2026!Strong",
  "adminFirstName": "Sophie",
  "adminLastName": "Durand",
  "branding": {
    "primaryColor": "#0ea5e9",
    "logoUrl": "https://cdn.acme-formation.fr/logo.svg"
  }
}'
POST /api/v1/admin/tenants · JavaScript
const response = await fetch('https://api.qualiforma.site/api/v1/admin/tenants', {
  method: 'POST',
  headers: {
    'Authorization': 'Bearer YOUR_ACCESS_TOKEN',
    'X-Tenant-ID': 'qualiforma-demo',
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    "name": "ACME Formation",
    "slug": "acme-formation",
    "plan": "PRO",
    "adminEmail": "admin@acme-formation.fr",
    "adminPassword": "Bootstrap2026!Strong",
    "adminFirstName": "Sophie",
    "adminLastName": "Durand",
    "branding": {
      "primaryColor": "#0ea5e9",
      "logoUrl": "https://cdn.acme-formation.fr/logo.svg"
    }
  }),
});

if (!response.ok) {
  throw new Error(`HTTP ${response.status}: ${await response.text()}`);
}

const data = await response.json();
console.log(data);
POST /api/v1/admin/tenants · Python
import requests

response = requests.post(
    'https://api.qualiforma.site/api/v1/admin/tenants',
    headers={
        'Authorization': 'Bearer YOUR_ACCESS_TOKEN',
        'X-Tenant-ID': 'qualiforma-demo',
        'Content-Type': 'application/json',
    },
    json={
        'name': 'ACME Formation',
        'slug': 'acme-formation',
        'plan': 'PRO',
        'adminEmail': 'admin@acme-formation.fr',
        'adminPassword': 'Bootstrap2026!Strong',
        'adminFirstName': 'Sophie',
        'adminLastName': 'Durand',
        'branding': {
            'primaryColor': '#0ea5e9',
            'logoUrl': 'https://cdn.acme-formation.fr/logo.svg',
        },
    },
    timeout=30,
)
response.raise_for_status()
data = response.json()
print(data)
POST /api/v1/admin/tenants · PHP
<?php

use GuzzleHttp\Client;
use GuzzleHttp\Exception\GuzzleException;

$client = new Client(['base_uri' => 'https://api.qualiforma.site/api/v1/']);

try {
    $response = $client->post('admin/tenants', [
        'headers' => [
            'Authorization' => 'Bearer YOUR_ACCESS_TOKEN',
            'X-Tenant-ID' => 'qualiforma-demo',
        ],
        'json' => [
            'name' => 'ACME Formation',
            'slug' => 'acme-formation',
            'plan' => 'PRO',
            'adminEmail' => 'admin@acme-formation.fr',
            'adminPassword' => 'Bootstrap2026!Strong',
            'adminFirstName' => 'Sophie',
            'adminLastName' => 'Durand',
            'branding' => [
                'primaryColor' => '#0ea5e9',
                'logoUrl' => 'https://cdn.acme-formation.fr/logo.svg',
            ],
        ],
    ]);
    $data = json_decode($response->getBody()->getContents(), true);
    var_dump($data);
} catch (GuzzleException $e) {
    fwrite(STDERR, $e->getMessage());
}
patch/api/v1/admin/tenants/:id

Mettre à jour un tenant (super-admin)

Mise à jour partielle d'un tenant : changement de plan, suspension, modification du branding ou des feature flags. Le slug ne peut pas être modifié après création.

  • Tenants
  • Admin

Paramètres

NomTypeRequisExempleDescription
idpathouitnt_8f3b1c20-4d5e-4a9b-9c20-2c5d8e7f0a1bIdentifiant UUID du tenant

Corps de requête

Content-Type : application/json

Body · JSON
{
  "plan": "ENTERPRISE",
  "status": "ACTIVE",
  "features": [
    "LIVE_SESSIONS",
    "AI_COPILOT",
    "QUALIOPI_AUDIT",
    "SCORM_EXPORT"
  ],
  "branding": {
    "primaryColor": "#10b981"
  }
}

Réponses

  • 200Tenant mis à jour
    Réponse 200 · JSON
    {
      "data": {
        "id": "tnt_8f3b1c20-4d5e-4a9b-9c20-2c5d8e7f0a1b",
        "slug": "acme-formation",
        "name": "ACME Formation",
        "plan": "ENTERPRISE",
        "status": "ACTIVE",
        "updatedAt": "2026-05-15T09:15:00.000Z"
      }
    }
  • 404Tenant introuvable
    Réponse 404 · JSON
    {
      "statusCode": 404,
      "message": "Tenant not found"
    }

Exemples

PATCH /api/v1/admin/tenants/:id · cURL / Shell
curl -X PATCH https://api.qualiforma.site/api/v1/admin/tenants/tnt_8f3b1c20-4d5e-4a9b-9c20-2c5d8e7f0a1b \
  -H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
  -H "X-Tenant-ID: qualiforma-demo" \
  -H "Content-Type: application/json" \
  -d '{
  "plan": "ENTERPRISE",
  "status": "ACTIVE",
  "features": [
    "LIVE_SESSIONS",
    "AI_COPILOT",
    "QUALIOPI_AUDIT",
    "SCORM_EXPORT"
  ],
  "branding": {
    "primaryColor": "#10b981"
  }
}'
PATCH /api/v1/admin/tenants/:id · JavaScript
const response = await fetch('https://api.qualiforma.site/api/v1/admin/tenants/tnt_8f3b1c20-4d5e-4a9b-9c20-2c5d8e7f0a1b', {
  method: 'PATCH',
  headers: {
    'Authorization': 'Bearer YOUR_ACCESS_TOKEN',
    'X-Tenant-ID': 'qualiforma-demo',
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    "plan": "ENTERPRISE",
    "status": "ACTIVE",
    "features": [
      "LIVE_SESSIONS",
      "AI_COPILOT",
      "QUALIOPI_AUDIT",
      "SCORM_EXPORT"
    ],
    "branding": {
      "primaryColor": "#10b981"
    }
  }),
});

if (!response.ok) {
  throw new Error(`HTTP ${response.status}: ${await response.text()}`);
}

const data = await response.json();
console.log(data);
PATCH /api/v1/admin/tenants/:id · Python
import requests

response = requests.patch(
    'https://api.qualiforma.site/api/v1/admin/tenants/tnt_8f3b1c20-4d5e-4a9b-9c20-2c5d8e7f0a1b',
    headers={
        'Authorization': 'Bearer YOUR_ACCESS_TOKEN',
        'X-Tenant-ID': 'qualiforma-demo',
        'Content-Type': 'application/json',
    },
    json={
        'plan': 'ENTERPRISE',
        'status': 'ACTIVE',
        'features': [
            'LIVE_SESSIONS',
            'AI_COPILOT',
            'QUALIOPI_AUDIT',
            'SCORM_EXPORT',
        ],
        'branding': {
            'primaryColor': '#10b981',
        },
    },
    timeout=30,
)
response.raise_for_status()
data = response.json()
print(data)
PATCH /api/v1/admin/tenants/:id · PHP
<?php

use GuzzleHttp\Client;
use GuzzleHttp\Exception\GuzzleException;

$client = new Client(['base_uri' => 'https://api.qualiforma.site/api/v1/']);

try {
    $response = $client->patch('admin/tenants/tnt_8f3b1c20-4d5e-4a9b-9c20-2c5d8e7f0a1b', [
        'headers' => [
            'Authorization' => 'Bearer YOUR_ACCESS_TOKEN',
            'X-Tenant-ID' => 'qualiforma-demo',
        ],
        'json' => [
            'plan' => 'ENTERPRISE',
            'status' => 'ACTIVE',
            'features' => [
                'LIVE_SESSIONS',
                'AI_COPILOT',
                'QUALIOPI_AUDIT',
                'SCORM_EXPORT',
            ],
            'branding' => [
                'primaryColor' => '#10b981',
            ],
        ],
    ]);
    $data = json_decode($response->getBody()->getContents(), true);
    var_dump($data);
} catch (GuzzleException $e) {
    fwrite(STDERR, $e->getMessage());
}
delete/api/v1/admin/tenants/:id

Supprimer un tenant (soft delete)

Archive un tenant et coupe l'accès à toutes ses ressources. Les données sont conservées 90 jours pour permettre une restauration (purge RGPD automatique au-delà).

  • Tenants
  • Admin

Paramètres

NomTypeRequisExempleDescription
idpathouitnt_8f3b1c20-4d5e-4a9b-9c20-2c5d8e7f0a1bIdentifiant UUID du tenant

Réponses

  • 204Tenant archivé (aucun corps de réponse)
  • 404Tenant introuvable
    Réponse 404 · JSON
    {
      "statusCode": 404,
      "message": "Tenant not found"
    }
  • 409Suppression impossible (factures impayées par exemple)
    Réponse 409 · JSON
    {
      "statusCode": 409,
      "message": "Cannot delete tenant with unpaid invoices"
    }

Exemples

DELETE /api/v1/admin/tenants/:id · cURL / Shell
curl -X DELETE https://api.qualiforma.site/api/v1/admin/tenants/tnt_8f3b1c20-4d5e-4a9b-9c20-2c5d8e7f0a1b \
  -H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
  -H "X-Tenant-ID: qualiforma-demo"
DELETE /api/v1/admin/tenants/:id · JavaScript
const response = await fetch('https://api.qualiforma.site/api/v1/admin/tenants/tnt_8f3b1c20-4d5e-4a9b-9c20-2c5d8e7f0a1b', {
  method: 'DELETE',
  headers: {
    'Authorization': 'Bearer YOUR_ACCESS_TOKEN',
    'X-Tenant-ID': 'qualiforma-demo',
  },
});

if (!response.ok) {
  throw new Error(`HTTP ${response.status}: ${await response.text()}`);
}

const data = await response.json();
console.log(data);
DELETE /api/v1/admin/tenants/:id · Python
import requests

response = requests.delete(
    'https://api.qualiforma.site/api/v1/admin/tenants/tnt_8f3b1c20-4d5e-4a9b-9c20-2c5d8e7f0a1b',
    headers={
        'Authorization': 'Bearer YOUR_ACCESS_TOKEN',
        'X-Tenant-ID': 'qualiforma-demo',
    },
    timeout=30,
)
response.raise_for_status()
data = response.json()
print(data)
DELETE /api/v1/admin/tenants/:id · PHP
<?php

use GuzzleHttp\Client;
use GuzzleHttp\Exception\GuzzleException;

$client = new Client(['base_uri' => 'https://api.qualiforma.site/api/v1/']);

try {
    $response = $client->delete('admin/tenants/tnt_8f3b1c20-4d5e-4a9b-9c20-2c5d8e7f0a1b', [
        'headers' => [
            'Authorization' => 'Bearer YOUR_ACCESS_TOKEN',
            'X-Tenant-ID' => 'qualiforma-demo',
        ],
    ]);
    $data = json_decode($response->getBody()->getContents(), true);
    var_dump($data);
} catch (GuzzleException $e) {
    fwrite(STDERR, $e->getMessage());
}
QualiForma

La plateforme de formation professionnelle certifiee Qualiopi.

Plateforme

  • Catalogue
  • Espace formateur
  • Étude de besoin

Societe

  • A propos
  • Contact

Ressources

  • Développeurs
  • Référence API
  • Webhooks

Legal

  • CGV
  • Mentions legales
  • Confidentialite

Catalogue par catégorie

  • Management
  • Digital
  • Communication
  • Langues
  • Sécurité
  • Gestion

Comparatifs

  • QualiForma vs Didask
  • QualiForma vs Edusign
  • QualiForma vs Klaxoon
  • QualiForma vs 360Learning

Glossaire Qualiopi

  • I01 — Conditions d'information
  • I05 — Adaptation des prestations
  • I11 — Évaluations en cours
  • I22 — Compétences des intervenants
  • I30 — Recueil des appréciations
  • Voir les 32 indicateurs →

© 2026 QualiForma. Tous droits reserves.

Certifie Qualiopi