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. Complaints

Complaints — Réclamations apprenant

Gestion complète des réclamations (Critère Qualiopi 6) : création, suivi, commentaires internes, résolution avec actions correctives, escalade au médiateur, lien automatique avec les plans d’amélioration (Critère 7) et statistiques d’audit.

Cycle de vie d’une réclamation

  1. NEW — création par l’apprenant (POST /complaints). Notification email automatique aux admins.
  2. IN_REVIEW — un admin est assigné (PATCH avec assignedTo) et ajoute des commentaires internes.
  3. RESOLVED — résolution proposée avec actions correctives (POST /resolve). L’apprenant est notifié.
  4. ESCALATED — si désaccord persistant, escalade au médiateur souscrit (POST /escalate-mediator). Voir module mediators.
  5. CLOSED — clôture finale après accord (manuel ou auto après 30j sans retour).

Catégories et sévérités

Catégories : COURSE_QUALITY (contenu pédagogique), ADMIN (inscription, convocations), BILLING (factures, remboursements), OTHER.

Sévérités : LOW, MEDIUM, HIGH (déclenche brouillon de plan d’amélioration), CRITICAL (notification temps réel à l’admin + SLA 24h).

Endpoints détaillés

get/api/v1/complaints

Lister les réclamations

Liste paginée des réclamations du tenant. Filtrable par statut et sévérité.

  • Complaints
  • Qualiopi

Paramètres

NomTypeRequisExempleDescription
pagequerynon1—
perPagequerynon20—
statusquerynonIN_REVIEWNEW | IN_REVIEW | RESOLVED | ESCALATED | CLOSED
severityquerynonHIGHLOW | MEDIUM | HIGH | CRITICAL
assignedToquerynonusr_admin1ID utilisateur assigné

Réponses

  • 200Liste paginée
    Réponse 200 · JSON
    {
      "data": [
        {
          "id": "cpl_abc123",
          "subject": "Problème de connexion à la session live",
          "category": "COURSE_QUALITY",
          "severity": "HIGH",
          "status": "IN_REVIEW",
          "createdAt": "2026-05-10T09:30:00Z",
          "assignedTo": "usr_admin1"
        }
      ],
      "meta": {
        "page": 1,
        "perPage": 20,
        "total": 12
      }
    }

Exemples

GET /api/v1/complaints · cURL / Shell
curl -X GET https://api.qualiforma.site/api/v1/complaints?page=1&perPage=20&status=IN_REVIEW&severity=HIGH&assignedTo=usr_admin1 \
  -H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
  -H "X-Tenant-ID: qualiforma-demo"
