Skip to content

Last update: October 15, 2026

Candidate Analyzer API

Local port (Docker Compose): 30003 | Repo: solyntek/djinn/services/djinn-candidate-analyzer

Decision support for recruitment: a deterministic, explainable and replayable scoring of candidates against a job posting. There is no LLM and no embeddings in the computation (ADR-028). The service ranks and explains; it never decides, never rejects.

Endpoints

Method Route Description
GET /health Health check (no authentication); returns version and scoring_version
POST /v1/analyze Score 1 candidate vs 1 job posting
POST /v1/analyze/batch Score 1 to 100 candidates, results sorted by score (best first)
POST /v1/analyze/competency-file Score a competency file (plain text, max 500,000 characters): the job's terms found in the text become the skills
POST /v1/hr/analyses/{analysis_id}/decisions Record the human decision taken on an analysis (201)
POST /v1/hr/subjects/ref Pseudonymous references of a candidate, one per month (rate limited to 10/min)
PUT /v1/hr/settings Journal retention and per-client emergency stop

Scoring (5 dimensions)

Dimension Default weight Method
Skills 0.30 Whole-token matching of required_skills / preferred_skills (80% / 20% when both are set)
Experience 0.25 Months of experience (overlapping positions counted once) vs min_experience_years; not evaluated without min_experience_years
Education 0.15 required_education found in a diploma's degree or field of study
Languages 0.15 required_languages found among the candidate's languages
Location 0.15 Candidate location vs job location and remote_policy; not evaluated without job location, if remote_policy is remote, or if anonymize is true

Weights (weights, optional) must sum to 1.0. They are renormalised over the evaluated dimensions only. Matching ignores case and accents, folds French gendered forms and keeps symbol names (C, C++, C#, .NET, R, Go, F#) exact: java does not match javascript.

The overall score is between 0 and 1; fit_level is excellent (>= 0.8), good (>= 0.6), moderate (>= 0.4) or weak.

Request options (the three analysis routes)

Field Default Description
weights 0.30 / 0.25 / 0.15 / 0.15 / 0.15 Weights per dimension, sum = 1.0
anonymize false Removes the location for the whole request; the location dimension is then not evaluated
as_of today (UTC) Reference date of the experience computation, returned in the response
lang fr Language of the explanation (fr or en)

candidate.id is the candidate's identifier on your side: use an opaque value (neither an e-mail nor a sequential integer). It is pseudonymised before being journaled. firstname, lastname, email, phone, linkedin and raw_text are deprecated: accepted so that doc-extract's resume output can be sent as is, but ignored, never journaled, and listed in minimization.ignored_fields.

What the response contains

analysis_id, scoring_version, notice_version, as_of, overall_score, fit_level, weights_used, one entry per dimension (score, applied weight, evaluated, evidence.matched / evidence.missing, rationale rendered from a versioned template, template_id), proxy_criteria (location and/or education when they weighed on the score), human_review_required (always true), explanation, minimization, strengths, gaps, summary. The same input, the same scoring_version and the same as_of always give the same score.

Human decision, contestation and emergency stop

  • POST /v1/hr/analyses/{analysis_id}/decisions: decision is shortlisted, not_retained, on_hold, review_requested (a candidate contests, GDPR art. 22(3)) or revised; reviewer_ref is an opaque identifier of the reviewer; supersedes is the decision_id replaced. The response gives decision_id, agrees_with_score (computed by the server) and seconds_since_scoring.
  • POST /v1/hr/subjects/ref with {"subject_id": "<candidate.id>"} returns the pseudonymous subject_ref of each month whose key still exists. It is the input of audit-trail's POST /v1/gdpr/export (subject_type: "resource_id") to answer an access request.
  • PUT /v1/hr/settings: retention_months (6 to 60, default 6) and scoring_enabled. false is the emergency stop: the analysis routes answer 423. Lowering the retention purges immediately; raising it does not bring destroyed keys back.

Scores and decisions are written to the audit trail without identity data. Retention works by destroying the monthly pseudonymisation keys: after that, references can no longer be linked on Djinn's side (this is not an anonymisation in the GDPR sense).

Errors

Errors of this service use {"detail": {"code": "...", "message": "..."}}:

HTTP code Meaning
404 analysis_not_found Analysis unknown, purged, or belonging to another client
422 no_evaluable_criteria The job and the weights leave no evaluable dimension: set at least one criterion with a positive weight
422 (validation) Invalid request (weights not summing to 1.0, unknown remote_policy, more than 100 candidates...)
423 scoring_disabled Emergency stop active for this client
500 audit emission failed: nothing was written, retry
503 Database not configured

Notice and limits (ADR-028)

Recruitment is a high-risk use under the EU AI Act (Annex III, 4(a)). Djinn is the provider, you are the deployer; using the service for another purpose makes you a provider (art. 25). notice_version identifies the usage notice (art. 13) that describes the scoring returned with each analysis. In particular:

  • Decision support only: every analysis requires a human review (human_review_required: true). Do not use the score as an automated decision.
  • Lexical matching: the candidate's skills list can be inflated; there is no evaluation of personality or soft skills.
  • Indirect criteria: location and education stay configurable and are reported in proxy_criteria; a bias report is published for each scoring_version.
  • Accuracy is not measured in this version (a measurement plan exists).

Example

curl -X POST http://localhost:30003/v1/analyze \
  -H "X-API-Key: your-local-key" \
  -H "Content-Type: application/json" \
  -d '{
    "job": {"title": "Python Developer", "required_skills": ["Python", "FastAPI"]},
    "candidate": {"id": "cand-7f3a", "skills": ["Python", "FastAPI", "Docker"]},
    "lang": "en"
  }'
