API Reference

CVReader API

Parse CVs, match candidates to jobs, and generate branded PDFs — all via REST endpoints authenticated with your ApiKey.

Base URL: https://cvreader.fr
Auth: Authorization: ApiKey <key>

Documentation API CVReaderPro

Automatisez l'analyse, l'appariement et la génération de CV pour un recrutement efficace et conforme au RGPD.

Fonctionnalités clés

FonctionnalitéDescriptionMéthode de livraison
Analyse de CV (Parsing)Extraire des données structurées (compétences, expérience, éducation, etc.) à partir d'un CV.Synchrone (Réponse API)
Appariement CV/Offre d'EmploiComparez les CVs avec vos offres d'emploi pour trouver les meilleurs candidats.API ou Webhook
Génération de CVGénérez des CVs standard ou anonymisés selon le modèle de votre entreprise.Webhook ou Email

1. Analyse de CV (Parsing)

Extraire des données structurées à partir de fichiers CV (PDF, DOCX, etc.).

POSThttps://cvreader.fr/api/v1/parser

Headers

http
Authorization: ApiKey YOUR_API_KEY
Accept: application/json  (default) | application/xml

Body (multipart/form-data)

  • file : Fichier CV (PDF, DOCX, TXT, etc.)
  • parserType : "ADVANCED" (56 champs) ou "PREMIUM" (96 champs, recommandé)

Exemple cURL

bash
curl -X POST https://cvreader.fr/api/v1/parser \
  -H "Authorization: ApiKey YOUR_API_KEY" \
  -F "file=@/path/to/cv.pdf" \
  -F "parserType=PREMIUM"

Réponse (extrait)

json
{
  "resumeId": "c8cd44a0-d765-4d47-ba04-67903ef650e5",
  "documentType": "CV",
  "documentLanguage": "FR",
  "candidate": { "firstName": "Jean", "lastName": "Dupont" },
  "experiences": [],
  "educations": [],
  "skills": [],
  ...
}

Mise à jour et suppression d'un CV analysé

PUT/api/v1/parser/{resumeId}

Met à jour les données d'un CV existant.

DELETE/api/v1/parser/{resumeId}

Supprime un CV analysé.

Async Parser (Parsing asynchrone)

Soumettez un CV pour traitement asynchrone. Les résultats sont envoyés à votre webhook.

POST/api/v1/parser/async

PrérequisConfigurez l'URL de votre webhook dans l'application.

Exemple

bash
curl -X POST https://cvreader.fr/api/v1/parser/async \
  -H "Authorization: ApiKey YOUR_API_KEY" \
  -F "file=@cv.pdf" \
  -F "parserType=PREMIUM"

Réponse immédiate :

json
{ "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08" }

Webhook (implémentation client)

Votre endpoint doit recevoir une requête POST avec le résultat. Vérifiez la signature HMAC-SHA256 avec votre secret.

http
POST /webhook/parser-results
Headers: X-Webhook-Signature: <hmac-sha256>
Body: { "id": "...", "status": "SUCCESS", "resumeData": { ... } }

2. API Offres d'Emploi (Jobs)

Fournissez une API qui retourne vos offres au format JobItem.

GET/api/jobs

(implémenté par le client)

Doit retourner un tableau d'objets :

json
[
  {
    "title": "Senior Software Engineer",
    "reference": "JOB-2023-456",
    "description": "...",
    "company": "TechCorp",
    "country": "FR",
    "city": "Paris"
  }
]

Enregistrez l'URL de votre endpoint dans CVReaderPro (Paramètres → Intégrations API).

POST

Parse job from file

POST/api/job/parse/api-key

Uploads a job description file (PDF, DOCX, etc.) and returns a structured Job object. The file is parsed server-side and the result is persisted and linked to the authenticated user.

Headers

http
Authorization: ApiKey YOUR_API_KEY
Content-Type: multipart/form-data

Request body multipart/form-data

FieldTypeDescription
file*FileThe job description file to parse (PDF, DOCX, TXT…)

Request example

