Qualiopi
Export du dossier d'audit par formation et validation pré-publication des 32 indicateurs Qualiopi. Réservé aux comptes ADMIN du tenant.
Endpoints disponibles
- GET
/api/v1/qualiopi/courses/:courseId/audit-export/previewAperçu des documents inclus dans l’export - GET
/api/v1/qualiopi/courses/:courseId/audit-exportTéléchargement du ZIP d’audit (ADMIN only) - GET
/api/v1/qualiopi/check-publicationValidation des 32 indicateurs avant publication
GET/qualiopi/courses/:courseId/audit-export/preview
Retourne la liste des documents qui seront inclus dans l'export ZIP avec leur taille estimée et la couverture des 32 indicateurs. Idéal pour afficher un récapitulatif avant le téléchargement.
Aperçu de l’export · Python
import requests
course_id = "crs_abc123"
response = requests.get(
f'https://api.qualiforma.site/api/v1/qualiopi/courses/{course_id}/audit-export/preview',
headers={
'Authorization': f'Bearer {access_token}',
'X-Tenant-ID': 'votre-tenant'
}
)
preview = response.json()['data']
print(f"Documents inclus : {preview['documentCount']}")
print(f"Indicateurs couverts : {preview['indicatorsCovered']} / 32")
print(f"Taille estimée : {preview['estimatedSizeMb']} MB")
for doc in preview['documents']:
print(f" - [{doc['indicator']}] {doc['name']}")Aperçu de l’export · cURL / Shell
TOKEN="eyJhbGci..."
COURSE_ID="crs_abc123"
curl "https://api.qualiforma.site/api/v1/qualiopi/courses/$COURSE_ID/audit-export/preview" \
-H "Authorization: Bearer $TOKEN" \
-H 'X-Tenant-ID: votre-tenant'Aperçu de l’export · TypeScript
interface AuditExportPreview {
documentCount: number;
indicatorsCovered: number;
estimatedSizeMb: number;
documents: Array<{
name: string;
indicator: string; // ex. "I-7"
type: string; // CONVENTION | EMARGEMENT | EVALUATION ...
sizeBytes: number;
}>;
}
async function previewAuditExport(
courseId: string,
accessToken: string,
tenantId: string
): Promise<AuditExportPreview> {
const response = await fetch(
`https://api.qualiforma.site/api/v1/qualiopi/courses/${courseId}/audit-export/preview`,
{
headers: {
Authorization: `Bearer ${accessToken}`,
'X-Tenant-ID': tenantId,
},
}
);
const { data } = await response.json();
return data;
}Aperçu de l’export · PHP
<?php
use GuzzleHttp\Client;
use GuzzleHttp\Exception\GuzzleException;
$client = new Client(['base_uri' => 'https://api.qualiforma.site/api/v1/']);
$courseId = 'crs_abc123';
try {
$response = $client->get("qualiopi/courses/{$courseId}/audit-export/preview", [
'headers' => [
'Authorization' => 'Bearer ' . $accessToken,
'X-Tenant-ID' => 'votre-tenant',
],
]);
$preview = json_decode($response->getBody()->getContents(), true)['data'];
echo "Documents inclus : {$preview['documentCount']}\n";
echo "Indicateurs couverts : {$preview['indicatorsCovered']} / 32\n";
echo "Taille estimee : {$preview['estimatedSizeMb']} MB\n";
foreach ($preview['documents'] as $doc) {
echo " - [{$doc['indicator']}] {$doc['name']}\n";
}
} catch (GuzzleException $e) {
fwrite(STDERR, "Erreur: " . $e->getMessage() . PHP_EOL);
}GET/qualiopi/courses/:courseId/audit-export
Télécharge l'archive ZIP complète du dossier d'audit pour la formation. Le contenu est généré à la volée à partir des données du tenant. Streaming HTTP pour les gros dossiers (centaines de MB).
Télécharger l’export · Python
import requests
course_id = "crs_abc123"
# Téléchargement du ZIP (stream pour les gros dossiers)
with requests.get(
f'https://api.qualiforma.site/api/v1/qualiopi/courses/{course_id}/audit-export',
headers={
'Authorization': f'Bearer {access_token}',
'X-Tenant-ID': 'votre-tenant'
},
stream=True
) as response:
response.raise_for_status()
with open(f'audit-{course_id}.zip', 'wb') as f:
for chunk in response.iter_content(chunk_size=8192):
f.write(chunk)
print(f"Dossier d'audit exporté : audit-{course_id}.zip")Télécharger l’export · cURL / Shell
TOKEN="eyJhbGci..."
COURSE_ID="crs_abc123"
# Téléchargement direct du ZIP
curl -X GET "https://api.qualiforma.site/api/v1/qualiopi/courses/$COURSE_ID/audit-export" \
-H "Authorization: Bearer $TOKEN" \
-H 'X-Tenant-ID: votre-tenant' \
-o "audit-$COURSE_ID.zip"
# Le ZIP contient :
# /convention/ contrats + conventions de formation
# /emargement/ feuilles d'émargement signées
# /evaluation/ questionnaires pre/post + analyse IA
# /attestation/ attestations de fin de formation
# /programme/ programmes pédagogiques + objectifs
# /trainers/ CV + certifications formateurs
# /qualiopi-report.pdf rapport agrégé 32 indicateursTélécharger l’export · TypeScript
async function downloadAuditExport(
courseId: string,
accessToken: string,
tenantId: string
): Promise<Blob> {
const response = await fetch(
`https://api.qualiforma.site/api/v1/qualiopi/courses/${courseId}/audit-export`,
{
headers: {
Authorization: `Bearer ${accessToken}`,
'X-Tenant-ID': tenantId,
},
}
);
if (!response.ok) {
throw new Error(`Export refusé : ${response.status}`);
}
return await response.blob();
}
// Sauvegarde côté navigateur
const blob = await downloadAuditExport('crs_abc123', token, tenant);
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = 'audit-crs_abc123.zip';
a.click();
URL.revokeObjectURL(url);Télécharger l’export · PHP
<?php
use GuzzleHttp\Client;
use GuzzleHttp\Exception\GuzzleException;
$client = new Client(['base_uri' => 'https://api.qualiforma.site/api/v1/']);
$courseId = 'crs_abc123';
$outputFile = "audit-{$courseId}.zip";
try {
// Streaming HTTP pour les gros dossiers (centaines de MB)
$response = $client->get("qualiopi/courses/{$courseId}/audit-export", [
'headers' => [
'Authorization' => 'Bearer ' . $accessToken,
'X-Tenant-ID' => 'votre-tenant',
],
'sink' => $outputFile, // ecrit directement sur disque
'stream' => true,
]);
echo "Dossier d'audit exporte : {$outputFile}\n";
} catch (GuzzleException $e) {
fwrite(STDERR, "Erreur: " . $e->getMessage() . PHP_EOL);
}GET/qualiopi/check-publication
Évalue la conformité Qualiopi d'une formation et retourne la liste des bloquants / avertissements. À appeler en pré-flight avant tout PATCH /courses/:id avec status: PUBLISHED.
Validation pré-publication · Python
import requests
course_id = "crs_abc123"
response = requests.get(
'https://api.qualiforma.site/api/v1/qualiopi/check-publication',
headers={
'Authorization': f'Bearer {access_token}',
'X-Tenant-ID': 'votre-tenant'
},
params={'courseId': course_id}
)
result = response.json()['data']
if result['canPublish']:
print(f"Formation prête à publier ({result['score']}/100)")
else:
print(f"Bloquants ({len(result['blockers'])}) :")
for blocker in result['blockers']:
print(f" - [{blocker['indicator']}] {blocker['message']}")
print(f"Avertissements ({len(result['warnings'])}) :")
for warn in result['warnings']:
print(f" - {warn['message']}")Validation pré-publication · cURL / Shell
TOKEN="eyJhbGci..."
COURSE_ID="crs_abc123"
curl "https://api.qualiforma.site/api/v1/qualiopi/check-publication?courseId=$COURSE_ID" \
-H "Authorization: Bearer $TOKEN" \
-H 'X-Tenant-ID: votre-tenant'
# Réponse :
# {
# "data": {
# "canPublish": false,
# "score": 78,
# "indicatorsCovered": 25,
# "indicatorsTotal": 32,
# "blockers": [
# { "indicator": "I-9",
# "message": "Programme pédagogique manquant" }
# ],
# "warnings": [
# { "message": "Aucun questionnaire pré-formation configuré" }
# ]
# }
# }Validation pré-publication · TypeScript
interface PublicationCheck {
canPublish: boolean;
score: number; // 0-100
indicatorsCovered: number;
indicatorsTotal: number;
blockers: Array<{ indicator: string; message: string }>;
warnings: Array<{ message: string }>;
}
async function checkPublication(
courseId: string,
accessToken: string,
tenantId: string
): Promise<PublicationCheck> {
const url = new URL('https://api.qualiforma.site/api/v1/qualiopi/check-publication');
url.searchParams.set('courseId', courseId);
const response = await fetch(url, {
headers: {
Authorization: `Bearer ${accessToken}`,
'X-Tenant-ID': tenantId,
},
});
const { data } = await response.json();
return data;
}
// Pattern : pré-flight avant PATCH status=PUBLISHED
const check = await checkPublication('crs_abc123', token, tenant);
if (!check.canPublish) {
console.error('Bloquants :', check.blockers);
return;
}
await publishCourse('crs_abc123');Validation pré-publication · PHP
<?php
use GuzzleHttp\Client;
use GuzzleHttp\Exception\GuzzleException;
$client = new Client(['base_uri' => 'https://api.qualiforma.site/api/v1/']);
$courseId = 'crs_abc123';
try {
$response = $client->get('qualiopi/check-publication', [
'headers' => [
'Authorization' => 'Bearer ' . $accessToken,
'X-Tenant-ID' => 'votre-tenant',
],
'query' => ['courseId' => $courseId],
]);
$result = json_decode($response->getBody()->getContents(), true)['data'];
if ($result['canPublish']) {
echo "Formation prete a publier ({$result['score']}/100)\n";
} else {
echo "Bloquants (" . count($result['blockers']) . ") :\n";
foreach ($result['blockers'] as $blocker) {
echo " - [{$blocker['indicator']}] {$blocker['message']}\n";
}
echo "Avertissements (" . count($result['warnings']) . ") :\n";
foreach ($result['warnings'] as $warn) {
echo " - {$warn['message']}\n";
}
}
} catch (GuzzleException $e) {
fwrite(STDERR, "Erreur: " . $e->getMessage() . PHP_EOL);
}