GET /api/v1/complaints · JavaScript
const response = await fetch('https://api.qualiforma.site/api/v1/complaints?page=1&perPage=20&status=IN_REVIEW&severity=HIGH&assignedTo=usr_admin1', {
  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/complaints · Python
import requests

response = requests.get(
    'https://api.qualiforma.site/api/v1/complaints?page=1&perPage=20&status=IN_REVIEW&severity=HIGH&assignedTo=usr_admin1',
    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/complaints · PHP
<?php

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

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

try {
    $response = $client->get('complaints?page=1&perPage=20&status=IN_REVIEW&severity=HIGH&assignedTo=usr_admin1', [
        '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/complaints/:id

Détail d’une réclamation

Retourne tous les champs : description, pièces jointes, commentaires internes, historique de statut, plan d’amélioration lié.

  • Complaints

Paramètres

NomTypeRequisExempleDescription
idpathouicpl_abc123—

Réponses

  • 200OK
    Réponse 200 · JSON
    {
      "data": {
        "id": "cpl_abc123",
        "subject": "Problème de connexion à la session live",
        "description": "Je n’arrive pas à rejoindre la session du 10/05…",
        "category": "COURSE_QUALITY",
        "severity": "HIGH",
        "status": "IN_REVIEW",
        "courseId": "crs_abc123",
        "sessionId": "ses_xyz789",
        "attachments": [
          "attachments/2026/05/cpl_abc123/log.txt"
        ],
        "comments": [
          {
            "author": "admin",
            "text": "Investigation en cours",
            "at": "2026-05-10T10:00:00Z"
          }
        ],
        "improvementPlanId": null
      }
    }
  • 404Réclamation introuvable

Exemples

GET /api/v1/complaints/:id · cURL / Shell
curl -X GET https://api.qualiforma.site/api/v1/complaints/cpl_abc123 \
  -H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
  -H "X-Tenant-ID: qualiforma-demo"
GET /api/v1/complaints/:id · JavaScript
const response = await fetch('https://api.qualiforma.site/api/v1/complaints/cpl_abc123', {
  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/complaints/:id · Python
import requests

response = requests.get(
    'https://api.qualiforma.site/api/v1/complaints/cpl_abc123',
    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/complaints/:id · PHP
<?php

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

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

try {
    $response = $client->get('complaints/cpl_abc123', [
        '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/complaints

Créer une réclamation

Accessible aux apprenants (auth ou contact public). Déclenche automatiquement une notification email à l’admin et l’ouverture d’un brouillon de plan d’amélioration si severity ≥ HIGH.

  • Complaints

Corps de requête

Content-Type : application/json

Body · JSON
{
  "subject": "Problème de connexion à la session live",
  "description": "Je n’arrive pas à rejoindre la session du 10/05 malgré plusieurs tentatives.",
  "category": "COURSE_QUALITY",
  "severity": "HIGH",
  "courseId": "crs_abc123",
  "sessionId": "ses_xyz789",
  "attachments": [
    "attachments/2026/05/upload_log.txt"
  ]
}

Réponses

  • 201Réclamation enregistrée
    Réponse 201 · JSON
    {
      "data": {
        "id": "cpl_new",
        "status": "NEW",
        "createdAt": "2026-05-15T10:00:00Z",
        "notifiedAdmins": [
          "admin@qualiforma.fr"
        ]
      }
    }
  • 422Validation échouée (catégorie ou sévérité invalide)

Exemples

POST /api/v1/complaints · cURL / Shell
curl -X POST https://api.qualiforma.site/api/v1/complaints \
  -H "X-Tenant-ID: qualiforma-demo" \
  -H "Content-Type: application/json" \
  -d '{
  "subject": "Problème de connexion à la session live",
  "description": "Je n’arrive pas à rejoindre la session du 10/05 malgré plusieurs tentatives.",
  "category": "COURSE_QUALITY",
  "severity": "HIGH",
  "courseId": "crs_abc123",
  "sessionId": "ses_xyz789",
  "attachments": [
    "attachments/2026/05/upload_log.txt"
  ]
}'
POST /api/v1/complaints · JavaScript
const response = await fetch('https://api.qualiforma.site/api/v1/complaints', {
  method: 'POST',
  headers: {
    'X-Tenant-ID': 'qualiforma-demo',
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    "subject": "Problème de connexion à la session live",
    "description": "Je n’arrive pas à rejoindre la session du 10/05 malgré plusieurs tentatives.",
    "category": "COURSE_QUALITY",
    "severity": "HIGH",
    "courseId": "crs_abc123",
    "sessionId": "ses_xyz789",
    "attachments": [
      "attachments/2026/05/upload_log.txt"
    ]
  }),
});

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

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

response = requests.post(
    'https://api.qualiforma.site/api/v1/complaints',
    headers={
        'X-Tenant-ID': 'qualiforma-demo',
        'Content-Type': 'application/json',
    },
    json={
        'subject': 'Problème de connexion à la session live',
        'description': 'Je n’arrive pas à rejoindre la session du 10/05 malgré plusieurs tentatives.',
        'category': 'COURSE_QUALITY',
        'severity': 'HIGH',
        'courseId': 'crs_abc123',
        'sessionId': 'ses_xyz789',
        'attachments': [
            'attachments/2026/05/upload_log.txt',
        ],
    },
    timeout=30,
)
response.raise_for_status()
data = response.json()
print(data)
POST /api/v1/complaints · PHP
<?php

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

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

try {
    $response = $client->post('complaints', [
        'headers' => [
            'X-Tenant-ID' => 'qualiforma-demo',
        ],
        'json' => [
            'subject' => 'Problème de connexion à la session live',
            'description' => 'Je n’arrive pas à rejoindre la session du 10/05 malgré plusieurs tentatives.',
            'category' => 'COURSE_QUALITY',
            'severity' => 'HIGH',
            'courseId' => 'crs_abc123',
            'sessionId' => 'ses_xyz789',
            'attachments' => [
                'attachments/2026/05/upload_log.txt',
            ],
        ],
    ]);
    $data = json_decode($response->getBody()->getContents(), true);
    var_dump($data);
} catch (GuzzleException $e) {
    fwrite(STDERR, $e->getMessage());
}
patch/api/v1/complaints/:id

Mettre à jour le statut ou l’assignation

Mise à jour partielle. Changement de statut tracé dans l’historique et déclenche les notifications pertinentes.

  • Complaints

Paramètres

NomTypeRequisExempleDescription
idpathouicpl_abc123—

Corps de requête

Content-Type : application/json

Body · JSON
{
  "status": "IN_REVIEW",
  "assignedTo": "usr_admin1"
}

Réponses

  • 200Mis à jour
  • 404Introuvable

Exemples

PATCH /api/v1/complaints/:id · cURL / Shell
curl -X PATCH https://api.qualiforma.site/api/v1/complaints/cpl_abc123 \
  -H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
  -H "X-Tenant-ID: qualiforma-demo" \
  -H "Content-Type: application/json" \
  -d '{
  "status": "IN_REVIEW",
  "assignedTo": "usr_admin1"
}'
PATCH /api/v1/complaints/:id · JavaScript
const response = await fetch('https://api.qualiforma.site/api/v1/complaints/cpl_abc123', {
  method: 'PATCH',
  headers: {
    'Authorization': 'Bearer YOUR_ACCESS_TOKEN',
    'X-Tenant-ID': 'qualiforma-demo',
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    "status": "IN_REVIEW",
    "assignedTo": "usr_admin1"
  }),
});

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

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

response = requests.patch(
    'https://api.qualiforma.site/api/v1/complaints/cpl_abc123',
    headers={
        'Authorization': 'Bearer YOUR_ACCESS_TOKEN',
        'X-Tenant-ID': 'qualiforma-demo',
        'Content-Type': 'application/json',
    },
    json={
        'status': 'IN_REVIEW',
        'assignedTo': 'usr_admin1',
    },
    timeout=30,
)
response.raise_for_status()
data = response.json()
print(data)
PATCH /api/v1/complaints/: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('complaints/cpl_abc123', [
        'headers' => [
            'Authorization' => 'Bearer YOUR_ACCESS_TOKEN',
            'X-Tenant-ID' => 'qualiforma-demo',
        ],
        'json' => [
            'status' => 'IN_REVIEW',
            'assignedTo' => 'usr_admin1',
        ],
    ]);
    $data = json_decode($response->getBody()->getContents(), true);
    var_dump($data);
} catch (GuzzleException $e) {
    fwrite(STDERR, $e->getMessage());
}
post/api/v1/complaints/:id/comments

Ajouter un commentaire interne

Ajoute un commentaire interne (non visible par le plaignant) à l’historique. Réservé ADMIN ou CREATOR.

  • Complaints

Paramètres

NomTypeRequisExempleDescription
idpathouicpl_abc123—

Corps de requête

Content-Type : application/json

Body · JSON
{
  "text": "Le formateur a confirmé un souci LiveKit côté serveur."
}

Réponses

  • 201Commentaire ajouté
    Réponse 201 · JSON
    {
      "data": {
        "id": "cmt_xyz",
        "at": "2026-05-15T11:00:00Z"
      }
    }

Exemples

POST /api/v1/complaints/:id/comments · cURL / Shell
curl -X POST https://api.qualiforma.site/api/v1/complaints/cpl_abc123/comments \
  -H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
  -H "X-Tenant-ID: qualiforma-demo" \
  -H "Content-Type: application/json" \
  -d '{
  "text": "Le formateur a confirmé un souci LiveKit côté serveur."
}'
POST /api/v1/complaints/:id/comments · JavaScript
const response = await fetch('https://api.qualiforma.site/api/v1/complaints/cpl_abc123/comments', {
  method: 'POST',
  headers: {
    'Authorization': 'Bearer YOUR_ACCESS_TOKEN',
    'X-Tenant-ID': 'qualiforma-demo',
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    "text": "Le formateur a confirmé un souci LiveKit côté serveur."
  }),
});

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

const data = await response.json();
console.log(data);
POST /api/v1/complaints/:id/comments · Python
import requests

response = requests.post(
    'https://api.qualiforma.site/api/v1/complaints/cpl_abc123/comments',
    headers={
        'Authorization': 'Bearer YOUR_ACCESS_TOKEN',
        'X-Tenant-ID': 'qualiforma-demo',
        'Content-Type': 'application/json',
    },
    json={
        'text': 'Le formateur a confirmé un souci LiveKit côté serveur.',
    },
    timeout=30,
)
response.raise_for_status()
data = response.json()
print(data)
POST /api/v1/complaints/:id/comments · PHP
<?php

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

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

try {
    $response = $client->post('complaints/cpl_abc123/comments', [
        'headers' => [
            'Authorization' => 'Bearer YOUR_ACCESS_TOKEN',
            'X-Tenant-ID' => 'qualiforma-demo',
        ],
        'json' => [
            'text' => 'Le formateur a confirmé un souci LiveKit côté serveur.',
        ],
    ]);
    $data = json_decode($response->getBody()->getContents(), true);
    var_dump($data);
} catch (GuzzleException $e) {
    fwrite(STDERR, $e->getMessage());
}
post/api/v1/complaints/:id/resolve

Résoudre une réclamation

Marque la réclamation comme RESOLVED avec une explication de résolution et la liste des actions correctives. Notifie le plaignant par email.

  • Complaints
  • Qualiopi

Paramètres

NomTypeRequisExempleDescription
idpathouicpl_abc123—

Corps de requête

Content-Type : application/json

Body · JSON
{
  "resolution": "Session re-planifiée le 17/05. Crédit d’une heure offert.",
  "correctiveActions": [
    "Monitoring LiveKit ajouté",
    "Procédure de re-planification documentée"
  ]
}

Réponses

  • 200Résolue
    Réponse 200 · JSON
    {
      "data": {
        "id": "cpl_abc123",
        "status": "RESOLVED",
        "resolvedAt": "2026-05-15T12:00:00Z"
      }
    }
  • 409Réclamation déjà résolue ou clôturée

Exemples

POST /api/v1/complaints/:id/resolve · cURL / Shell
curl -X POST https://api.qualiforma.site/api/v1/complaints/cpl_abc123/resolve \
  -H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
  -H "X-Tenant-ID: qualiforma-demo" \
  -H "Content-Type: application/json" \
  -d '{
  "resolution": "Session re-planifiée le 17/05. Crédit d’une heure offert.",
  "correctiveActions": [
    "Monitoring LiveKit ajouté",
    "Procédure de re-planification documentée"
  ]
}'
POST /api/v1/complaints/:id/resolve · JavaScript
const response = await fetch('https://api.qualiforma.site/api/v1/complaints/cpl_abc123/resolve', {
  method: 'POST',
  headers: {
    'Authorization': 'Bearer YOUR_ACCESS_TOKEN',
    'X-Tenant-ID': 'qualiforma-demo',
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    "resolution": "Session re-planifiée le 17/05. Crédit d’une heure offert.",
    "correctiveActions": [
      "Monitoring LiveKit ajouté",
      "Procédure de re-planification documentée"
    ]
  }),
});

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

const data = await response.json();
console.log(data);
POST /api/v1/complaints/:id/resolve · Python
import requests

response = requests.post(
    'https://api.qualiforma.site/api/v1/complaints/cpl_abc123/resolve',
    headers={
        'Authorization': 'Bearer YOUR_ACCESS_TOKEN',
        'X-Tenant-ID': 'qualiforma-demo',
        'Content-Type': 'application/json',
    },
    json={
        'resolution': 'Session re-planifiée le 17/05. Crédit d’une heure offert.',
        'correctiveActions': [
            'Monitoring LiveKit ajouté',
            'Procédure de re-planification documentée',
        ],
    },
    timeout=30,
)
response.raise_for_status()
data = response.json()
print(data)
POST /api/v1/complaints/:id/resolve · PHP
<?php

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

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

try {
    $response = $client->post('complaints/cpl_abc123/resolve', [
        'headers' => [
            'Authorization' => 'Bearer YOUR_ACCESS_TOKEN',
            'X-Tenant-ID' => 'qualiforma-demo',
        ],
        'json' => [
            'resolution' => 'Session re-planifiée le 17/05. Crédit d’une heure offert.',
            'correctiveActions' => [
                'Monitoring LiveKit ajouté',
                'Procédure de re-planification documentée',
            ],
        ],
    ]);
    $data = json_decode($response->getBody()->getContents(), true);
    var_dump($data);
} catch (GuzzleException $e) {
    fwrite(STDERR, $e->getMessage());
}
post/api/v1/complaints/:id/escalate-mediator

Escalader au médiateur de la consommation

Escalade la réclamation au médiateur souscrit par le tenant. Envoie automatiquement un email récapitulatif au médiateur avec les pièces jointes. Statut → ESCALATED.

  • Complaints
  • Mediators

Paramètres

NomTypeRequisExempleDescription
idpathouicpl_abc123—

Corps de requête

Content-Type : application/json

Body · JSON
{
  "reason": "Désaccord persistant après proposition de résolution."
}

Réponses

  • 200Escaladée
    Réponse 200 · JSON
    {
      "data": {
        "id": "cpl_abc123",
        "status": "ESCALATED",
        "mediatorId": "med_abc123",
        "escalatedAt": "2026-05-15T13:00:00Z"
      }
    }
  • 409Aucun contrat médiateur actif — souscrire d’abord via /tenants/current/mediator-contract

Exemples

POST /api/v1/complaints/:id/escalate-mediator · cURL / Shell
curl -X POST https://api.qualiforma.site/api/v1/complaints/cpl_abc123/escalate-mediator \
  -H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
  -H "X-Tenant-ID: qualiforma-demo" \
  -H "Content-Type: application/json" \
  -d '{
  "reason": "Désaccord persistant après proposition de résolution."
}'
POST /api/v1/complaints/:id/escalate-mediator · JavaScript
const response = await fetch('https://api.qualiforma.site/api/v1/complaints/cpl_abc123/escalate-mediator', {
  method: 'POST',
  headers: {
    'Authorization': 'Bearer YOUR_ACCESS_TOKEN',
    'X-Tenant-ID': 'qualiforma-demo',
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    "reason": "Désaccord persistant après proposition de résolution."
  }),
});

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

const data = await response.json();
console.log(data);
POST /api/v1/complaints/:id/escalate-mediator · Python
import requests

response = requests.post(
    'https://api.qualiforma.site/api/v1/complaints/cpl_abc123/escalate-mediator',
    headers={
        'Authorization': 'Bearer YOUR_ACCESS_TOKEN',
        'X-Tenant-ID': 'qualiforma-demo',
        'Content-Type': 'application/json',
    },
    json={
        'reason': 'Désaccord persistant après proposition de résolution.',
    },
    timeout=30,
)
response.raise_for_status()
data = response.json()
print(data)
POST /api/v1/complaints/:id/escalate-mediator · PHP
<?php

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

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

try {
    $response = $client->post('complaints/cpl_abc123/escalate-mediator', [
        'headers' => [
            'Authorization' => 'Bearer YOUR_ACCESS_TOKEN',
            'X-Tenant-ID' => 'qualiforma-demo',
        ],
        'json' => [
            'reason' => 'Désaccord persistant après proposition de résolution.',
        ],
    ]);
    $data = json_decode($response->getBody()->getContents(), true);
    var_dump($data);
} catch (GuzzleException $e) {
    fwrite(STDERR, $e->getMessage());
}
post/api/v1/complaints/:id/improvement-plan

Lier à un plan d’amélioration

Associe la réclamation à un plan d’amélioration (Critère Qualiopi 7) — existant ou nouveau. Critère Qualiopi 6/7 satisfait : la réclamation alimente le processus d’amélioration continue.

  • Complaints
  • Qualiopi

Paramètres

NomTypeRequisExempleDescription
idpathouicpl_abc123—

Corps de requête

Content-Type : application/json

Body · JSON
{
  "improvementPlanId": "imp_xyz789"
}

Réponses

  • 200Lien créé
    Réponse 200 · JSON
    {
      "data": {
        "complaintId": "cpl_abc123",
        "improvementPlanId": "imp_xyz789"
      }
    }

Exemples

POST /api/v1/complaints/:id/improvement-plan · cURL / Shell
curl -X POST https://api.qualiforma.site/api/v1/complaints/cpl_abc123/improvement-plan \
  -H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
  -H "X-Tenant-ID: qualiforma-demo" \
  -H "Content-Type: application/json" \
  -d '{
  "improvementPlanId": "imp_xyz789"
}'
POST /api/v1/complaints/:id/improvement-plan · JavaScript
const response = await fetch('https://api.qualiforma.site/api/v1/complaints/cpl_abc123/improvement-plan', {
  method: 'POST',
  headers: {
    'Authorization': 'Bearer YOUR_ACCESS_TOKEN',
    'X-Tenant-ID': 'qualiforma-demo',
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    "improvementPlanId": "imp_xyz789"
  }),
});

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