curl -X POST "https://cvreader.fr/api/job/parse/api-key" \
  -H "Authorization: ApiKey YOUR_API_KEY" \
  -F "file=@/path/to/job_description.pdf"

Response 200 OK

FieldTypeDescription
id*UUIDUnique job identifier
titlestringParsed job title
descriptionstringFull job description text
profilestringRequired candidate profile
experiencestringRequired experience level
educationstringRequired education level
skillsstring (JSON)JSON-encoded array of required skills
companystringCompany name (if detected)
countrystringCountry code (e.g. "FR")
citystringCity name (if detected)
json
{
  "id": "d4c7a1e2-0f3b-4c8d-9e1f-000000000001",
  "title": "Senior Software Engineer",
  "description": "We are looking for...",
  "profile": "Experienced developer with leadership skills",
  "experience": "5+ years",
  "education": "Bachelor's degree",
  "skills": "[\"Java\",\"Spring Boot\",\"Docker\"]",
  "company": "TechCorp",
  "country": "FR",
  "city": "Paris"
}

Error responses

StatusDescription
401Invalid or missing ApiKey
400No file provided or unsupported file format
500Failed to parse job file
POST

Parse job from text

POST/api/job/parse/text/api-key

Parses a raw job description string and returns a structured DTO without creating a file upload. The body can be a plain JSON string, a quoted string, or a JSON object with a description, job_description, or text field — the API extracts the value automatically.

Headers

http
Authorization: ApiKey YOUR_API_KEY
Content-Type: application/json

Request body application/json

Send the job description as a JSON string, a raw string, or an object with a recognized field:

json
// Option A — plain JSON string
"We are looking for a Senior React Developer with 5+ years..."

// Option B — object with recognized field
{ "description": "We are looking for a Senior React Developer..." }

Request example

curl -X POST "https://cvreader.fr/api/job/parse/text/api-key" \
  -H "Authorization: ApiKey YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '"We are looking for a Senior React Developer with 5+ years of experience..."'

Response 200 OK

FieldTypeDescription
jobTitlestringParsed job title
jobDescriptionstringFull job description
profileRecherchestringRequired candidate profile
experienceRequiredstringRequired experience level
educationLevelstringRequired education level
skillsstring[]Array of required skills
json
{
  "jobTitle": "Senior React Developer",
  "jobDescription": "We are looking for a Senior React Developer...",
  "profileRecherche": "Experienced frontend engineer",
  "experienceRequired": "5+ years",
  "educationLevel": "Bachelor's degree",
  "skills": ["React", "TypeScript", "Node.js", "GraphQL"]
}

Error responses

StatusDescription
400Job description is required (empty or missing body)
401Invalid or missing ApiKey
500Failed to parse job description text
POST

Create a job

POST/api/jobs/api-key

Creates a new job record linked to the API key owner. The payload shape is the same as the authenticated frontend endpoint. Use this to push jobs from your own ATS or data pipeline.

Request body application/json

FieldTypeDescription
title*stringJob title
referencestringInternal job reference code (e.g. "JOB-2026-001")
descriptionstringFull job description text
profilestringRequired candidate profile narrative
experiencestringRequired experience level (e.g. "5+ years")
educationstringRequired education level (e.g. "Bachelor's degree")
skillsstring (JSON)JSON-encoded array of required skills
companystringCompany name
countrystringCountry code (e.g. "FR")
citystringCity name
statusstring"ACTIVE" | "CLOSED" | "DRAFT"

Request example

curl -X POST "https://cvreader.fr/api/jobs/api-key" \
  -H "Authorization: ApiKey YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "title": "Senior Java Developer",
    "reference": "JOB-2026-001",
    "description": "We are looking for a Senior Java Developer...",
    "profile": "Experienced backend engineer",
    "experience": "5+ years",
    "education": "Bachelor'"'"'s degree",
    "skills": "[\"Java\",\"Spring Boot\",\"Docker\"]",
    "company": "TechCorp",
    "country": "FR",
    "city": "Paris",
    "status": "ACTIVE"
  }'

Response 200 OK

Returns the created Job object (same shape as the parse file response).