curl -X POST https://api.dev.djinn.solyntek.io/v1/analyze \
  -H "X-API-Key: your-api-key" \
  -H "Content-Type: application/json" \
  -d '{
    "job": {"title": "Python Developer", "required_skills": ["Python", "FastAPI"]},
    "candidate": {"id": "cand-7f3a", "skills": ["Python", "FastAPI", "Docker"]},
    "lang": "en"
  }'

Interactive reference

Generated on every build from the versioned spec openapi/candidate-analyzer-v1.json (ADR-011) — no route is documented by hand.

Djinn Candidate Analyzer 0.1.0

Aide à la décision de recrutement : scoring explicable, journalisé et minimisé (ADR-028)


Endpoints


GET /health

Health

Description

Health check, without authentication.

Responses

{
    "status": "string",
    "version": "string",
    "scoring_version": "string"
}
⚠️ This example has been generated automatically from the schema and it is not accurate. Refer to the schema for more information.

Schema of the response body
{
    "properties": {
        "status": {
            "type": "string",
            "title": "Status",
            "default": "ok"
        },
        "version": {
            "type": "string",
            "title": "Version",
            "default": "0.1.0"
        },
        "scoring_version": {
            "type": "string",
            "title": "Scoring Version",
            "default": "2026.10.1"
        }
    },
    "type": "object",
    "title": "HealthResponse",
    "description": "Response for health check."
}

POST /v1/analyze

Analyze

Description

Score one candidate against one job: decision support, never a rejection.

Input parameters

Parameter In Type Default Nullable Description
X-API-Key header No

Request body

{
    "weights": {
        "skills": 10.12,
        "experience": 10.12,
        "education": 10.12,
        "languages": 10.12,
        "location": 10.12
    },
    "anonymize": true,
    "as_of": null,
    "lang": "fr",
    "job": {
        "title": "string",
        "description": "string",
        "required_skills": [
            "string"
        ],
        "preferred_skills": [
            "string"
        ],
        "min_experience_years": null,
        "required_languages": [
            "string"
        ],
        "required_education": null,
        "location": null,
        "remote_policy": null
    },
    "candidate": {
        "id": null,
        "firstname": null,
        "lastname": null,
        "email": null,
        "phone": null,
        "linkedin": null,
        "raw_text": null,
        "skills": [
            "string"
        ],
        "languages": [
            "string"
        ],
        "experiences": [
            {
                "company": "string",
                "title": "string",
                "location": "string",
                "start_date": "string",
                "end_date": "string",
                "description": "string"
            }
        ],
        "diplomas": [
            {
                "school": "string",
                "degree": "string",
                "field_of_study": "string",
                "start_date": "string",
                "end_date": "string"
            }
        ],
        "certifications": [
            {}
        ],
        "location": null
    }
}
⚠️ This example has been generated automatically from the schema and it is not accurate. Refer to the schema for more information.

