Conformité
Endpoints liés au cycle Qualiopi : analyse des besoins amont, parcours adaptatifs (Critère 3) et timeline du Plan d'Action Formation pour le suivi audit.
Endpoints disponibles
- POST
/api/v1/needs-analysisCréer une analyse des besoins de formation - GET
/api/v1/needs-analysisLister les analyses (paginé, filtres) - POST
/api/v1/adaptive-pathsCréer un parcours adaptatif (Critère 3) - GET
/api/v1/adaptive-pathsLister les parcours adaptatifs - PATCH
/api/v1/adaptive-paths/:idModifier un parcours (modules, audience) - GET
/api/v1/paf/enrollments/:id/timelineTimeline complète du Plan d'Action Formation
POST/needs-analysis
Crée une analyse des besoins de formation pour une entreprise ou un apprenant. L'IA peut générer des recommandations de formations à partir des objectifs et du gap de compétences.
import requests
response = requests.post(
'https://api.qualiforma.site/api/v1/needs-analysis',
headers={
'Authorization': f'Bearer {access_token}',
'X-Tenant-ID': 'votre-tenant',
'Content-Type': 'application/json'
},
json={
'companyId': 'cmp_abc123',
'enrollmentId': 'enr_xyz789', # optionnel
'objectives': ['Maîtriser Excel pour reporting RH'],
'currentLevel': 'BEGINNER',
'targetLevel': 'ADVANCED',
'context': 'Mise à jour annuelle compétences bureautiques',
'fundingSource': 'OPCO'
}
)
needs = response.json()['data']
print(f"Analyse créée : {needs['id']}")
print(f"Recommandations IA : {len(needs['recommendations'])}")TOKEN="eyJhbGci..."
curl -X POST https://api.qualiforma.site/api/v1/needs-analysis \
-H "Authorization: Bearer $TOKEN" \
-H 'X-Tenant-ID: votre-tenant' \
-H 'Content-Type: application/json' \
-d '{
"companyId": "cmp_abc123",
"objectives": ["Maîtriser Excel pour reporting RH"],
"currentLevel": "BEGINNER",
"targetLevel": "ADVANCED",
"context": "Mise à jour annuelle compétences bureautiques",
"fundingSource": "OPCO"
}'interface NeedsAnalysisInput {
companyId: string;
enrollmentId?: string;
objectives: string[];
currentLevel: 'BEGINNER' | 'INTERMEDIATE' | 'ADVANCED' | 'EXPERT';
targetLevel: 'BEGINNER' | 'INTERMEDIATE' | 'ADVANCED' | 'EXPERT';
context: string;
fundingSource?: 'OPCO' | 'CPF' | 'POLE_EMPLOI' | 'SELF' | 'OTHER';
}
async function createNeedsAnalysis(
input: NeedsAnalysisInput,
accessToken: string,
tenantId: string
) {
const response = await fetch('https://api.qualiforma.site/api/v1/needs-analysis', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
Authorization: `Bearer ${accessToken}`,
'X-Tenant-ID': tenantId,
},
body: JSON.stringify(input),
});
const { data } = await response.json();
return data; // { id, recommendations[], gapAnalysis, ... }
}<?php
use GuzzleHttp\Client;
use GuzzleHttp\Exception\GuzzleException;
$client = new Client(['base_uri' => 'https://api.qualiforma.site/api/v1/']);
try {
$response = $client->post('needs-analysis', [
'headers' => [
'Authorization' => 'Bearer ' . $accessToken,
'X-Tenant-ID' => 'votre-tenant',
'Content-Type' => 'application/json',
],
'json' => [
'companyId' => 'cmp_abc123',
'enrollmentId' => 'enr_xyz789', // optionnel
'objectives' => ['Maitriser Excel pour reporting RH'],
'currentLevel' => 'BEGINNER',
'targetLevel' => 'ADVANCED',
'context' => 'Mise a jour annuelle competences bureautiques',
'fundingSource' => 'OPCO',
],
]);
$needs = json_decode($response->getBody()->getContents(), true)['data'];
echo "Analyse creee : {$needs['id']}\n";
echo "Recommandations IA : " . count($needs['recommendations']) . "\n";
} catch (GuzzleException $e) {
fwrite(STDERR, "Erreur: " . $e->getMessage() . PHP_EOL);
}Lister les analyses du tenant :
TOKEN="eyJhbGci..."
# Lister les analyses du tenant (paginé)
curl "https://api.qualiforma.site/api/v1/needs-analysis?page=1&perPage=20&companyId=cmp_abc123" \
-H "Authorization: Bearer $TOKEN" \
-H 'X-Tenant-ID: votre-tenant'POST/adaptive-paths
Crée un parcours adaptatif composé de plusieurs formations enchaînées avec un ordre, des conditions de déblocage et un assessment de prérequis facultatif. Couvre l'exigence du Critère 3 Qualiopi (adaptation au public).
import requests
# Créer un parcours adaptatif (Critère 3 Qualiopi)
response = requests.post(
'https://api.qualiforma.site/api/v1/adaptive-paths',
headers={
'Authorization': f'Bearer {access_token}',
'X-Tenant-ID': 'votre-tenant',
'Content-Type': 'application/json'
},
json={
'name': 'Parcours Excel - Public débutant',
'description': "Adapté aux apprenants n'ayant jamais utilisé Excel",
'targetAudience': 'BEGINNER',
'modules': [
{'courseId': 'crs_excel_init', 'order': 1, 'mandatory': True},
{'courseId': 'crs_excel_form', 'order': 2, 'mandatory': True},
{'courseId': 'crs_excel_macro', 'order': 3, 'mandatory': False}
],
'prerequisiteAssessmentId': 'qst_pre_excel'
}
)
path = response.json()['data']
print(f"Parcours créé : {path['id']} ({len(path['modules'])} modules)")TOKEN="eyJhbGci..."
curl -X POST https://api.qualiforma.site/api/v1/adaptive-paths \
-H "Authorization: Bearer $TOKEN" \
-H 'X-Tenant-ID: votre-tenant' \
-H 'Content-Type: application/json' \
-d '{
"name": "Parcours Excel - Public débutant",
"targetAudience": "BEGINNER",
"modules": [
{ "courseId": "crs_excel_init", "order": 1, "mandatory": true },
{ "courseId": "crs_excel_form", "order": 2, "mandatory": true }
]
}'interface AdaptivePathModule {
courseId: string;
order: number;
mandatory: boolean;
unlockCondition?: 'COMPLETION' | 'SCORE_GTE_70' | 'SCORE_GTE_80';
}
interface AdaptivePathInput {
name: string;
description?: string;
targetAudience: 'BEGINNER' | 'INTERMEDIATE' | 'ADVANCED' | 'EXPERT';
modules: AdaptivePathModule[];
prerequisiteAssessmentId?: string;
}
async function createAdaptivePath(
input: AdaptivePathInput,
accessToken: string,
tenantId: string
) {
const response = await fetch('https://api.qualiforma.site/api/v1/adaptive-paths', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
Authorization: `Bearer ${accessToken}`,
'X-Tenant-ID': tenantId,
},
body: JSON.stringify(input),
});
const { data } = await response.json();
return data;
}<?php
use GuzzleHttp\Client;
use GuzzleHttp\Exception\GuzzleException;
$client = new Client(['base_uri' => 'https://api.qualiforma.site/api/v1/']);
try {
// Creer un parcours adaptatif (Critere 3 Qualiopi)
$response = $client->post('adaptive-paths', [
'headers' => [
'Authorization' => 'Bearer ' . $accessToken,
'X-Tenant-ID' => 'votre-tenant',
'Content-Type' => 'application/json',
],
'json' => [
'name' => 'Parcours Excel - Public debutant',
'description' => "Adapte aux apprenants n'ayant jamais utilise Excel",
'targetAudience' => 'BEGINNER',
'modules' => [
['courseId' => 'crs_excel_init', 'order' => 1, 'mandatory' => true],
['courseId' => 'crs_excel_form', 'order' => 2, 'mandatory' => true],
['courseId' => 'crs_excel_macro', 'order' => 3, 'mandatory' => false],
],
'prerequisiteAssessmentId' => 'qst_pre_excel',
],
]);
$path = json_decode($response->getBody()->getContents(), true)['data'];
echo "Parcours cree : {$path['id']} (" . count($path['modules']) . " modules)\n";
} catch (GuzzleException $e) {
fwrite(STDERR, "Erreur: " . $e->getMessage() . PHP_EOL);
}GET/paf/enrollments/:id/timeline
Retourne la timeline complète d'un Plan d'Action Formation pour une inscription : création, analyse des besoins, sessions, émargements, questionnaires, attestations. Trié par date croissante. Idéal pour reconstituer le dossier audit d'un apprenant.
import requests
enrollment_id = "enr_abc123"
response = requests.get(
f'https://api.qualiforma.site/api/v1/paf/enrollments/{enrollment_id}/timeline',
headers={
'Authorization': f'Bearer {access_token}',
'X-Tenant-ID': 'votre-tenant'
}
)
timeline = response.json()['data']
print(f"Timeline PAF — {len(timeline['events'])} événements")
for ev in timeline['events']:
print(f" [{ev['date']}] {ev['type']:20s} {ev['description']}")TOKEN="eyJhbGci..."
ENROLLMENT_ID="enr_abc123"
curl "https://api.qualiforma.site/api/v1/paf/enrollments/$ENROLLMENT_ID/timeline" \
-H "Authorization: Bearer $TOKEN" \
-H 'X-Tenant-ID: votre-tenant'
# Réponse :
# {
# "data": {
# "enrollmentId": "enr_abc123",
# "events": [
# { "date": "2026-04-01T10:00:00Z",
# "type": "ENROLLMENT_CREATED",
# "description": "Inscription créée par admin@qualiforma.fr" },
# { "date": "2026-04-02T09:30:00Z",
# "type": "NEEDS_ANALYSIS_COMPLETED",
# "description": "Analyse des besoins validée — niveau cible : ADVANCED" },
# { "date": "2026-04-15T14:00:00Z",
# "type": "PRE_QUESTIONNAIRE_COMPLETED",
# "description": "Questionnaire pré-formation rempli (score 12/20)" }
# ]
# }
# }type PafEventType =
| 'ENROLLMENT_CREATED'
| 'NEEDS_ANALYSIS_COMPLETED'
| 'PRE_QUESTIONNAIRE_COMPLETED'
| 'SESSION_ATTENDED'
| 'EMARGEMENT_SIGNED'
| 'POST_QUESTIONNAIRE_COMPLETED'
| 'CERTIFICATE_ISSUED'
| 'IMPROVEMENT_PLAN_CREATED';
interface PafTimeline {
enrollmentId: string;
events: Array<{
date: string; // ISO 8601
type: PafEventType;
description: string;
metadata?: Record<string, unknown>;
}>;
}
async function getPafTimeline(
enrollmentId: string,
accessToken: string,
tenantId: string
): Promise<PafTimeline> {
const response = await fetch(
`https://api.qualiforma.site/api/v1/paf/enrollments/${enrollmentId}/timeline`,
{
headers: {
Authorization: `Bearer ${accessToken}`,
'X-Tenant-ID': tenantId,
},
}
);
const { data } = await response.json();
return data;
}<?php
use GuzzleHttp\Client;
use GuzzleHttp\Exception\GuzzleException;
$client = new Client(['base_uri' => 'https://api.qualiforma.site/api/v1/']);
$enrollmentId = 'enr_abc123';
try {
$response = $client->get("paf/enrollments/{$enrollmentId}/timeline", [
'headers' => [
'Authorization' => 'Bearer ' . $accessToken,
'X-Tenant-ID' => 'votre-tenant',
],
]);
$timeline = json_decode($response->getBody()->getContents(), true)['data'];
echo "Timeline PAF - " . count($timeline['events']) . " evenements\n";
foreach ($timeline['events'] as $ev) {
printf(" [%s] %-20s %s\n", $ev['date'], $ev['type'], $ev['description']);
}
} catch (GuzzleException $e) {
fwrite(STDERR, "Erreur: " . $e->getMessage() . PHP_EOL);
}