json
{
  "id": "d4c7a1e2-0f3b-4c8d-9e1f-000000000001",
  "title": "Senior Java Developer",
  "reference": "JOB-2026-001",
  "status": "ACTIVE",
  "company": "TechCorp",
  "country": "FR",
  "city": "Paris"
}

Error responses

StatusDescription
400Invalid or missing required fields
401Invalid or missing ApiKey
GET

List my jobs

GET/api/jobs/api-key/my

Returns a paginated list of jobs belonging to the API key owner. Supports the same filtering options as the authenticated frontend list endpoint.

Query parameters

FieldTypeDescription
pageintegerZero-based page index (default: 0)
sizeintegerItems per page (default: 10)
statusstringFilter by job status: "ACTIVE" | "CLOSED" | "DRAFT"
sourcestringFilter by source (e.g. "api_key", "manual")
referencestringFilter by reference code (partial match)
titlestringFilter by title (partial match)
postedFromISO date-timeFilter jobs posted on or after this date
postedToISO date-timeFilter jobs posted on or before this date

Request example

# All active jobs, page 0, 10 per page
curl "https://cvreader.fr/api/jobs/api-key/my?page=0&size=10&status=ACTIVE" \
  -H "Authorization: ApiKey YOUR_API_KEY"

Response 200 OK

Paginated response — standard Spring Page structure:

json
{
  "content": [
    { "id": "d4c7a1e2-...", "title": "Senior Java Developer", "status": "ACTIVE", ... }
  ],
  "totalElements": 42,
  "totalPages": 5,
  "number": 0,
  "size": 10
}

Error responses

StatusDescription
401Invalid or missing ApiKey
GET

Get one job

GET/api/jobs/api-key/my/{jobId}

Retrieves a single job by ID. Ownership is enforced — only jobs belonging to the authenticated API key owner are returned.

Path parameters

FieldTypeDescription
jobId*UUIDUUID of the job to retrieve.

Request example

JOB_ID="d4c7a1e2-0f3b-4c8d-9e1f-000000000001"
curl "https://cvreader.fr/api/jobs/api-key/my/${JOB_ID}" \
  -H "Authorization: ApiKey YOUR_API_KEY"

Response 200 OK

Returns the full Job object.

Error responses

StatusDescription
401Invalid or missing ApiKey
403Job does not belong to the API key owner
404Job not found
PUT

Update a job

PUT/api/jobs/api-key/my/{jobId}

Replaces an existing job's data. The payload shape is the same as POST /api/jobs/api-key. Only fields present in the body are applied — omit fields you do not wish to change. Ownership is enforced.

Path parameters

FieldTypeDescription
jobId*UUIDUUID of the job to update.

Request body application/json

FieldTypeDescription
title*stringJob title
referencestringInternal job reference code (e.g. "JOB-2026-001")
descriptionstringFull job description text
profilestringRequired candidate profile narrative
experiencestringRequired experience level (e.g. "5+ years")
educationstringRequired education level (e.g. "Bachelor's degree")
skillsstring (JSON)JSON-encoded array of required skills
companystringCompany name
countrystringCountry code (e.g. "FR")
citystringCity name
statusstring"ACTIVE" | "CLOSED" | "DRAFT"

Request example

JOB_ID="d4c7a1e2-0f3b-4c8d-9e1f-000000000001"
curl -X PUT "https://cvreader.fr/api/jobs/api-key/my/${JOB_ID}" \
  -H "Authorization: ApiKey YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "title": "Lead Java Developer",
    "status": "ACTIVE",
    "city": "Lyon"
  }'

Response 200 OK

Returns the updated Job object.

Error responses

StatusDescription
400Invalid payload
401Invalid or missing ApiKey
403Job does not belong to the API key owner
404Job not found

3. API Score (Appariement)

Obtenir les scores d'un CV avec les offres

GET/api/scores/jobs-for-resume/{resumeId}

Retourne une liste de scores pour un CV donné.

json
[
  {
    "jobId": "e918ab2f-d2f8-4890-b2d6-b049a76207a9",
    "totalScore": 88.79
  }
]

Obtenir les CV correspondant à une offre

GET/api/scores/resumes-for-job/{jobReference}