Schema of the request body
{
    "properties": {
        "weights": {
            "$ref": "#/components/schemas/ScoringWeights"
        },
        "anonymize": {
            "type": "boolean",
            "title": "Anonymize",
            "description": "Retire le lieu (profil et expériences) pour tout le lot ; la localisation n'est alors pas évaluée.",
            "default": false
        },
        "as_of": {
            "anyOf": [
                {
                    "type": "string",
                    "format": "date"
                },
                {
                    "type": "null"
                }
            ],
            "title": "As Of",
            "description": "Date de référence du calcul de l'expérience ; défaut : date du jour (UTC), renvoyée dans l'analyse."
        },
        "lang": {
            "type": "string",
            "enum": [
                "fr",
                "en"
            ],
            "title": "Lang",
            "description": "Langue de l'explication.",
            "default": "fr"
        },
        "job": {
            "$ref": "#/components/schemas/JobDescription"
        },
        "candidate": {
            "$ref": "#/components/schemas/CandidateProfile"
        }
    },
    "type": "object",
    "required": [
        "job",
        "candidate"
    ],
    "title": "AnalyzeRequest",
    "description": "Requête d'analyse d'un candidat."
}

Responses

{
    "analysis_id": "5f9ff6d7-ec30-4f02-bd3f-56e3886e85aa",
    "candidate_id": null,
    "scoring_version": "string",
    "notice_version": "string",
    "as_of": "2022-04-13",
    "overall_score": 10.12,
    "fit_level": "excellent",
    "weights_used": {},
    "dimension_scores": [
        {
            "dimension": "skills",
            "score": 10.12,
            "weight": 10.12,
            "evaluated": true,
            "evidence": {
                "matched": [
                    "string"
                ],
                "missing": [
                    "string"
                ]
            },
            "rationale": "string",
            "template_id": "string",
            "details": "string"
        }
    ],
    "proxy_criteria": [
        "location"
    ],
    "human_review_required": true,
    "explanation": [
        "string"
    ],
    "minimization": {
        "ignored_fields": [
            "string"
        ],
        "dimensions_not_evaluated": [
            "string"
        ]
    },
    "strengths": [
        "string"
    ],
    "gaps": [
        "string"
    ],
    "summary": "string"
}
⚠️ This example has been generated automatically from the schema and it is not accurate. Refer to the schema for more information.

Schema of the response body
{
    "properties": {
        "analysis_id": {
            "type": "string",
            "format": "uuid",
            "title": "Analysis Id"
        },
        "candidate_id": {
            "anyOf": [
                {
                    "type": "string"
                },
                {
                    "type": "null"
                }
            ],
            "title": "Candidate Id"
        },
        "scoring_version": {
            "type": "string",
            "title": "Scoring Version"
        },
        "notice_version": {
            "type": "string",
            "title": "Notice Version"
        },
        "as_of": {
            "type": "string",
            "format": "date",
            "title": "As Of"
        },
        "overall_score": {
            "type": "number",
            "maximum": 1.0,
            "minimum": 0.0,
            "title": "Overall Score"
        },
        "fit_level": {
            "type": "string",
            "enum": [
                "excellent",
                "good",
                "moderate",
                "weak"
            ],
            "title": "Fit Level"
        },
        "weights_used": {
            "additionalProperties": {
                "type": "number"
            },
            "propertyNames": {
                "enum": [
                    "skills",
                    "experience",
                    "education",
                    "languages",
                    "location"
                ]
            },
            "type": "object",
            "title": "Weights Used"
        },
        "dimension_scores": {
            "items": {
                "$ref": "#/components/schemas/DimensionScore"
            },
            "type": "array",
            "title": "Dimension Scores"
        },
        "proxy_criteria": {
            "items": {
                "type": "string",
                "enum": [
                    "location",
                    "education"
                ]
            },
            "type": "array",
            "title": "Proxy Criteria",
            "description": "Critères indirects (lieu, formation) qui ont pesé : poids > 0 et dimension évaluée."
        },
        "human_review_required": {
            "type": "boolean",
            "const": true,
            "title": "Human Review Required",
            "default": true
        },
        "explanation": {
            "items": {
                "type": "string"
            },
            "type": "array",
            "title": "Explanation"
        },
        "minimization": {
            "$ref": "#/components/schemas/MinimizationReport"
        },
        "strengths": {
            "items": {
                "type": "string"
            },
            "type": "array",
            "title": "Strengths"
        },
        "gaps": {
            "items": {
                "type": "string"
            },
            "type": "array",
            "title": "Gaps"
        },
        "summary": {
            "type": "string",
            "title": "Summary",
            "default": ""
        }
    },
    "type": "object",
    "required": [
        "analysis_id",
        "scoring_version",
        "notice_version",
        "as_of",
        "overall_score",
        "fit_level",
        "weights_used",
        "dimension_scores",
        "explanation",
        "minimization"
    ],
    "title": "CandidateAnalysis",
    "description": "Analyse d'un candidat : aide à la décision, jamais un rejet."
}

POST /v1/analyze/batch