const data = await response.json();
console.log(data);
POST /api/v1/complaints/:id/improvement-plan · Python
import requests

response = requests.post(
    'https://api.qualiforma.site/api/v1/complaints/cpl_abc123/improvement-plan',
    headers={
        'Authorization': 'Bearer YOUR_ACCESS_TOKEN',
        'X-Tenant-ID': 'qualiforma-demo',
        'Content-Type': 'application/json',
    },
    json={
        'improvementPlanId': 'imp_xyz789',
    },
    timeout=30,
)
response.raise_for_status()
data = response.json()
print(data)
POST /api/v1/complaints/:id/improvement-plan · PHP
<?php

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

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

try {
    $response = $client->post('complaints/cpl_abc123/improvement-plan', [
        'headers' => [
            'Authorization' => 'Bearer YOUR_ACCESS_TOKEN',
            'X-Tenant-ID' => 'qualiforma-demo',
        ],
        'json' => [
            'improvementPlanId' => 'imp_xyz789',
        ],
    ]);
    $data = json_decode($response->getBody()->getContents(), true);
    var_dump($data);
} catch (GuzzleException $e) {
    fwrite(STDERR, $e->getMessage());
}
get/api/v1/complaints/stats

Statistiques Qualiopi (Critère 6)

Statistiques agrégées requises pour l’audit Qualiopi : nombre par statut, temps moyen de résolution, taux d’escalade vers le médiateur.

  • Complaints
  • Qualiopi