Match direct (job vs CV)

POST/api/scores/match-job-resume/{resumeId}

Corps JSON avec les détails de l'offre.

File d'attente asynchrone

POST/api/jobs/queue

Soumettez une liste de références d'offres pour traitement. Résultats envoyés par webhook.

json
["offre-123", "offre-456"]

4. Génération de CV (standard ou anonymisé)

Générez des CVs au format PDF avec anonymisation optionnelle.

Authentication required

All endpoints below require an Authorization: ApiKey <YOUR_API_KEY> header. Missing or invalid keys return 401 Invalid Api Key.

Base path/api/resume-settings
PUT

Update settings + regenerate canvas

PUT/api/resume-settings/api-key/update-with-canvas

Replaces the authenticated user's resume settings and immediately regenerates canvas preview images. Returns the updated settings payload including refreshed canvas pages — ideal for updating the preview UI instantly after a settings change.

Request body application/json

FieldTypeDescription
layoutstringTemplate layout name (e.g. "modern", "classic")
fontStylestringFont family (e.g. "Calibri", "Arial")
fontSizenumberBase font size in pt (e.g. 11)
lineHeightnumberLine height multiplier (e.g. 1.35)
marginTopnumberTop page margin in mm
marginBottomnumberBottom page margin in mm
marginXnumberLeft/right page margin in mm
sectionSpacingnumberVertical spacing between sections in pt
agencyNamestringBranding: recruiter agency name (optional)
agencyWebsitestringBranding: recruiter agency URL (optional)

Request example

curl -X PUT "https://cvreader.fr/api/resume-settings/api-key/update-with-canvas" \
  -H "Authorization: ApiKey YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "layout": "modern",
    "fontStyle": "Calibri",
    "fontSize": 11,
    "lineHeight": 1.35,
    "marginTop": 20,
    "marginBottom": 18,
    "marginX": 18,
    "sectionSpacing": 10,
    "agencyName": "Acme Recruiting",
    "agencyWebsite": "https://acme.example"
  }'

Response 200 OK

Returns a ResumeSettingsResponseDto JSON object:

FieldTypeDescription
id*UUIDUnique settings record ID
layout*stringActive layout name
settings*objectFull settings object (font, margins, spacing, branding)
privacy*objectPrivacy/anonymization configuration
canvas_page_count*numberNumber of regenerated canvas preview pages
canvas_pages*arrayArray of { index: number, url: string } — public preview image URLs per page

Response example

json
{
  "id": "a3f4e2b1-0c91-4d2e-bc57-7f3a6e9d0012",
  "layout": "modern",
  "settings": {
    "fontStyle": "Calibri",
    "fontSize": 11,
    "lineHeight": 1.35,
    "marginTop": 20,
    "marginBottom": 18,
    "marginX": 18,
    "sectionSpacing": 10,
    "agencyName": "Acme Recruiting",
    "agencyWebsite": "https://acme.example"
  },
  "privacy": {
    "hidePhoto": false,
    "hideEmail": false,
    "hidePhone": false,
    "hideName": false
  },
  "canvas_page_count": 2,
  "canvas_pages": [
    { "index": 0, "url": "https://cdn.cvreader.fr/canvas/page_0.png" },
    { "index": 1, "url": "https://cdn.cvreader.fr/canvas/page_1.png" }
  ]
}

Error responses

StatusDescription
401Invalid or missing ApiKey
POST

Generate PDF by resume ID

POST/api/resume-settings/api-key/resumes/{resumeId}/generate-pdf

Generates a PDF for the given resumeId using the current settings of the ApiKey owner. Candidate ownership is enforced — the resume must belong to the authenticated user. Returns the PDF as binary bytes with Content-Type: application/pdf.

Path parameters

FieldTypeDescription
resumeId*UUIDUUID of the resume to render. Must belong to the authenticated ApiKey user.

Request example

# Replace RESUME_ID with a valid UUID
curl -X POST \
  "https://cvreader.fr/api/resume-settings/api-key/resumes/RESUME_ID/generate-pdf" \
  -H "Authorization: ApiKey YOUR_API_KEY" \
  --output resume.pdf