Analyze Batch

Description

Score up to 100 candidates against one job, best first.

Input parameters

Parameter In Type Default Nullable Description
X-API-Key header No

Request body

{
    "weights": {
        "skills": 10.12,
        "experience": 10.12,
        "education": 10.12,
        "languages": 10.12,
        "location": 10.12
    },
    "anonymize": true,
    "as_of": null,
    "lang": "fr",
    "job": {
        "title": "string",
        "description": "string",
        "required_skills": [
            "string"
        ],
        "preferred_skills": [
            "string"
        ],
        "min_experience_years": null,
        "required_languages": [
            "string"
        ],
        "required_education": null,
        "location": null,
        "remote_policy": null
    },
    "candidates": [
        {
            "id": null,
            "firstname": null,
            "lastname": null,
            "email": null,
            "phone": null,
            "linkedin": null,
            "raw_text": null,
            "skills": [
                "string"
            ],
            "languages": [
                "string"
            ],
            "experiences": [
                {
                    "company": "string",
                    "title": "string",
                    "location": "string",
                    "start_date": "string",
                    "end_date": "string",
                    "description": "string"
                }
            ],
            "diplomas": [
                {
                    "school": "string",
                    "degree": "string",
                    "field_of_study": "string",
                    "start_date": "string",
                    "end_date": "string"
                }
            ],
            "certifications": [
                {}
            ],
            "location": null
        }
    ]
}
⚠️ This example has been generated automatically from the schema and it is not accurate. Refer to the schema for more information.

Schema of the request body
{
    "properties": {
        "weights": {
            "$ref": "#/components/schemas/ScoringWeights"
        },
        "anonymize": {
            "type": "boolean",
            "title": "Anonymize",
            "description": "Retire le lieu (profil et expériences) pour tout le lot ; la localisation n'est alors pas évaluée.",
            "default": false
        },
        "as_of": {
            "anyOf": [
                {
                    "type": "string",
                    "format": "date"
                },
                {
                    "type": "null"
                }
            ],
            "title": "As Of",
            "description": "Date de référence du calcul de l'expérience ; défaut : date du jour (UTC), renvoyée dans l'analyse."
        },
        "lang": {
            "type": "string",
            "enum": [
                "fr",
                "en"
            ],
            "title": "Lang",
            "description": "Langue de l'explication.",
            "default": "fr"
        },
        "job": {
            "$ref": "#/components/schemas/JobDescription"
        },
        "candidates": {
            "items": {
                "$ref": "#/components/schemas/CandidateProfile"
            },
            "type": "array",
            "maxItems": 100,
            "minItems": 1,
            "title": "Candidates"
        }
    },
    "type": "object",
    "required": [
        "job",
        "candidates"
    ],
    "title": "AnalyzeBatchRequest",
    "description": "Requête d'analyse de plusieurs candidats (100 au plus)."
}

Responses

{
    "job_title": "string",
    "candidates": [
        {
            "analysis_id": "baf22809-01d5-4539-bb54-d85d858e6d5f",
            "candidate_id": null,
            "scoring_version": "string",
            "notice_version": "string",
            "as_of": "2022-04-13",
            "overall_score": 10.12,
            "fit_level": "excellent",
            "weights_used": {},
            "dimension_scores": [
                {
                    "dimension": "skills",
                    "score": 10.12,
                    "weight": 10.12,
                    "evaluated": true,
                    "evidence": {
                        "matched": [
                            "string"
                        ],
                        "missing": [
                            "string"
                        ]
                    },
                    "rationale": "string",
                    "template_id": "string",
                    "details": "string"
                }
            ],
            "proxy_criteria": [
                "location"
            ],
            "human_review_required": true,
            "explanation": [
                "string"
            ],
            "minimization": {
                "ignored_fields": [
                    "string"
                ],
                "dimensions_not_evaluated": [
                    "string"
                ]
            },
            "strengths": [
                "string"
            ],
            "gaps": [
                "string"
            ],
            "summary": "string"
        }
    ],
    "total_analyzed": 0
}
⚠️ This example has been generated automatically from the schema and it is not accurate. Refer to the schema for more information.

Schema of the response body
{
    "properties": {
        "job_title": {
            "type": "string",
            "title": "Job Title"
        },
        "candidates": {
            "items": {
                "$ref": "#/components/schemas/CandidateAnalysis"
            },
            "type": "array",
            "title": "Candidates"
        },
        "total_analyzed": {
            "type": "integer",
            "title": "Total Analyzed"
        }
    },
    "type": "object",
    "required": [
        "job_title",
        "candidates",
        "total_analyzed"
    ],
    "title": "AnalyzeBatchResponse",
    "description": "Réponse d'analyse batch (triée par score décroissant)."
}

