API REST Candidalyze
L'API Candidalyze permet d'intégrer l'analyse de CV et la comparaison de candidats directement dans vos outils RH. Tous les échanges se font en JSON via HTTPS.
Base URL
https://api.candidalyze.com/api/v1Authentification
Deux méthodes d'authentification sont disponibles :
API Key (endpoints data)
Pour les appels d'analyse et de comparaison. Transmettez votre clé dans le header X-API-Key.
curl -X POST https://api.candidalyze.com/api/v1/analyses \
-H "X-API-Key: sk_live_xxxxxxxxxxxx" \
-H "Content-Type: application/json" \
-d '{"cv_text": "...", "job_title": "...", "job_description": "..."}'Bearer JWT (endpoints management)
Pour la gestion des clés API et webhooks. Utilisez le token JWT de votre session Supabase.
curl https://api.candidalyze.com/api/v1/keys \
-H "Authorization: Bearer eyJhbGciOiJIUzI1NiIs..."Rate Limits
Les limites par défaut sont appliquées par clé API :
En cas de dépassement, l'API retourne un statut 429 Too Many Requests avec un header Retry-After.
Endpoints
/api/v1/analysesLance une analyse de CV par rapport à une fiche de poste. Le traitement est asynchrone — l'API retourne immédiatement un ID à interroger via GET.
Paramètres
cv_textstring (requis)— Texte du CV du candidatjob_titlestring (requis)— Intitulé du postejob_descriptionstring— Description complète du postecandidate_namestring— Nom du candidat (défaut: "Candidat API")languagestring— Langue du rapport: fr, en, es, it, de (défaut: fr)Corps de la requête
{
"cv_text": "Expérience: 5 ans en développement React...",
"job_title": "Développeur senior React",
"job_description": "Nous recherchons un développeur senior React...",
"candidate_name": "Alice Martin",
"language": "fr"
}Réponse
// 202 Accepted
{
"id": "550e8400-e29b-41d4-a716-446655440000",
"status": "pending",
"credits_remaining": 14,
"message": "Analysis started. Poll GET /api/v1/analyses/:id or listen for webhook analysis.completed."
}/api/v1/analysesListe les analyses effectuées, triées par date de création décroissante.
Paramètres
limitnumber— Nombre max de résultats (défaut: 20, max: 100)offsetnumber— Décalage pour la paginationRéponse
{
"analyses": [
{
"id": "ana_abc123",
"status": "completed",
"overall_score": 82,
"created_at": "2026-02-24T10:30:00Z"
}
],
"total": 42,
"limit": 20,
"offset": 0
}/api/v1/analyses/:idRetourne le détail complet d'une analyse.
Paramètres
idstring— Identifiant de l'analyseRéponse
{
"id": "ana_abc123",
"status": "completed",
"overall_score": 82,
"strengths": ["5 ans d'expérience React", "Stack technique alignée"],
"concerns": ["Pas d'expérience en management"],
"recommendations": ["Vérifier les compétences en architecture"],
"criteria_scores": {
"technical_skills": 90,
"experience": 85,
"soft_skills": 70
},
"summary": "Candidat solide avec un profil technique fort...",
"created_at": "2026-02-24T10:30:00Z"
}/api/v1/compareLance une comparaison entre 2 à 10 analyses existantes. Le traitement est asynchrone — l'API retourne immédiatement un ID à interroger via GET.
Paramètres
analysis_idsstring[] (requis)— Tableau de 2-10 IDs d'analyses complétéesjob_titlestring— Intitulé du poste (par défaut celui de la première analyse)languagestring— Langue du rapport: fr, en, es, it, de (défaut: fr)Corps de la requête
{
"analysis_ids": [
"550e8400-e29b-41d4-a716-446655440000",
"6ba7b810-9dad-11d1-80b4-00c04fd430c8"
],
"job_title": "Développeur senior React",
"language": "fr"
}Réponse
// 202 Accepted
{
"id": "7c9e6679-7425-40de-944b-e07fc1f90ae7",
"type": "comparison",
"status": "pending",
"candidate_count": 2,
"message": "Comparison started. Poll GET /api/v1/comparisons/:id or listen for webhook comparison.completed."
}/api/v1/comparisons/:idRetourne le détail d'une comparaison. Le champ type indique comparison (2 candidats) ou multi_comparison (3+). Le résultat est inclus uniquement quand status = completed.
Paramètres
idstring— Identifiant de la comparaisonRéponse
{
"comparison": {
"id": "7c9e6679-7425-40de-944b-e07fc1f90ae7",
"type": "comparison",
"status": "completed",
"job_title": "Développeur senior React",
"candidates": [
{ "name": "Alice Martin", "score": 85 },
{ "name": "Bob Dupont", "score": 72 }
],
"result": {
"verdict": { "winner": "A", "confidence": 0.82, "summary": "...", "decisionFactors": [...] },
"scoreComparison": { "overall": { "a": 85, "b": 72 }, ... },
"relativeStrengths": { "aOverB": [...], "bOverA": [...] },
"differentiatingQuestions": { "a": [...], "b": [...] }
},
"created_at": "2026-02-24T11:00:00Z",
"updated_at": "2026-02-24T11:00:15Z"
}
}/api/v1/creditsRetourne les crédits d'analyse restants, le quota de comparaisons et les informations du plan. Accessible avec n'importe quel scope.
Réponse
{
"credits_remaining": 15,
"bonus_remaining": 3,
"total_available": 18,
"comparisons_used": 7,
"comparisons_limit": 20,
"plan_type": "pro",
"period_end": "2026-03-01T00:00:00Z"
}/api/v1/keysCrée une nouvelle clé API. La clé complète n'est retournée qu'une seule fois.
Corps de la requête
{
"name": "Production Backend",
"scopes": ["analyses:read", "analyses:create"]
}Réponse
{
"id": "key_abc123",
"key": "sk_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
"key_prefix": "sk_live_xxxx",
"name": "Production Backend",
"scopes": ["analyses:read", "analyses:create"],
"rate_limit_per_minute": 30,
"rate_limit_per_day": 1000
}/api/v1/keysListe les clés API actives. Le secret complet n'est jamais retourné.
Réponse
{
"keys": [
{
"id": "key_abc123",
"key_prefix": "sk_live_xxxx",
"name": "Production Backend",
"scopes": ["analyses:read", "analyses:create"],
"last_used_at": "2026-02-24T09:15:00Z",
"total_requests": 1523,
"created_at": "2026-01-15T10:00:00Z"
}
]
}/api/v1/keys/:idRévoque une clé API. L'action est immédiate et irréversible.
Paramètres
idstring— Identifiant de la cléRéponse
{
"success": true,
"message": "API key revoked successfully"
}/api/v1/webhooksCrée un nouveau webhook. Le secret de signature n'est retourné qu'une seule fois.
Corps de la requête
{
"url": "https://votre-serveur.com/webhook",
"events": ["analysis.completed", "analysis.failed"],
"description": "Notification Slack"
}Réponse
{
"id": "wh_abc123",
"secret": "whsec_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
"url": "https://votre-serveur.com/webhook",
"events": ["analysis.completed", "analysis.failed"]
}/api/v1/webhooksListe les webhooks configurés.
Réponse
{
"webhooks": [
{
"id": "wh_abc123",
"url": "https://votre-serveur.com/webhook",
"events": ["analysis.completed", "analysis.failed"],
"description": "Notification Slack",
"last_triggered_at": "2026-02-24T09:15:00Z",
"last_status_code": 200,
"consecutive_failures": 0
}
]
}/api/v1/webhooks/:idSupprime un webhook.
Paramètres
idstring— Identifiant du webhookRéponse
{
"success": true,
"message": "Webhook deleted successfully"
}ATS — Positions & Candidates
Cabinet & Enterprise plans only. Requires positions:read, positions:write, candidates:read, or candidates:write scopes.
/api/v1/positionsList all job positions. Filter by status with ?status=active. Supports pagination.
Paramètres
limitnumber— Max results (default 50, max 100)offsetnumber— Pagination offset (default 0)statusstring— Filter by status: draft, active, paused, closedRéponse
{
"positions": [
{
"id": "550e8400-e29b-41d4-a716-446655440000",
"title": "Développeur senior React",
"description": "Nous recherchons...",
"location": "Paris",
"contract_type": "cdi",
"department": "Engineering",
"status": "active",
"custom_criteria": [{ "name": "React", "weight": 3 }],
"candidates_count": 12,
"created_at": "2026-03-01T10:00:00Z",
"updated_at": "2026-03-05T14:30:00Z"
}
],
"limit": 50,
"offset": 0
}/api/v1/positionsCreate a new job position.
Paramètres
titlestring (required)— Job title (max 200 chars)descriptionstring— Job description (max 5000 chars)locationstring— Location (max 200 chars)contract_typestring— cdi, cdd, interim, freelance, stage, alternance, otherdepartmentstring— Department namestatusstring— draft, active, paused, closed (default: active)custom_criteriaarray— Custom scoring criteria [{name, weight}]Corps de la requête
{
"title": "Développeur senior React",
"description": "Nous recherchons un développeur senior React...",
"location": "Paris",
"contract_type": "cdi",
"department": "Engineering",
"status": "active",
"custom_criteria": [
{ "name": "React/Next.js", "weight": 3 },
{ "name": "TypeScript", "weight": 2 }
]
}Réponse
// 201 Created
{
"position": {
"id": "550e8400-e29b-41d4-a716-446655440000",
"title": "Développeur senior React",
"status": "active",
"created_at": "2026-03-10T10:00:00Z"
}
}/api/v1/positions/:idGet details of a specific position.
Paramètres
idstring— Position UUIDRéponse
{
"position": {
"id": "550e8400-e29b-41d4-a716-446655440000",
"title": "Développeur senior React",
"description": "Nous recherchons...",
"location": "Paris",
"contract_type": "cdi",
"department": "Engineering",
"status": "active",
"custom_criteria": [{ "name": "React", "weight": 3 }],
"tag_colors": { "urgent": "#ef4444" },
"candidates_count": 12,
"created_at": "2026-03-01T10:00:00Z",
"updated_at": "2026-03-05T14:30:00Z"
}
}/api/v1/positions/:idUpdate a position. Only send the fields you want to change.
Paramètres
idstring— Position UUIDCorps de la requête
{
"status": "paused",
"description": "Updated job description..."
}Réponse
{
"position": {
"id": "550e8400-e29b-41d4-a716-446655440000",
"title": "Développeur senior React",
"status": "paused",
"updated_at": "2026-03-10T15:00:00Z"
}
}/api/v1/positions/:idDelete a position. Candidates linked to this position are not deleted.
Paramètres
idstring— Position UUIDRéponse
{
"success": true,
"message": "Position deleted successfully"
}/api/v1/positions/:id/candidatesList all candidates linked to a position, with scores, pipeline status, and tags.
Paramètres
idstring— Position UUIDlimitnumber— Max results (default 50, max 100)offsetnumber— Pagination offset (default 0)pipeline_statusstring— Filter: new, shortlist, interview, offer, hired, rejectedRéponse
{
"candidates": [
{
"id": "6ba7b810-9dad-11d1-80b4-00c04fd430c8",
"candidate_name": "Alice Martin",
"job_title": "Développeur senior React",
"overall_score": 85,
"recommendation": "strongly_recommend",
"pipeline_status": "shortlist",
"is_starred": true,
"tags": ["senior", "react-expert"],
"analysis_summary": "Profil technique solide...",
"created_at": "2026-03-02T10:30:00Z"
}
],
"limit": 50,
"offset": 0
}/api/v1/candidates/:id/pipelineMove a candidate through the recruitment pipeline.
Paramètres
idstring— Candidate (analysis) UUIDCorps de la requête
{
"status": "interview"
}Réponse
{
"success": true,
"id": "6ba7b810-9dad-11d1-80b4-00c04fd430c8",
"pipeline_status": "interview"
}/api/v1/candidates/:id/notesList all notes/comments on a candidate.
Paramètres
idstring— Candidate (analysis) UUIDRéponse
{
"notes": [
{
"id": "note_abc123",
"content": "Excellent entretien technique. À revoir pour l'offre.",
"author_name": "Marie Dupont",
"created_at": "2026-03-05T14:00:00Z",
"updated_at": "2026-03-05T14:00:00Z"
}
]
}/api/v1/candidates/:id/notesAdd a note to a candidate.
Paramètres
idstring— Candidate (analysis) UUIDcontentstring (required)— Note content (max 5000 chars)author_namestring— Author name (default: "API")Corps de la requête
{
"content": "Disponible pour un entretien la semaine prochaine.",
"author_name": "Jean Martin"
}Réponse
// 201 Created
{
"note": {
"id": "note_def456",
"content": "Disponible pour un entretien la semaine prochaine.",
"author_name": "Jean Martin",
"created_at": "2026-03-10T16:00:00Z"
}
}Webhooks
Signature HMAC-SHA256
Chaque requête webhook inclut un header X-Candidalyze-Signature contenant une signature HMAC-SHA256 du body, calculée avec votre secret. Le type d'événement est transmis via X-Candidalyze-Event.
const crypto = require('crypto');
// Headers: X-Candidalyze-Signature, X-Candidalyze-Event
function verifyWebhookSignature(body, signature, secret) {
const expected = crypto
.createHmac('sha256', secret)
.update(body)
.digest('hex');
return crypto.timingSafeEqual(
Buffer.from(signature),
Buffer.from(expected)
);
}Événements disponibles
| Événement | Description |
|---|---|
analysis.completed | Une analyse de CV est terminée |
analysis.failed | Une analyse de CV a échoué |
comparison.completed | Une comparaison multi-candidats est terminée |
interview_kit.ready | Un kit d'entretien est prêt |
Payload d'exemple
{
"event": "analysis.completed",
"timestamp": "2026-02-24T10:30:00Z",
"data": {
"id": "ana_abc123",
"status": "completed",
"overall_score": 82,
"candidate_name": "Alice Martin"
}
}Politique de retry
En cas d'échec (statut HTTP hors 2xx), le webhook est rejoué avec un backoff exponentiel. Après 10 échecs consécutifs, le webhook est automatiquement désactivé. Vous pouvez le supprimer et en recréer un pour le réactiver.
Codes d'erreur
| Code | Signification | Description |
|---|---|---|
400 | Bad Request | Paramètres manquants ou invalides |
401 | Unauthorized | Clé API manquante ou invalide |
402 | Payment Required | Crédits épuisés ou quota de comparaisons atteint |
403 | Forbidden | Scope insuffisant pour cette action |
404 | Not Found | Ressource introuvable |
429 | Too Many Requests | Rate limit dépassé, réessayez après le délai indiqué |
500 | Internal Server Error | Erreur serveur, contactez le support |
Format d'erreur
{
"error": "Invalid API key",
"code": "INVALID_KEY",
"status": 401
}Plans et limites
| Fonctionnalité | Cabinet | Enterprise |
|---|---|---|
| Clés API max | 5 | 5 |
| Webhooks max | 5 | 5 |
| Rate limit / min | 30 | 30 |
| Rate limit / jour | 1 000 | 1 000 |
| Scopes analyses | Oui | Oui |
| Scopes comparaisons | Oui | Oui |
| Scopes webhooks | Oui | Oui |
| ATS (positions, candidates, pipeline, notes) | Oui | Oui |
Créez un compte pour commencer à utiliser l'API.