Response 200 OK

Header / FieldValue
Content-Typeapplication/pdf
Content-Dispositionattachment; filename="resume_{resumeId}.pdf"
BodyPDF binary stream
Frontend note: Use responseType: blob (Axios) or response.blob() (fetch). Save the blob as a .pdf file or open via URL.createObjectURL().

Error responses

StatusDescription
401Invalid or missing ApiKey
404Resume not found for this user
4xxNo credits remaining (NoMoreCreditException)
POST

Instant PDF generation (1–10)

POST/api/resume-settings/v1/generate-pdf

Synchronously generates up to 10 PDFs in a single blocking request. All PDFs are ready when the response arrives — download URLs are included directly in the body. For larger batches (1–500) use the async webhook endpoint below.

Limit: Maximum 10 resume IDs per request. For larger batches configure a webhook and use POST /api/webhook/generate-pdfs.

Request body application/json

FieldTypeDescription
resumeIds*UUID[]List of 1–10 resume UUIDs to generate PDFs for synchronously.

Request example

curl -X POST "https://cvreader.fr/api/resume-settings/v1/generate-pdf" \
  -H "Authorization: ApiKey YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '["9f6ad665-25ce-4107-8ec5-b2a2fba572cc", "a1b2c3d4-5678-90ab-cdef-000000000001"]'

Response 200 OK

FieldTypeDescription
jobId*UUIDInternal queue ID for this batch.
status*string"COMPLETED" | "PARTIAL" | "FAILED"
progress*stringPercentage of successfully processed PDFs (e.g. "100%").
results*arrayPer-resume result objects — each contains resumeId, downloadUrl, generatedAt, or an error field.
json
{
  "jobId": "b72e9a01-3f4c-4e12-9a1d-000000000001",
  "status": "COMPLETED",
  "progress": "100%",
  "results": [
    {
      "resumeId": "9f6ad665-25ce-4107-8ec5-b2a2fba572cc",
      "downloadUrl": "https://cdn.cvreader.fr/pdfs/resume_9f6ad665.pdf",
      "generatedAt": "2026-05-14T10:00:00Z"
    }
  ]
}

Error responses

StatusDescription
400No resume IDs provided, or more than 10 IDs in a single request
401Invalid or missing ApiKey
403One or more resume IDs do not belong to the current user
429Webhook delivery queue full, or no credits remaining
POST

Bulk async PDF generation (1–500)

POST/api/webhook/generate-pdfs

Enqueues a large PDF batch for asynchronous processing. Returns immediately with a 202 Accepted response containing a job ID and status URL. Results are pushed to your configured webhook URL once processing completes. Requires a webhook configured with pdfGenerated=true.

Prerequisite: Configure a webhook URL with pdfGenerated=true via POST /api/webhook. Without this, the endpoint returns 400.

Request body application/json

FieldTypeDescription
resumeIds*UUID[]List of 1–500 resume UUIDs. All must belong to the authenticated user.

Request example

curl -X POST "https://cvreader.fr/api/webhook/generate-pdfs" \
  -H "Authorization: ApiKey YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '["<uuid-1>", "<uuid-2>", ..., "<uuid-50>"]'

Response 202 Accepted

FieldTypeDescription
jobId*UUIDUnique identifier for the async generation job. Use with the status endpoint.
status*string"QUEUED" — processing has started asynchronously.
statusUrl*stringPolling URL: GET /api/webhook/generate-pdfs/{jobId}
message*stringHuman-readable confirmation.
webhookSecurity*objectHMAC-SHA256 signing metadata: algorithm, signatureHeader, timestampHeader, signedPayload format.
json
{
  "jobId": "c8a12f44-0000-0000-0000-000000000002",
  "status": "QUEUED",
  "statusUrl": "/api/webhook/generate-pdfs/c8a12f44-0000-0000-0000-000000000002",
  "message": "Processing started. Results will be sent to your webhook URL.",
  "webhookSecurity": {
    "algorithm": "HmacSHA256",
    "signatureHeader": "X-Webhook-Signature",
    "timestampHeader": "X-Webhook-Timestamp",
    "signedPayload": "<timestamp>.<raw-json-body>"
  }
}