POST /v1/analyze/competency-file

Analyze Competency File

Description

Score a competency file: the job's terms found in the text become the skills.

The text is read once and never stored or journaled; the other dimensions have no input, so those the job sets a criterion for are evaluated with nothing found.

Input parameters

Parameter In Type Default Nullable Description
X-API-Key header No

Request body

{
    "weights": {
        "skills": 10.12,
        "experience": 10.12,
        "education": 10.12,
        "languages": 10.12,
        "location": 10.12
    },
    "anonymize": true,
    "as_of": null,
    "lang": "fr",
    "job": {
        "title": "string",
        "description": "string",
        "required_skills": [
            "string"
        ],
        "preferred_skills": [
            "string"
        ],
        "min_experience_years": null,
        "required_languages": [
            "string"
        ],
        "required_education": null,
        "location": null,
        "remote_policy": null
    },
    "competency_text": "string"
}
⚠️ This example has been generated automatically from the schema and it is not accurate. Refer to the schema for more information.

Schema of the request body
{
    "properties": {
        "weights": {
            "$ref": "#/components/schemas/ScoringWeights"
        },
        "anonymize": {
            "type": "boolean",
            "title": "Anonymize",
            "description": "Retire le lieu (profil et expériences) pour tout le lot ; la localisation n'est alors pas évaluée.",
            "default": false
        },
        "as_of": {
            "anyOf": [
                {
                    "type": "string",
                    "format": "date"
                },
                {
                    "type": "null"
                }
            ],
            "title": "As Of",
            "description": "Date de référence du calcul de l'expérience ; défaut : date du jour (UTC), renvoyée dans l'analyse."
        },
        "lang": {
            "type": "string",
            "enum": [
                "fr",
                "en"
            ],
            "title": "Lang",
            "description": "Langue de l'explication.",
            "default": "fr"
        },
        "job": {
            "$ref": "#/components/schemas/JobDescription"
        },
        "competency_text": {
            "type": "string",
            "maxLength": 500000,
            "minLength": 1,
            "title": "Competency Text"
        }
    },
    "type": "object",
    "required": [
        "job",
        "competency_text"
    ],
    "title": "CompetencyFileRequest",
    "description": "Requête d'analyse d'un dossier de compétences (texte brut, jamais journalisé)."
}

Responses

{
    "analysis_id": "b8fd886b-48f8-4457-aa3f-c5d9c56762d7",
    "candidate_id": null,
    "scoring_version": "string",
    "notice_version": "string",
    "as_of": "2022-04-13",
    "overall_score": 10.12,
    "fit_level": "excellent",
    "weights_used": {},
    "dimension_scores": [
        {
            "dimension": "skills",
            "score": 10.12,
            "weight": 10.12,
            "evaluated": true,
            "evidence": {
                "matched": [
                    "string"
                ],
                "missing": [
                    "string"
                ]
            },
            "rationale": "string",
            "template_id": "string",
            "details": "string"
        }
    ],
    "proxy_criteria": [
        "location"
    ],
    "human_review_required": true,
    "explanation": [
        "string"
    ],
    "minimization": {
        "ignored_fields": [
            "string"
        ],
        "dimensions_not_evaluated": [
            "string"
        ]
    },
    "strengths": [
        "string"
    ],
    "gaps": [
        "string"
    ],
    "summary": "string"
}
⚠️ This example has been generated automatically from the schema and it is not accurate. Refer to the schema for more information.