Paramètres

NomTypeRequisExempleDescription
fromDatequerynon2026-01-01—
toDatequerynon2026-12-31—

Réponses

  • 200Statistiques
    Réponse 200 · JSON
    {
      "data": {
        "total": 42,
        "byStatus": {
          "NEW": 3,
          "IN_REVIEW": 5,
          "RESOLVED": 28,
          "ESCALATED": 4,
          "CLOSED": 2
        },
        "bySeverity": {
          "LOW": 12,
          "MEDIUM": 18,
          "HIGH": 9,
          "CRITICAL": 3
        },
        "averageResolutionHours": 36.4,
        "escalationRate": 0.095,
        "resolutionRate": 0.83
      }
    }

Exemples

GET /api/v1/complaints/stats · cURL / Shell
curl -X GET https://api.qualiforma.site/api/v1/complaints/stats?fromDate=2026-01-01&toDate=2026-12-31 \
  -H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
  -H "X-Tenant-ID: qualiforma-demo"
GET /api/v1/complaints/stats · JavaScript
const response = await fetch('https://api.qualiforma.site/api/v1/complaints/stats?fromDate=2026-01-01&toDate=2026-12-31', {
  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/complaints/stats · Python
import requests

response = requests.get(
    'https://api.qualiforma.site/api/v1/complaints/stats?fromDate=2026-01-01&toDate=2026-12-31',
    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/complaints/stats · PHP
<?php

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

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

try {
    $response = $client->get('complaints/stats?fromDate=2026-01-01&toDate=2026-12-31', [
        '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