Error responses

StatusDescription
400Resume ID list is empty, below minimum (1), above maximum (500), or webhook not configured with pdfGenerated=true
401Invalid or missing ApiKey
403One or more resume IDs do not belong to the current user
429Too many pending webhook deliveries
GET

PDF generation job status

GET/api/webhook/generate-pdfs/{jobId}

Polls the status of an asynchronous PDF generation job. Returns per-resume processing results and webhook delivery attempts. Poll periodically until status is "COMPLETED".

Path parameters

FieldTypeDescription
jobId*UUIDThe job ID returned by POST /api/webhook/generate-pdfs.

Request example

JOB_ID="c8a12f44-0000-0000-0000-000000000002"
curl "https://cvreader.fr/api/webhook/generate-pdfs/${JOB_ID}" \
  -H "Authorization: ApiKey YOUR_API_KEY"

Response 200 OK

FieldTypeDescription
jobId*UUIDJob identifier.
status*string"QUEUED" | "PROCESSING" | "COMPLETED"
total*numberTotal number of resume items in the batch.
processed*numberNumber of items already processed.
results*arrayPer-resume: resumeId, processed (bool), downloadUrl, generatedAt.
deliveries*arrayWebhook delivery attempts with status, attemptCount, responseStatusCode, errorMessage, and retry timing.
json
{
  "jobId": "c8a12f44-0000-0000-0000-000000000002",
  "status": "PROCESSING",
  "total": 25,
  "processed": 12,
  "results": [
    { "resumeId": "9f6ad665-...", "processed": true,  "downloadUrl": "https://cdn.cvreader.fr/pdfs/...", "generatedAt": "2026-05-14T10:02:00Z" },
    { "resumeId": "a1b2c3d4-...", "processed": false, "downloadUrl": null, "generatedAt": null }
  ],
  "deliveries": [
    {
      "deliveryId": "d1e2f3a4-...",
      "type": "PDF_GENERATED",
      "delivered": false,
      "attemptCount": 1,
      "lastAttempt": "2026-05-14T10:01:00Z",
      "nextAttempt": "2026-05-14T10:06:00Z",
      "responseStatusCode": 500,
      "responseBody": "Internal Server Error",
      "errorMessage": "Connection refused"
    }
  ]
}

Error responses

StatusDescription
401Invalid or missing ApiKey
403This job does not belong to the current user
404PDF generation job not found
POST

Batch format (standard or anonymized)

POST/api/resume-settings/format

Configurez les règles d'anonymisation dans votre espace abonné ("Paramètres du CV").

Request body application/json — array of resume UUIDs

json
[
  "resume-data-uuid-1",
  "a10288d7-b4ad-4181-8a45-2b7af9671b7c"
]

Request example

curl -X POST "https://cvreader.fr/api/resume-settings/format" \
  -H "Authorization: ApiKey YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '["resume-data-uuid-1", "a10288d7-b4ad-4181-8a45-2b7af9671b7c"]'

Les CV générés sont livrés par webhook ou email avec un lien de téléchargement.

Cas d'utilisation

1. Automatiser le pré‑filtrage des candidats

Analysez les CVs → obtenez les resumeId → envoyez-les à /api/jobs/queue → recevez les scores par webhook.

2. Recrutement équitable avec CVs anonymisés

Configurez l'anonymisation dans les paramètres, puis générez des CVs sans données personnelles.

Gestion des erreurs

CodeCauseSolution
400Requête mal forméeVérifiez le format du corps.
401Clé API invalideVérifiez l'en-tête Authorization.
404Ressource non trouvéeVérifiez resumeId/jobId.
429Trop de requêtesRéduisez la fréquence.

Meilleures pratiques

  • Testez dans l'environnement de bac à sable (sandbox) avant la production.
  • Anonymisez systématiquement les CVs pour les rôles sensibles.
  • Surveillez vos webhooks/emails pour les résultats asynchrones.
  • Archivez les CVs originaux de manière sécurisée (RGPD).

Besoin d'aide ?