Schema of the response body
{
    "properties": {
        "analysis_id": {
            "type": "string",
            "format": "uuid",
            "title": "Analysis Id"
        },
        "candidate_id": {
            "anyOf": [
                {
                    "type": "string"
                },
                {
                    "type": "null"
                }
            ],
            "title": "Candidate Id"
        },
        "scoring_version": {
            "type": "string",
            "title": "Scoring Version"
        },
        "notice_version": {
            "type": "string",
            "title": "Notice Version"
        },
        "as_of": {
            "type": "string",
            "format": "date",
            "title": "As Of"
        },
        "overall_score": {
            "type": "number",
            "maximum": 1.0,
            "minimum": 0.0,
            "title": "Overall Score"
        },
        "fit_level": {
            "type": "string",
            "enum": [
                "excellent",
                "good",
                "moderate",
                "weak"
            ],
            "title": "Fit Level"
        },
        "weights_used": {
            "additionalProperties": {
                "type": "number"
            },
            "propertyNames": {
                "enum": [
                    "skills",
                    "experience",
                    "education",
                    "languages",
                    "location"
                ]
            },
            "type": "object",
            "title": "Weights Used"
        },
        "dimension_scores": {
            "items": {
                "$ref": "#/components/schemas/DimensionScore"
            },
            "type": "array",
            "title": "Dimension Scores"
        },
        "proxy_criteria": {
            "items": {
                "type": "string",
                "enum": [
                    "location",
                    "education"
                ]
            },
            "type": "array",
            "title": "Proxy Criteria",
            "description": "Critères indirects (lieu, formation) qui ont pesé : poids > 0 et dimension évaluée."
        },
        "human_review_required": {
            "type": "boolean",
            "const": true,
            "title": "Human Review Required",
            "default": true
        },
        "explanation": {
            "items": {
                "type": "string"
            },
            "type": "array",
            "title": "Explanation"
        },
        "minimization": {
            "$ref": "#/components/schemas/MinimizationReport"
        },
        "strengths": {
            "items": {
                "type": "string"
            },
            "type": "array",
            "title": "Strengths"
        },
        "gaps": {
            "items": {
                "type": "string"
            },
            "type": "array",
            "title": "Gaps"
        },
        "summary": {
            "type": "string",
            "title": "Summary",
            "default": ""
        }
    },
    "type": "object",
    "required": [
        "analysis_id",
        "scoring_version",
        "notice_version",
        "as_of",
        "overall_score",
        "fit_level",
        "weights_used",
        "dimension_scores",
        "explanation",
        "minimization"
    ],
    "title": "CandidateAnalysis",
    "description": "Analyse d'un candidat : aide à la décision, jamais un rejet."
}

POST /v1/hr/analyses/{analysis_id}/decisions

Record Decision

Description

Journal a human decision; agreement with the score is computed here.

review_requested records a contest (GDPR art. 22(3)), revised the new review; supersedes names the decision_id it replaces. Unknown, purged and other tenants' analyses answer the same 404.

Input parameters

Parameter In Type Default Nullable Description
analysis_id path string No
X-API-Key header No

Request body

{
    "decision": "shortlisted",
    "reviewer_ref": "string",
    "supersedes": null
}
⚠️ This example has been generated automatically from the schema and it is not accurate. Refer to the schema for more information.

Schema of the request body
{
    "properties": {
        "decision": {
            "type": "string",
            "enum": [
                "shortlisted",
                "not_retained",
                "on_hold",
                "review_requested",
                "revised"
            ],
            "title": "Decision"
        },
        "reviewer_ref": {
            "type": "string",
            "maxLength": 200,
            "minLength": 1,
            "title": "Reviewer Ref",
            "description": "Identifiant opaque du relecteur chez le client ; pseudonymisé avant journalisation."
        },
        "supersedes": {
            "anyOf": [
                {
                    "type": "string",
                    "format": "uuid"
                },
                {
                    "type": "null"
                }
            ],
            "title": "Supersedes",
            "description": "`decision_id` de la décision remplacée."
        }
    },
    "type": "object",
    "required": [
        "decision",
        "reviewer_ref"
    ],
    "title": "DecisionRequest",
    "description": "Décision humaine sur une analyse (spec §4.3)."
}

Responses

{
    "decision_id": "9f38c517-dbc5-4973-93eb-f420e5e7e887",
    "agrees_with_score": true,
    "seconds_since_scoring": 0
}
⚠️ This example has been generated automatically from the schema and it is not accurate. Refer to the schema for more information.

Schema of the response body
{
    "properties": {
        "decision_id": {
            "type": "string",
            "format": "uuid",
            "title": "Decision Id"
        },
        "agrees_with_score": {
            "type": "boolean",
            "title": "Agrees With Score"
        },
        "seconds_since_scoring": {
            "type": "integer",
            "title": "Seconds Since Scoring"
        }
    },
    "type": "object",
    "required": [
        "decision_id",
        "agrees_with_score",
        "seconds_since_scoring"
    ],
    "title": "DecisionResponse"
}

{
    "detail": [
        {
            "loc": [
                null
            ],
            "msg": "string",
            "type": "string",
            "input": null,
            "ctx": {}
        }
    ]
}
⚠️ This example has been generated automatically from the schema and it is not accurate. Refer to the schema for more information.

Schema of the response body
{
    "properties": {
        "detail": {
            "items": {
                "$ref": "#/components/schemas/ValidationError"
            },
            "type": "array",
            "title": "Detail"
        }
    },
    "type": "object",
    "title": "HTTPValidationError"
}

POST /v1/hr/subjects/ref

Subject Refs

Description

Pseudonymous reference of a candidate, one per month whose key still exists.

Input of audit-trail's POST /v1/gdpr/export (subject_type="resource_id"). Each reference returned is journaled; Kong rate-limits this route harder.

Input parameters

Parameter In Type Default Nullable Description
X-API-Key header No

Request body

{
    "subject_id": "string"
}
⚠️ This example has been generated automatically from the schema and it is not accurate. Refer to the schema for more information.

Schema of the request body
{
    "properties": {
        "subject_id": {
            "type": "string",
            "maxLength": 200,
            "minLength": 1,
            "title": "Subject Id",
            "description": "Le `CandidateProfile.id` des analyses."
        }
    },
    "type": "object",
    "required": [
        "subject_id"
    ],
    "title": "SubjectRefRequest"
}

Responses

{
    "subject_refs": [
        {
            "period": "string",
            "subject_ref": "string"
        }
    ]
}
⚠️ This example has been generated automatically from the schema and it is not accurate. Refer to the schema for more information.

Schema of the response body
{
    "properties": {
        "subject_refs": {
            "items": {
                "$ref": "#/components/schemas/SubjectRef"
            },
            "type": "array",
            "title": "Subject Refs"
        }
    },
    "type": "object",
    "required": [
        "subject_refs"
    ],
    "title": "SubjectRefResponse"
}

{
    "detail": [
        {
            "loc": [
                null
            ],
            "msg": "string",
            "type": "string",
            "input": null,
            "ctx": {}
        }
    ]
}
⚠️ This example has been generated automatically from the schema and it is not accurate. Refer to the schema for more information.

Schema of the response body
{
    "properties": {
        "detail": {
            "items": {
                "$ref": "#/components/schemas/ValidationError"
            },
            "type": "array",
            "title": "Detail"
        }
    },
    "type": "object",
    "title": "HTTPValidationError"
}

PUT /v1/hr/settings

Put Settings

Description

Retention (6 to 60 months) and the per-tenant emergency stop, journaled.

Lowering the retention purges in the same transaction; raising it does not bring destroyed keys back.

Input parameters

Parameter In Type Default Nullable Description
X-API-Key header No

Request body

{
    "retention_months": 0,
    "scoring_enabled": true
}
⚠️ This example has been generated automatically from the schema and it is not accurate. Refer to the schema for more information.

Schema of the request body
{
    "properties": {
        "retention_months": {
            "type": "integer",
            "maximum": 60.0,
            "minimum": 6.0,
            "title": "Retention Months",
            "description": "Conservation du journal RH, en mois (6 à 60)."
        },
        "scoring_enabled": {
            "type": "boolean",
            "title": "Scoring Enabled",
            "description": "false = arrêt d'urgence : les routes d'analyse répondent 423."
        }
    },
    "type": "object",
    "required": [
        "retention_months",
        "scoring_enabled"
    ],
    "title": "HrSettingsUpdate"
}

Responses

{
    "retention_months": 0,
    "scoring_enabled": true
}
⚠️ This example has been generated automatically from the schema and it is not accurate. Refer to the schema for more information.

Schema of the response body
{
    "properties": {
        "retention_months": {
            "type": "integer",
            "maximum": 60.0,
            "minimum": 6.0,
            "title": "Retention Months",
            "default": 6
        },
        "scoring_enabled": {
            "type": "boolean",
            "title": "Scoring Enabled",
            "default": true
        }
    },
    "type": "object",
    "title": "HrSettings"
}

{
    "detail": [
        {
            "loc": [
                null
            ],
            "msg": "string",
            "type": "string",
            "input": null,
            "ctx": {}
        }
    ]
}
⚠️ This example has been generated automatically from the schema and it is not accurate. Refer to the schema for more information.

Schema of the response body
{
    "properties": {
        "detail": {
            "items": {
                "$ref": "#/components/schemas/ValidationError"
            },
            "type": "array",
            "title": "Detail"
        }
    },
    "type": "object",
    "title": "HTTPValidationError"
}

Schemas

AnalyzeBatchRequest

Name Type Description
anonymize boolean Retire le lieu (profil et expériences) pour tout le lot ; la localisation n'est alors pas évaluée.
as_of Date de référence du calcul de l'expérience ; défaut : date du jour (UTC), renvoyée dans l'analyse.
candidates Array<CandidateProfile>
job JobDescription
lang string Langue de l'explication.
weights ScoringWeights

AnalyzeBatchResponse

Name Type Description
candidates Array<CandidateAnalysis>
job_title string
total_analyzed integer

AnalyzeRequest

Name Type Description
anonymize boolean Retire le lieu (profil et expériences) pour tout le lot ; la localisation n'est alors pas évaluée.
as_of Date de référence du calcul de l'expérience ; défaut : date du jour (UTC), renvoyée dans l'analyse.
candidate CandidateProfile
job JobDescription
lang string Langue de l'explication.
weights ScoringWeights

CandidateAnalysis

Name Type Description
analysis_id string(uuid)
as_of string(date)
candidate_id
dimension_scores Array<DimensionScore>
explanation Array<string>
fit_level string
gaps Array<string>
human_review_required boolean
minimization MinimizationReport
notice_version string
overall_score number
proxy_criteria Array<string> Critères indirects (lieu, formation) qui ont pesé : poids > 0 et dimension évaluée.
scoring_version string
strengths Array<string>
summary string
weights_used

CandidateProfile

Name Type Description
certifications Array<>
diplomas Array<Diploma>
email Ignoré (minimisation), jamais journalisé ; déprécié.
experiences Array<Experience>
firstname Ignoré (minimisation), jamais journalisé ; déprécié.
id Identifiant opaque du candidat chez le client (ni e-mail, ni entier séquentiel). Pseudonymisé avant journalisation.
languages Array<string>
lastname Ignoré (minimisation), jamais journalisé ; déprécié.
linkedin Ignoré (minimisation), jamais journalisé ; déprécié.
location
phone Ignoré (minimisation), jamais journalisé ; déprécié.
raw_text Ignoré (minimisation), jamais journalisé ; déprécié.
skills Array<string>

CompetencyFileRequest

Name Type Description
anonymize boolean Retire le lieu (profil et expériences) pour tout le lot ; la localisation n'est alors pas évaluée.
as_of Date de référence du calcul de l'expérience ; défaut : date du jour (UTC), renvoyée dans l'analyse.
competency_text string
job JobDescription
lang string Langue de l'explication.
weights ScoringWeights

DecisionRequest

Name Type Description
decision string
reviewer_ref string Identifiant opaque du relecteur chez le client ; pseudonymisé avant journalisation.
supersedes `decision_id` de la décision remplacée.

DecisionResponse

Name Type Description
agrees_with_score boolean
decision_id string(uuid)
seconds_since_scoring integer

DimensionScore

Name Type Description
details string Déprécié : reprend `rationale`.
dimension string
evaluated boolean
evidence Evidence
rationale string
score number
template_id string
weight number Poids appliqué, après renormalisation sur les dimensions évaluées.

Diploma

Name Type Description
degree string
end_date string
field_of_study string
school string
start_date string

Evidence

Name Type Description
matched Array<string>
missing Array<string>

Experience

Name Type Description
company string
description string
end_date string Même format ; vide, « present » ou « en cours » pour un poste en cours.
location string
start_date string AAAA ou AAAA-MM : premier jour du mois (janvier si l'année seule).
title string

HealthResponse

Name Type Description
scoring_version string
status string
version string

HrSettings

Name Type Description
retention_months integer
scoring_enabled boolean

HrSettingsUpdate

Name Type Description
retention_months integer Conservation du journal RH, en mois (6 à 60).
scoring_enabled boolean false = arrêt d'urgence : les routes d'analyse répondent 423.

HTTPValidationError

Name Type Description
detail Array<ValidationError>

JobDescription

Name Type Description
description string
location
min_experience_years
preferred_skills Array<string>
remote_policy onsite | hybrid | remote. Common aliases (e.g. full-remote, télétravail, hybride, présentiel) are normalised; any other value is refused (422). remote: the location dimension is not evaluated.
required_education
required_languages Array<string>
required_skills Array<string>
title string

MinimizationReport

Name Type Description
dimensions_not_evaluated Array<string> Processing dimensions skipped because of that minimisation.
ignored_fields Array<string> Input paths received then dropped before processing (e.g. `email`, `experiences[].location`).

ScoringWeights

Name Type Description
education number
experience number
languages number
location number
skills number

SubjectRef

Name Type Description
period string Mois de la clé, AAAA-MM.
subject_ref string

SubjectRefRequest

Name Type Description
subject_id string Le `CandidateProfile.id` des analyses.

SubjectRefResponse

Name Type Description
subject_refs Array<SubjectRef>

ValidationError

Name Type Description
ctx
input
loc Array<>
msg string
type string