{
  "openapi": "3.1.0",
  "info": {
    "title": "HireLayer API",
    "version": "2026-10-01",
    "summary": "Recruiting APIs: resume parsing, job criteria, matching, ranking and skills.",
    "description": "Five recruiting APIs behind one API key. Every call is synchronous and a successful call costs 1 credit. Human-readable documentation: https://hirelayer.co/api-docs. Markdown for agents: https://hirelayer.co/llms.txt.",
    "contact": {
      "name": "HireLayer",
      "url": "https://cal.com/resumeparser/demo"
    }
  },
  "servers": [
    {
      "url": "https://hirelayer.co",
      "description": "Production"
    }
  ],
  "security": [
    {
      "ApiKeyAuth": []
    }
  ],
  "tags": [
    {
      "name": "HireLayer CV Extract",
      "description": "Resume file → structured candidate JSON",
      "externalDocs": {
        "url": "https://hirelayer.co/api-docs/extract"
      }
    },
    {
      "name": "HireLayer Job Extract",
      "description": "Job description → weighted criteria",
      "externalDocs": {
        "url": "https://hirelayer.co/api-docs/job-extract"
      }
    },
    {
      "name": "HireLayer Match",
      "description": "One candidate vs. one job, criterion by criterion",
      "externalDocs": {
        "url": "https://hirelayer.co/api-docs/match"
      }
    },
    {
      "name": "HireLayer Rank",
      "description": "Up to 10 candidates ranked for one job",
      "externalDocs": {
        "url": "https://hirelayer.co/api-docs/rank"
      }
    },
    {
      "name": "HireLayer Skills",
      "description": "Free-text skills → skills taxonomy",
      "externalDocs": {
        "url": "https://hirelayer.co/api-docs/skills"
      }
    },
    {
      "name": "Platform",
      "description": "Service status."
    }
  ],
  "externalDocs": {
    "description": "HireLayer API documentation",
    "url": "https://hirelayer.co/api-docs"
  },
  "paths": {
    "/api/v3/parser": {
      "post": {
        "operationId": "parseResume",
        "summary": "Parse a resume",
        "description": "Upload one resume file and receive the structured candidate profile in the same response.\n\n**Billing:** 1 credit per successful parse (HTTP 200).\n\n**Latency:** Synchronous. Parsing usually takes about 35 seconds; scans that need OCR take longer. The gateway waits up to 145 seconds, then returns `504`. Use a client timeout of at least 150 seconds.\n\n**Asynchronous mode:** Send `Prefer: respond-async` with a `webhook_url` to get `202 Accepted` right away, for clients that cannot wait (Zapier actions stop after 30 seconds). See [Asynchronous mode](#async).\n\n**Retries:** Retry `502`, `503` and `504` with exponential backoff and honour `Retry-After`. Never retry `4xx` unchanged. Failed requests are not charged.\n\n**Idempotency:** There is no idempotency key. A request your client abandons can still complete and be charged: do not use a client timeout shorter than the gateway timeout.\n\n**Partial results:** When an optional step is skipped (OCR of some pages, photo, geocoding, occupation codes), the response is still `200` with `upstream_status: \"partial\"` and a note in `warnings`.\n\n**Documents:** 13 formats (PDF, DOC, DOCX, ODT, PPT, PPTX, ODP, XLS, RTF, TXT, JPG/JPEG, PNG and BMP). All pages are read; scanned documents are OCR'd on their first 4 pages. Up to 100,000 extracted characters.\n\n**Languages:** Free-text values stay in the language of the resume (no translation). Enumerated fields use the fixed English values of the response schema. `rome_jobs` labels are in French.\n\n**Request ID:** Successful responses carry `request_id`; error responses carry the `x-parser-request-id` header. Quote them when contacting support.\n\nReference: https://hirelayer.co/api-docs/extract#parse-resume",
        "tags": [
          "HireLayer CV Extract"
        ],
        "x-stability": "stable",
        "x-client-timeout-seconds": 150,
        "externalDocs": {
          "url": "https://hirelayer.co/api-docs/extract#parse-resume"
        },
        "requestBody": {
          "required": true,
          "content": {
            "multipart/form-data": {
              "schema": {
                "$ref": "#/components/schemas/ParseResumeRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Parsed resume.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ParseResumeResponse"
                },
                "examples": {
                  "example-1": {
                    "summary": "Parsed resume.",
                    "value": {
                      "status": "success",
                      "request_id": "6f1c2a9e-4b7d-4c3e-9a51-2f8d7e6b1c04",
                      "warnings": [],
                      "errors": [],
                      "info_resume": {
                        "application_id": "app_123",
                        "date_parsing": "2026-10-01T09:30:12",
                        "language": "EN",
                        "url": "https://files.example.com/original/1790847012000-alex-morgan.pdf",
                        "face_url": "https://files.example.com/faces/1790847012000-alex-morgan.jpg",
                        "face_url_expires_at": null,
                        "text": "Alex Morgan\nSenior Software Engineer\nParis, France\nalex.morgan@example.com\n\nSenior software engineer with 8 years of experience building web platforms…"
                      },
                      "info_candidate": {
                        "full_name": "Alex Morgan",
                        "last_name": "Morgan",
                        "first_name": "Alex",
                        "email": "alex.morgan@example.com",
                        "phone_number": "+33612345678",
                        "birth_date": "1992-04-18",
                        "age": 34,
                        "availability_now": false,
                        "availability_date": "2026-11-01",
                        "driver_license": [
                          "Permis B"
                        ],
                        "job_title": "Senior Software Engineer",
                        "education_name": "Master of Science in Computer Science",
                        "education_level": "Level 7",
                        "experience_level": "5 to 10 years",
                        "linkedin_url": "https://www.linkedin.com/in/alex-morgan",
                        "github_url": "https://github.com/alexmorgan",
                        "other_urls": [
                          "https://alexmorgan.dev"
                        ],
                        "location": {
                          "country": "France",
                          "country_code": "FR",
                          "region": "Île-de-France",
                          "department": "Paris",
                          "city": "Paris",
                          "postal_code": "75011",
                          "full_address": "75011 Paris, France",
                          "latitude": 48.8589,
                          "longitude": 2.3801
                        },
                        "mobility": {
                          "can_work_in_other_cities": true,
                          "other_cities": [
                            {
                              "city": "Lyon",
                              "country": "France",
                              "postal_code": null,
                              "latitude": 45.764,
                              "longitude": 4.8357
                            }
                          ]
                        }
                      },
                      "work_experiences": [
                        {
                          "company_name": "Northstar Labs",
                          "job_title": "Senior Software Engineer",
                          "description": "Lead a team of five engineers building a TypeScript and React SaaS platform.",
                          "contract_type": "Permanent contract",
                          "start_date": "2022-03-01",
                          "end_date": null,
                          "currently_active": true,
                          "work_experience_country": "France",
                          "work_experience_country_code": "FR",
                          "work_experience_city": "Paris",
                          "work_experience_postal_code": null,
                          "experience_duration": 55
                        },
                        {
                          "company_name": "Atelier Digital",
                          "job_title": "Software Engineer",
                          "description": "Built Node.js APIs and data pipelines for recruitment clients.",
                          "contract_type": "Permanent contract",
                          "start_date": "2018-09-01",
                          "end_date": "2022-02-28",
                          "currently_active": false,
                          "work_experience_country": "France",
                          "work_experience_country_code": "FR",
                          "work_experience_city": "Paris",
                          "work_experience_postal_code": null,
                          "experience_duration": 42
                        }
                      ],
                      "educations": [
                        {
                          "degree_title": "Master of Science in Computer Science",
                          "school_name": "École Polytechnique",
                          "description": "Distributed systems and software architecture.",
                          "degree_type": "Level 7",
                          "start_date": "2014-09-01",
                          "end_date": "2016-06-30",
                          "currently_active": false,
                          "location": {
                            "country": "France",
                            "country_code": "FR",
                            "region": "Île-de-France",
                            "department": "Essonne",
                            "city": "Palaiseau",
                            "postal_code": "91120",
                            "full_address": "Palaiseau, France"
                          }
                        }
                      ],
                      "rome_jobs": [
                        {
                          "job_title": "Ingénieur / Ingénieure logiciel",
                          "job_code": "38971",
                          "rome_title": "Études et développement informatique",
                          "rome_code": "M1805",
                          "prediction_score": 0.93
                        }
                      ],
                      "languages": [
                        {
                          "language": "English",
                          "level": "Native or Bilingual (C2)"
                        },
                        {
                          "language": "French",
                          "level": "Professional Working Proficiency (B2)"
                        }
                      ],
                      "skills": [
                        {
                          "skill_title": "React",
                          "skill_type": "Software skill",
                          "status": "normalized",
                          "domain": "Développement logiciel",
                          "subcategory": "Développement frontend"
                        },
                        {
                          "skill_title": "TypeScript",
                          "skill_type": "Software skill",
                          "status": "normalized",
                          "domain": "Développement logiciel",
                          "subcategory": "Langages de programmation"
                        },
                        {
                          "skill_title": "Figma",
                          "skill_type": "Software skill",
                          "status": "normalized",
                          "domain": "Design, Création & Médias",
                          "subcategory": "UX/UI design"
                        },
                        {
                          "skill_title": "Leadership technique",
                          "skill_type": "Soft skill",
                          "status": "normalized",
                          "domain": "Management, Projet & Stratégie",
                          "subcategory": "Management d'équipe"
                        },
                        {
                          "skill_title": "Developer experience",
                          "skill_type": "Hard skill",
                          "status": "raw",
                          "domain": null,
                          "subcategory": null
                        }
                      ],
                      "certifications": [
                        "AWS Certified Developer – Associate"
                      ],
                      "interests": [
                        "Open-source software",
                        "Climbing"
                      ]
                    }
                  }
                }
              }
            }
          },
          "202": {
            "description": "Accepted in [asynchronous mode](#async): the outcome is posted to `webhook_url`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ParseResumeResponse"
                },
                "examples": {
                  "example-1": {
                    "summary": "Accepted in [asynchronous mode](#async): the outcome is posted to `webhook_url`.",
                    "value": {
                      "status": "accepted",
                      "application_id": "app_123"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "- `The request body is not valid multipart/form-data. Check the boundary and the Content-Disposition header of each part.` (`INVALID_MULTIPART_BODY`): The body cannot be read as `multipart/form-data`: the `boundary` is missing or does not match the body, the body is truncated, or a part has no `Content-Disposition: form-data` header with a `name`. Unquoted parameter values and `filename*` (as sent by .NET `MultipartFormDataContent`) are accepted. Do not retry.\n- `Missing required file field`: No multipart part named `file`. Do not retry.\n- `Prefer: respond-async requires a webhook_url field with an HTTPS URL`: The request asks for the [asynchronous mode](#async) without a valid HTTPS `webhook_url`. Do not retry.\n- `application_id must be a string when provided`: `application_id` was sent as a file part. Do not retry.\n- `The uploaded file is empty or invalid. Please check the file and try again.` (`INVALID_FILE`): Empty file, unsupported format, content that does not match its type, or a `do_not_store_data` value other than `true`/`false`. Do not retry.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/GatewayError"
                },
                "examples": {
                  "invalid-multipart-body": {
                    "summary": "The request body is not valid multipart/form-data. Check the boundary and the Content-Disposition header of each part.",
                    "value": {
                      "error": "The request body is not valid multipart/form-data. Check the boundary and the Content-Disposition header of each part.",
                      "code": "INVALID_MULTIPART_BODY"
                    }
                  },
                  "missing-required-file-field": {
                    "summary": "Missing required file field",
                    "value": {
                      "error": "Missing required file field"
                    }
                  },
                  "prefer-respond-async-requires-a-webhook-url-field-with-an-https-url": {
                    "summary": "Prefer: respond-async requires a webhook_url field with an HTTPS URL",
                    "value": {
                      "error": "Prefer: respond-async requires a webhook_url field with an HTTPS URL"
                    }
                  },
                  "application-id-must-be-a-string-when-provided": {
                    "summary": "application_id must be a string when provided",
                    "value": {
                      "error": "application_id must be a string when provided"
                    }
                  },
                  "invalid-file": {
                    "summary": "The uploaded file is empty or invalid. Please check the file and try again.",
                    "value": {
                      "error": "The uploaded file is empty or invalid. Please check the file and try again.",
                      "code": "INVALID_FILE"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "- `Missing API Key`: The `X-API-Key` header is absent. `Authorization: Bearer` is not accepted. Do not retry.\n- `Invalid API Key`: The key is malformed, unknown or revoked. Rotating a key revokes the previous one immediately. Do not retry.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/GatewayError"
                },
                "examples": {
                  "missing-api-key": {
                    "summary": "Missing API Key",
                    "value": {
                      "error": "Missing API Key"
                    }
                  },
                  "invalid-api-key": {
                    "summary": "Invalid API Key",
                    "value": {
                      "error": "Invalid API Key"
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "- `Insufficient credits available`: The account has no credit left. Fix, then retry.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/GatewayError"
                },
                "examples": {
                  "insufficient-credits-available": {
                    "summary": "Insufficient credits available",
                    "value": {
                      "error": "Insufficient credits available"
                    }
                  }
                }
              }
            }
          },
          "413": {
            "description": "- `The uploaded file is too large to process. Please upload a smaller file.`: The encoded upload exceeds 6 MiB (a file of about 4.5 MB). Do not retry.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/GatewayError"
                },
                "examples": {
                  "the-uploaded-file-is-too-large-to-process-please-upload-a-smaller-file": {
                    "summary": "The uploaded file is too large to process. Please upload a smaller file.",
                    "value": {
                      "error": "The uploaded file is too large to process. Please upload a smaller file."
                    }
                  }
                }
              }
            }
          },
          "415": {
            "description": "- `Content-Type must be multipart/form-data`: The request is not `multipart/form-data`. Do not retry.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/GatewayError"
                },
                "examples": {
                  "content-type-must-be-multipart-form-data": {
                    "summary": "Content-Type must be multipart/form-data",
                    "value": {
                      "error": "Content-Type must be multipart/form-data"
                    }
                  }
                }
              }
            }
          },
          "422": {
            "description": "- `This document does not appear to be a CV or resume. Please upload a CV or resume and try again.` (`DOCUMENT_NOT_A_RESUME`): The document is clearly not a resume (cover letter, ID, invoice…). Do not retry.\n- `The text could not be extracted from this document. Please verify that the file is readable and contains selectable text.` (`DOCUMENT_TEXT_EMPTY`): No text was found, even with OCR. Do not retry.\n- `The document could not be read. Please upload a valid, readable file.` (`DOCUMENT_UNREADABLE`): The file is corrupted or cannot be opened. Do not retry.\n- `This document contains too much text to process. Please try a shorter or simpler version.` (`DOCUMENT_TOO_LARGE`): More than 100,000 characters of text were extracted. Do not retry.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/GatewayError"
                },
                "examples": {
                  "document-not-a-resume": {
                    "summary": "This document does not appear to be a CV or resume. Please upload a CV or resume and try again.",
                    "value": {
                      "error": "This document does not appear to be a CV or resume. Please upload a CV or resume and try again.",
                      "code": "DOCUMENT_NOT_A_RESUME"
                    }
                  },
                  "document-text-empty": {
                    "summary": "The text could not be extracted from this document. Please verify that the file is readable and contains selectable text.",
                    "value": {
                      "error": "The text could not be extracted from this document. Please verify that the file is readable and contains selectable text.",
                      "code": "DOCUMENT_TEXT_EMPTY"
                    }
                  },
                  "document-unreadable": {
                    "summary": "The document could not be read. Please upload a valid, readable file.",
                    "value": {
                      "error": "The document could not be read. Please upload a valid, readable file.",
                      "code": "DOCUMENT_UNREADABLE"
                    }
                  },
                  "document-too-large": {
                    "summary": "This document contains too much text to process. Please try a shorter or simpler version.",
                    "value": {
                      "error": "This document contains too much text to process. Please try a shorter or simpler version.",
                      "code": "DOCUMENT_TOO_LARGE"
                    }
                  }
                }
              }
            }
          },
          "500": {
            "description": "- `Internal Server Error`: Unexpected failure. Retry with backoff.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/GatewayError"
                },
                "examples": {
                  "internal-server-error": {
                    "summary": "Internal Server Error",
                    "value": {
                      "error": "Internal Server Error"
                    }
                  }
                }
              }
            }
          },
          "502": {
            "description": "- `An error occurred while processing the document or extracting its text. Please try again later.` (`PARSER_UNAVAILABLE`): The parser failed or returned an invalid result. Retry with backoff.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/GatewayError"
                },
                "examples": {
                  "parser-unavailable": {
                    "summary": "An error occurred while processing the document or extracting its text. Please try again later.",
                    "value": {
                      "error": "An error occurred while processing the document or extracting its text. Please try again later.",
                      "code": "PARSER_UNAVAILABLE"
                    }
                  }
                }
              }
            }
          },
          "503": {
            "description": "- `An error occurred while processing the document or extracting its text. Please try again later.` (`PARSER_UNAVAILABLE`): A processing step (text extraction, OCR, model) is temporarily unavailable. Retry with backoff.\n- `Credit service temporarily unavailable`: Credits could not be checked or deducted. No credit is consumed, including when the operation itself had completed. Retry with backoff.",
            "headers": {
              "Retry-After": {
                "description": "Seconds to wait before retrying.",
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/GatewayError"
                },
                "examples": {
                  "parser-unavailable": {
                    "summary": "An error occurred while processing the document or extracting its text. Please try again later.",
                    "value": {
                      "error": "An error occurred while processing the document or extracting its text. Please try again later.",
                      "code": "PARSER_UNAVAILABLE"
                    }
                  },
                  "credit-service-temporarily-unavailable": {
                    "summary": "Credit service temporarily unavailable",
                    "value": {
                      "error": "Credit service temporarily unavailable"
                    }
                  }
                }
              }
            }
          },
          "504": {
            "description": "- `An error occurred while processing the document or extracting its text. Please try again later.` (`PARSER_UNAVAILABLE`): Parsing did not finish within 145 seconds. Retry with backoff.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/GatewayError"
                },
                "examples": {
                  "parser-unavailable": {
                    "summary": "An error occurred while processing the document or extracting its text. Please try again later.",
                    "value": {
                      "error": "An error occurred while processing the document or extracting its text. Please try again later.",
                      "code": "PARSER_UNAVAILABLE"
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/jobs/extract-criteria": {
      "post": {
        "operationId": "extractJobCriteria",
        "summary": "Extract job criteria",
        "description": "Turn a job description into weighted criteria that can be checked against a resume.\n\n**Billing:** 1 credit per successful call.\n\n**Latency:** Synchronous. The gateway waits up to 60 seconds, then returns `502 Upstream API unavailable`. Use a client timeout of at least 65 seconds.\n\n**Retries:** Transient model errors are retried by the service before it answers. Retry `502` and `503` with exponential backoff; never retry `4xx` unchanged. Failed requests are not charged.\n\n**Validation:** Validation stops at the first error, so one call reports one problem. Text fields are trimmed before their length is checked.\n\n**Output:** Only requirements a resume can prove are returned; the endpoint does not score candidates. `label` and `rationale` are written in French. The number of criteria is not fixed and can be zero.\n\n**Stability:** Two calls with the same text can return slightly different criteria. Extract once per job, let a recruiter review the list, and store it with the job.\n\nReference: https://hirelayer.co/api-docs/job-extract#extract-criteria",
        "tags": [
          "HireLayer Job Extract"
        ],
        "x-stability": "stable",
        "x-client-timeout-seconds": 65,
        "externalDocs": {
          "url": "https://hirelayer.co/api-docs/job-extract#extract-criteria"
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ExtractJobCriteriaRequest"
              },
              "examples": {
                "default": {
                  "value": {
                    "job_text": "Senior Frontend Engineer, Paris (hybrid). You will build our recruiting platform with React and TypeScript. Requirements: 5+ years of frontend development, strong React and TypeScript skills, fluent English. Nice to have: experience with Next.js."
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Extracted criteria.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ExtractJobCriteriaResponse"
                },
                "examples": {
                  "example-1": {
                    "summary": "Extracted criteria.",
                    "value": {
                      "matching_criteria": [
                        {
                          "id": "crit_1",
                          "label": "Maîtrise de React",
                          "weight": 3,
                          "is_mandatory": true,
                          "rationale": "React est explicitement exigé pour le poste."
                        },
                        {
                          "id": "crit_2",
                          "label": "Maîtrise de TypeScript",
                          "weight": 3,
                          "is_mandatory": true,
                          "rationale": "TypeScript est explicitement exigé pour le poste."
                        },
                        {
                          "id": "crit_3",
                          "label": "Au moins 5 ans d’expérience en développement frontend",
                          "weight": 3,
                          "is_mandatory": true,
                          "rationale": "L’offre demande plus de cinq ans d’expérience frontend."
                        },
                        {
                          "id": "crit_4",
                          "label": "Anglais courant",
                          "weight": 2,
                          "is_mandatory": true,
                          "rationale": "Un anglais courant est demandé."
                        },
                        {
                          "id": "crit_5",
                          "label": "Expérience avec Next.js",
                          "weight": 1,
                          "is_mandatory": false,
                          "rationale": "Next.js est présenté comme un atout."
                        }
                      ]
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "- `Request body must be a JSON object`: The body is missing, is a JSON array, or `Content-Type` is not `application/json`. Do not retry.\n- `The request contains unsupported fields`: The body contains a field that is not documented for this endpoint. Do not retry.\n- `The 'job_text' field is required`: `job_text` is missing or not a string. Do not retry.\n- `job_text cannot be empty`: `job_text` is empty after trimming. Do not retry.\n- `job_text must be 50000 characters or less`: `job_text` is longer than 50,000 characters after trimming. Do not retry.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ServiceError"
                },
                "examples": {
                  "request-body-must-be-a-json-object": {
                    "summary": "Request body must be a JSON object",
                    "value": {
                      "success": false,
                      "error": "Request body must be a JSON object"
                    }
                  },
                  "the-request-contains-unsupported-fields": {
                    "summary": "The request contains unsupported fields",
                    "value": {
                      "success": false,
                      "error": "The request contains unsupported fields"
                    }
                  },
                  "the-job-text-field-is-required": {
                    "summary": "The 'job_text' field is required",
                    "value": {
                      "success": false,
                      "error": "The 'job_text' field is required"
                    }
                  },
                  "job-text-cannot-be-empty": {
                    "summary": "job_text cannot be empty",
                    "value": {
                      "success": false,
                      "error": "job_text cannot be empty"
                    }
                  },
                  "job-text-must-be-50000-characters-or-less": {
                    "summary": "job_text must be 50000 characters or less",
                    "value": {
                      "success": false,
                      "error": "job_text must be 50000 characters or less"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "- `Missing API Key`: The `X-API-Key` header is absent. `Authorization: Bearer` is not accepted. Do not retry.\n- `Invalid API Key`: The key is malformed, unknown or revoked. Rotating a key revokes the previous one immediately. Do not retry.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/GatewayError"
                },
                "examples": {
                  "missing-api-key": {
                    "summary": "Missing API Key",
                    "value": {
                      "error": "Missing API Key"
                    }
                  },
                  "invalid-api-key": {
                    "summary": "Invalid API Key",
                    "value": {
                      "error": "Invalid API Key"
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "- `Insufficient credits available`: The account has no credit left. `availableCredits` is the current balance. Fix, then retry.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/GatewayError"
                },
                "examples": {
                  "insufficient-credits-available": {
                    "summary": "Insufficient credits available",
                    "value": {
                      "error": "Insufficient credits available",
                      "availableCredits": 0
                    }
                  }
                }
              }
            }
          },
          "500": {
            "description": "- `Internal server error`: Unexpected gateway failure. Retry with backoff.\n- `Internal server error. Please try again later.`: The body is not valid JSON, is a JSON primitive or exceeds 10 MB, or the service failed unexpectedly. Check the payload: if it is valid, retry. Retry with backoff.",
            "content": {
              "application/json": {
                "schema": {
                  "oneOf": [
                    {
                      "$ref": "#/components/schemas/GatewayError"
                    },
                    {
                      "$ref": "#/components/schemas/ServiceError"
                    }
                  ]
                },
                "examples": {
                  "internal-server-error": {
                    "summary": "Internal server error",
                    "value": {
                      "error": "Internal server error"
                    }
                  },
                  "internal-server-error-please-try-again-later": {
                    "summary": "Internal server error. Please try again later.",
                    "value": {
                      "success": false,
                      "error": "Internal server error. Please try again later."
                    }
                  }
                }
              }
            }
          },
          "502": {
            "description": "- `Upstream API unavailable`: The service did not answer within 60 seconds, or could not be reached. Retry with backoff.\n- `The AI processing step failed. Please try again later.`: Criteria extraction failed or returned an invalid result after the service's internal retries. Retry with backoff.",
            "content": {
              "application/json": {
                "schema": {
                  "oneOf": [
                    {
                      "$ref": "#/components/schemas/GatewayError"
                    },
                    {
                      "$ref": "#/components/schemas/ServiceError"
                    }
                  ]
                },
                "examples": {
                  "upstream-api-unavailable": {
                    "summary": "Upstream API unavailable",
                    "value": {
                      "error": "Upstream API unavailable"
                    }
                  },
                  "the-ai-processing-step-failed-please-try-again-later": {
                    "summary": "The AI processing step failed. Please try again later.",
                    "value": {
                      "success": false,
                      "error": "The AI processing step failed. Please try again later."
                    }
                  }
                }
              }
            }
          },
          "503": {
            "description": "- `Credit service temporarily unavailable`: Credits could not be checked or deducted. No credit is consumed, including when the operation itself had completed. Retry with backoff.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/GatewayError"
                },
                "examples": {
                  "credit-service-temporarily-unavailable": {
                    "summary": "Credit service temporarily unavailable",
                    "value": {
                      "error": "Credit service temporarily unavailable"
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/matching/job-candidate": {
      "post": {
        "operationId": "matchCandidate",
        "summary": "Match a candidate to a job",
        "description": "Evaluate one resume against each job criterion and get an explained 0–1 score.\n\n**Billing:** 1 credit per successful call.\n\n**Latency:** Synchronous. The gateway waits up to 60 seconds, then returns `502 Upstream API unavailable`. Use a client timeout of at least 65 seconds.\n\n**Retries:** Transient model errors are retried by the service before it answers. Retry `502` and `503` with exponential backoff; never retry `4xx` unchanged. Failed requests are not charged.\n\n**Validation:** Validation stops at the first error, so one call reports one problem. Text fields are trimmed before their length is checked.\n\n**Score:** `score = Σ(weight × value) / Σ weight` with `ideal` = 1, `potential` = 0.6, `not_mentioned` = 0.5 and `not_valid` = 0. Every criterion counts in the denominator; `is_mandatory` has no effect on the score.\n\n**Empty criteria:** With `\"matching_criteria\": []` the model is not called and the response is exactly `{\"score\": 0, \"summary\": \"Aucun critère à évaluer.\", \"evaluated_criteria\": []}`.\n\n**Hard requirements:** To reject candidates who miss a mandatory criterion, check `is_mandatory` and `match_status` in your code: the score alone does not do it.\n\nReference: https://hirelayer.co/api-docs/match#match-job-candidate",
        "tags": [
          "HireLayer Match"
        ],
        "x-stability": "stable",
        "x-client-timeout-seconds": 65,
        "externalDocs": {
          "url": "https://hirelayer.co/api-docs/match#match-job-candidate"
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/MatchCandidateRequest"
              },
              "examples": {
                "default": {
                  "value": {
                    "job_text": "Senior Frontend Engineer, Paris (hybrid). You will build our recruiting platform with React and TypeScript. Requirements: 5+ years of frontend development, strong React and TypeScript skills, fluent English. Nice to have: experience with Next.js.",
                    "candidate_text": "Alex Morgan, Senior Software Engineer in Paris. 8 years of experience. Since 2022, leads a team building a React and TypeScript SaaS platform at Northstar Labs. Previously built Node.js APIs. Professional English.",
                    "matching_criteria": [
                      {
                        "id": "crit_1",
                        "label": "Maîtrise de React",
                        "weight": 3,
                        "is_mandatory": true,
                        "rationale": "React est explicitement exigé pour le poste."
                      },
                      {
                        "id": "crit_2",
                        "label": "Maîtrise de TypeScript",
                        "weight": 3,
                        "is_mandatory": true,
                        "rationale": "TypeScript est explicitement exigé pour le poste."
                      },
                      {
                        "id": "crit_3",
                        "label": "Au moins 5 ans d’expérience en développement frontend",
                        "weight": 3,
                        "is_mandatory": true,
                        "rationale": "L’offre demande plus de cinq ans d’expérience frontend."
                      },
                      {
                        "id": "crit_4",
                        "label": "Anglais courant",
                        "weight": 2,
                        "is_mandatory": true,
                        "rationale": "Un anglais courant est demandé."
                      },
                      {
                        "id": "crit_5",
                        "label": "Expérience avec Next.js",
                        "weight": 1,
                        "is_mandatory": false,
                        "rationale": "Next.js est présenté comme un atout."
                      }
                    ]
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Evaluation of every criterion.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/MatchCandidateResponse"
                },
                "examples": {
                  "example-1": {
                    "summary": "Evaluation of every criterion.",
                    "value": {
                      "score": 0.8916666666666666,
                      "summary": "Profil très aligné : React, TypeScript et l’expérience demandée sont démontrés. Le niveau d’anglais reste à confirmer.",
                      "evaluated_criteria": [
                        {
                          "id": "crit_1",
                          "label": "Maîtrise de React",
                          "weight": 3,
                          "is_mandatory": true,
                          "rationale": "React est explicitement exigé pour le poste.",
                          "match_status": "ideal",
                          "match_explanation": "Le CV décrit une équipe React dirigée depuis 2022 sur une plateforme en production."
                        },
                        {
                          "id": "crit_2",
                          "label": "Maîtrise de TypeScript",
                          "weight": 3,
                          "is_mandatory": true,
                          "rationale": "TypeScript est explicitement exigé pour le poste.",
                          "match_status": "ideal",
                          "match_explanation": "La plateforme actuelle est développée en TypeScript."
                        },
                        {
                          "id": "crit_3",
                          "label": "Au moins 5 ans d’expérience en développement frontend",
                          "weight": 3,
                          "is_mandatory": true,
                          "rationale": "L’offre demande plus de cinq ans d’expérience frontend.",
                          "match_status": "ideal",
                          "match_explanation": "Le candidat cumule huit ans d’expérience en développement."
                        },
                        {
                          "id": "crit_4",
                          "label": "Anglais courant",
                          "weight": 2,
                          "is_mandatory": true,
                          "rationale": "Un anglais courant est demandé.",
                          "match_status": "potential",
                          "match_explanation": "Le CV mentionne un anglais professionnel, sans préciser un niveau courant."
                        },
                        {
                          "id": "crit_5",
                          "label": "Expérience avec Next.js",
                          "weight": 1,
                          "is_mandatory": false,
                          "rationale": "Next.js est présenté comme un atout.",
                          "match_status": "not_mentioned",
                          "match_explanation": "Le CV ne mentionne pas Next.js."
                        }
                      ]
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "- `Request body must be a JSON object`: The body is missing, is a JSON array, or `Content-Type` is not `application/json`. Do not retry.\n- `The request contains unsupported fields`: The body contains a field that is not documented for this endpoint. Do not retry.\n- `The 'job_text' field is required`: `job_text` is missing or not a string. Do not retry.\n- `job_text cannot be empty`: `job_text` is empty after trimming. Do not retry.\n- `job_text must be 50000 characters or less`: `job_text` is longer than 50,000 characters after trimming. Do not retry.\n- `The 'candidate_text' field is required`: `candidate_text` is missing or not a string. Do not retry.\n- `candidate_text cannot be empty`: `candidate_text` is empty after trimming. Do not retry.\n- `candidate_text must be 50000 characters or less`: `candidate_text` is longer than 50,000 characters after trimming. Do not retry.\n- `The 'matching_criteria' field must be an array`: `matching_criteria` is missing or not an array. Do not retry.\n- `matching_criteria contains an invalid criterion`: A criterion has a missing, empty or extra field, or a `weight` outside 1–3. Do not retry.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ServiceError"
                },
                "examples": {
                  "request-body-must-be-a-json-object": {
                    "summary": "Request body must be a JSON object",
                    "value": {
                      "success": false,
                      "error": "Request body must be a JSON object"
                    }
                  },
                  "the-request-contains-unsupported-fields": {
                    "summary": "The request contains unsupported fields",
                    "value": {
                      "success": false,
                      "error": "The request contains unsupported fields"
                    }
                  },
                  "the-job-text-field-is-required": {
                    "summary": "The 'job_text' field is required",
                    "value": {
                      "success": false,
                      "error": "The 'job_text' field is required"
                    }
                  },
                  "job-text-cannot-be-empty": {
                    "summary": "job_text cannot be empty",
                    "value": {
                      "success": false,
                      "error": "job_text cannot be empty"
                    }
                  },
                  "job-text-must-be-50000-characters-or-less": {
                    "summary": "job_text must be 50000 characters or less",
                    "value": {
                      "success": false,
                      "error": "job_text must be 50000 characters or less"
                    }
                  },
                  "the-candidate-text-field-is-required": {
                    "summary": "The 'candidate_text' field is required",
                    "value": {
                      "success": false,
                      "error": "The 'candidate_text' field is required"
                    }
                  },
                  "candidate-text-cannot-be-empty": {
                    "summary": "candidate_text cannot be empty",
                    "value": {
                      "success": false,
                      "error": "candidate_text cannot be empty"
                    }
                  },
                  "candidate-text-must-be-50000-characters-or-less": {
                    "summary": "candidate_text must be 50000 characters or less",
                    "value": {
                      "success": false,
                      "error": "candidate_text must be 50000 characters or less"
                    }
                  },
                  "the-matching-criteria-field-must-be-an-array": {
                    "summary": "The 'matching_criteria' field must be an array",
                    "value": {
                      "success": false,
                      "error": "The 'matching_criteria' field must be an array"
                    }
                  },
                  "matching-criteria-contains-an-invalid-criterion": {
                    "summary": "matching_criteria contains an invalid criterion",
                    "value": {
                      "success": false,
                      "error": "matching_criteria contains an invalid criterion"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "- `Missing API Key`: The `X-API-Key` header is absent. `Authorization: Bearer` is not accepted. Do not retry.\n- `Invalid API Key`: The key is malformed, unknown or revoked. Rotating a key revokes the previous one immediately. Do not retry.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/GatewayError"
                },
                "examples": {
                  "missing-api-key": {
                    "summary": "Missing API Key",
                    "value": {
                      "error": "Missing API Key"
                    }
                  },
                  "invalid-api-key": {
                    "summary": "Invalid API Key",
                    "value": {
                      "error": "Invalid API Key"
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "- `Insufficient credits available`: The account has no credit left. `availableCredits` is the current balance. Fix, then retry.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/GatewayError"
                },
                "examples": {
                  "insufficient-credits-available": {
                    "summary": "Insufficient credits available",
                    "value": {
                      "error": "Insufficient credits available",
                      "availableCredits": 0
                    }
                  }
                }
              }
            }
          },
          "500": {
            "description": "- `Internal server error`: Unexpected gateway failure. Retry with backoff.\n- `Internal server error. Please try again later.`: The body is not valid JSON, is a JSON primitive or exceeds 10 MB, or the service failed unexpectedly. Check the payload: if it is valid, retry. Retry with backoff.",
            "content": {
              "application/json": {
                "schema": {
                  "oneOf": [
                    {
                      "$ref": "#/components/schemas/GatewayError"
                    },
                    {
                      "$ref": "#/components/schemas/ServiceError"
                    }
                  ]
                },
                "examples": {
                  "internal-server-error": {
                    "summary": "Internal server error",
                    "value": {
                      "error": "Internal server error"
                    }
                  },
                  "internal-server-error-please-try-again-later": {
                    "summary": "Internal server error. Please try again later.",
                    "value": {
                      "success": false,
                      "error": "Internal server error. Please try again later."
                    }
                  }
                }
              }
            }
          },
          "502": {
            "description": "- `Upstream API unavailable`: The service did not answer within 60 seconds, or could not be reached. Retry with backoff.\n- `The AI processing step failed. Please try again later.`: Matching failed or returned an invalid result after the service's internal retries. Retry with backoff.",
            "content": {
              "application/json": {
                "schema": {
                  "oneOf": [
                    {
                      "$ref": "#/components/schemas/GatewayError"
                    },
                    {
                      "$ref": "#/components/schemas/ServiceError"
                    }
                  ]
                },
                "examples": {
                  "upstream-api-unavailable": {
                    "summary": "Upstream API unavailable",
                    "value": {
                      "error": "Upstream API unavailable"
                    }
                  },
                  "the-ai-processing-step-failed-please-try-again-later": {
                    "summary": "The AI processing step failed. Please try again later.",
                    "value": {
                      "success": false,
                      "error": "The AI processing step failed. Please try again later."
                    }
                  }
                }
              }
            }
          },
          "503": {
            "description": "- `Credit service temporarily unavailable`: Credits could not be checked or deducted. No credit is consumed, including when the operation itself had completed. Retry with backoff.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/GatewayError"
                },
                "examples": {
                  "credit-service-temporarily-unavailable": {
                    "summary": "Credit service temporarily unavailable",
                    "value": {
                      "error": "Credit service temporarily unavailable"
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/matching/job-candidates/rank": {
      "post": {
        "operationId": "rankCandidates",
        "summary": "Rank candidates for a job",
        "description": "Order up to 10 candidates for one job description, with a score and a rationale for each.\n\n**Billing:** 1 credit per successful call, whatever the number of candidates.\n\n**Latency:** Synchronous. The gateway waits up to 60 seconds, then returns `502 Upstream API unavailable`. Use a client timeout of at least 65 seconds.\n\n**Retries:** Transient model errors are retried by the service before it answers. Retry `502` and `503` with exponential backoff; never retry `4xx` unchanged. Failed requests are not charged.\n\n**Validation:** Validation stops at the first error, so one call reports one problem. Text fields are trimmed before their length is checked.\n\n**Ordering:** Every candidate appears exactly once and ranks are `1`…`n`. `rank` is authoritative: `score` is not guaranteed to decrease strictly with rank.\n\n**More than 10 candidates:** Ranks are relative to one request. To screen a larger pool, pre-filter it, or score each candidate with [Match](https://hirelayer.co/api-docs/match.md) against the same criteria, which gives comparable scores.\n\nReference: https://hirelayer.co/api-docs/rank#rank-job-candidates",
        "tags": [
          "HireLayer Rank"
        ],
        "x-stability": "stable",
        "x-client-timeout-seconds": 65,
        "externalDocs": {
          "url": "https://hirelayer.co/api-docs/rank#rank-job-candidates"
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/RankCandidatesRequest"
              },
              "examples": {
                "default": {
                  "value": {
                    "job_text": "Senior Frontend Engineer, Paris (hybrid). You will build our recruiting platform with React and TypeScript. Requirements: 5+ years of frontend development, strong React and TypeScript skills, fluent English. Nice to have: experience with Next.js.",
                    "candidates": [
                      {
                        "id": "candidate_1",
                        "candidate_text": "Alex Morgan, Senior Software Engineer in Paris. 8 years of experience. Since 2022, leads a team building a React and TypeScript SaaS platform at Northstar Labs. Previously built Node.js APIs. Professional English."
                      },
                      {
                        "id": "candidate_2",
                        "candidate_text": "Frontend developer in Lyon with 3 years of React experience on e-commerce sites. JavaScript, some TypeScript. Conversational English."
                      },
                      {
                        "id": "candidate_3",
                        "candidate_text": "Full-stack JavaScript developer with 6 years of experience, mostly Vue.js and PHP. Fluent English."
                      }
                    ]
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Ranked candidates.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RankCandidatesResponse"
                },
                "examples": {
                  "example-1": {
                    "summary": "Ranked candidates.",
                    "value": {
                      "rankings": [
                        {
                          "rank": 1,
                          "candidate_id": "candidate_1",
                          "score": 0.91,
                          "rationale": "React et TypeScript sont démontrés en production, avec l’expérience demandée."
                        },
                        {
                          "rank": 2,
                          "candidate_id": "candidate_2",
                          "score": 0.64,
                          "rationale": "Bonne pratique de React, mais expérience plus courte et anglais seulement conversationnel."
                        },
                        {
                          "rank": 3,
                          "candidate_id": "candidate_3",
                          "score": 0.38,
                          "rationale": "Profil JavaScript solide, mais centré sur Vue.js sans expérience React mentionnée."
                        }
                      ]
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "- `Request body must be a JSON object`: The body is missing, is a JSON array, or `Content-Type` is not `application/json`. Do not retry.\n- `The request contains unsupported fields`: The body contains a field that is not documented for this endpoint. Do not retry.\n- `The 'job_text' field is required`: `job_text` is missing or not a string. Do not retry.\n- `job_text cannot be empty`: `job_text` is empty after trimming. Do not retry.\n- `job_text must be 50000 characters or less`: `job_text` is longer than 50,000 characters after trimming. Do not retry.\n- `The 'candidates' field must be an array`: `candidates` is missing or not an array. Do not retry.\n- `candidates cannot be empty`: `candidates` is `[]`. Do not retry.\n- `candidates must contain 10 candidates or fewer`: More than 10 candidates. Do not retry.\n- `candidates contains an invalid candidate`: A candidate has a missing, empty or extra field. Do not retry.\n- `candidate_text must be 50000 characters or less`: A `candidate_text` is longer than 50,000 characters after trimming. Do not retry.\n- `candidates contains duplicate ids`: Two candidates share the same `id` after trimming. Do not retry.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ServiceError"
                },
                "examples": {
                  "request-body-must-be-a-json-object": {
                    "summary": "Request body must be a JSON object",
                    "value": {
                      "success": false,
                      "error": "Request body must be a JSON object"
                    }
                  },
                  "the-request-contains-unsupported-fields": {
                    "summary": "The request contains unsupported fields",
                    "value": {
                      "success": false,
                      "error": "The request contains unsupported fields"
                    }
                  },
                  "the-job-text-field-is-required": {
                    "summary": "The 'job_text' field is required",
                    "value": {
                      "success": false,
                      "error": "The 'job_text' field is required"
                    }
                  },
                  "job-text-cannot-be-empty": {
                    "summary": "job_text cannot be empty",
                    "value": {
                      "success": false,
                      "error": "job_text cannot be empty"
                    }
                  },
                  "job-text-must-be-50000-characters-or-less": {
                    "summary": "job_text must be 50000 characters or less",
                    "value": {
                      "success": false,
                      "error": "job_text must be 50000 characters or less"
                    }
                  },
                  "the-candidates-field-must-be-an-array": {
                    "summary": "The 'candidates' field must be an array",
                    "value": {
                      "success": false,
                      "error": "The 'candidates' field must be an array"
                    }
                  },
                  "candidates-cannot-be-empty": {
                    "summary": "candidates cannot be empty",
                    "value": {
                      "success": false,
                      "error": "candidates cannot be empty"
                    }
                  },
                  "candidates-must-contain-10-candidates-or-fewer": {
                    "summary": "candidates must contain 10 candidates or fewer",
                    "value": {
                      "success": false,
                      "error": "candidates must contain 10 candidates or fewer"
                    }
                  },
                  "candidates-contains-an-invalid-candidate": {
                    "summary": "candidates contains an invalid candidate",
                    "value": {
                      "success": false,
                      "error": "candidates contains an invalid candidate"
                    }
                  },
                  "candidate-text-must-be-50000-characters-or-less": {
                    "summary": "candidate_text must be 50000 characters or less",
                    "value": {
                      "success": false,
                      "error": "candidate_text must be 50000 characters or less"
                    }
                  },
                  "candidates-contains-duplicate-ids": {
                    "summary": "candidates contains duplicate ids",
                    "value": {
                      "success": false,
                      "error": "candidates contains duplicate ids"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "- `Missing API Key`: The `X-API-Key` header is absent. `Authorization: Bearer` is not accepted. Do not retry.\n- `Invalid API Key`: The key is malformed, unknown or revoked. Rotating a key revokes the previous one immediately. Do not retry.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/GatewayError"
                },
                "examples": {
                  "missing-api-key": {
                    "summary": "Missing API Key",
                    "value": {
                      "error": "Missing API Key"
                    }
                  },
                  "invalid-api-key": {
                    "summary": "Invalid API Key",
                    "value": {
                      "error": "Invalid API Key"
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "- `Insufficient credits available`: The account has no credit left. `availableCredits` is the current balance. Fix, then retry.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/GatewayError"
                },
                "examples": {
                  "insufficient-credits-available": {
                    "summary": "Insufficient credits available",
                    "value": {
                      "error": "Insufficient credits available",
                      "availableCredits": 0
                    }
                  }
                }
              }
            }
          },
          "500": {
            "description": "- `Internal server error`: Unexpected gateway failure. Retry with backoff.\n- `Internal server error. Please try again later.`: The body is not valid JSON, is a JSON primitive or exceeds 10 MB, or the service failed unexpectedly. Check the payload: if it is valid, retry. Retry with backoff.",
            "content": {
              "application/json": {
                "schema": {
                  "oneOf": [
                    {
                      "$ref": "#/components/schemas/GatewayError"
                    },
                    {
                      "$ref": "#/components/schemas/ServiceError"
                    }
                  ]
                },
                "examples": {
                  "internal-server-error": {
                    "summary": "Internal server error",
                    "value": {
                      "error": "Internal server error"
                    }
                  },
                  "internal-server-error-please-try-again-later": {
                    "summary": "Internal server error. Please try again later.",
                    "value": {
                      "success": false,
                      "error": "Internal server error. Please try again later."
                    }
                  }
                }
              }
            }
          },
          "502": {
            "description": "- `Upstream API unavailable`: The service did not answer within 60 seconds, or could not be reached. Retry with backoff.\n- `The AI processing step failed. Please try again later.`: Ranking failed or returned an invalid result after the service's internal retries. Retry with backoff.",
            "content": {
              "application/json": {
                "schema": {
                  "oneOf": [
                    {
                      "$ref": "#/components/schemas/GatewayError"
                    },
                    {
                      "$ref": "#/components/schemas/ServiceError"
                    }
                  ]
                },
                "examples": {
                  "upstream-api-unavailable": {
                    "summary": "Upstream API unavailable",
                    "value": {
                      "error": "Upstream API unavailable"
                    }
                  },
                  "the-ai-processing-step-failed-please-try-again-later": {
                    "summary": "The AI processing step failed. Please try again later.",
                    "value": {
                      "success": false,
                      "error": "The AI processing step failed. Please try again later."
                    }
                  }
                }
              }
            }
          },
          "503": {
            "description": "- `Credit service temporarily unavailable`: Credits could not be checked or deducted. No credit is consumed, including when the operation itself had completed. Retry with backoff.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/GatewayError"
                },
                "examples": {
                  "credit-service-temporarily-unavailable": {
                    "summary": "Credit service temporarily unavailable",
                    "value": {
                      "error": "Credit service temporarily unavailable"
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/skills/resolve": {
      "post": {
        "operationId": "resolveSkills",
        "summary": "Resolve skills",
        "description": "Turn free text, from one skill to a whole skills section, into taxonomy skills with their families and domains.\n\n**Billing:** 1 credit per successful call.\n\n**Latency:** Synchronous. Most calls answer in well under a second; a long skills section can take 10 seconds or more. The gateway waits up to 60 seconds; use a client timeout of at least 65 seconds.\n\n**Resolution:** There is no score and no threshold: every part of the text is either resolved to taxonomy skills or listed in `unresolved`. A compound mention can yield several skills (`Pack Office (Word, Excel)` gives Microsoft Office, Word and Excel), and a skill named twice is returned once.\n\n**Storage:** Store `id` rather than `name`: names depend on `language`, ids do not. Keep `taxonomy_version` with your results and resolve them again when it changes.\n\n**Strict body:** Only `text` and `language` are accepted. The former `/api/v1/skills/match` fields (`skill`, `skills`, `top_k`) are rejected, and `POST /api/v1/skills/match` now answers `410`.\n\nReference: https://hirelayer.co/api-docs/skills#skills-resolve",
        "tags": [
          "HireLayer Skills"
        ],
        "x-stability": "stable",
        "x-client-timeout-seconds": 65,
        "externalDocs": {
          "url": "https://hirelayer.co/api-docs/skills#skills-resolve"
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ResolveSkillsRequest"
              },
              "examples": {
                "default": {
                  "value": {
                    "text": "Google Sheet/Excel",
                    "language": "fr"
                  }
                },
                "skills-section-names-in-english": {
                  "summary": "Skills section, names in English",
                  "value": {
                    "text": "React, Node, Cobol, gestion de projet",
                    "language": "en"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Skills found in the text.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ResolveSkillsResponse"
                },
                "examples": {
                  "example-1": {
                    "summary": "Skills found in the text.",
                    "value": {
                      "language": "fr",
                      "skills": [
                        {
                          "id": "google_sheets",
                          "name": "Google Sheets",
                          "type": "software",
                          "mention": "Google Sheet",
                          "families": [
                            {
                              "id": "office_software",
                              "name": "Bureautique",
                              "domain_id": "administration_office"
                            },
                            {
                              "id": "data_analysis",
                              "name": "Analyse de données",
                              "domain_id": "data_ai"
                            },
                            {
                              "id": "business_intelligence",
                              "name": "Business Intelligence & dataviz",
                              "domain_id": "data_ai"
                            }
                          ],
                          "domains": [
                            {
                              "id": "administration_office",
                              "name": "Administration & Bureautique"
                            },
                            {
                              "id": "data_ai",
                              "name": "Data & Intelligence artificielle"
                            }
                          ],
                          "broader": null
                        },
                        {
                          "id": "excel",
                          "name": "Excel",
                          "type": "software",
                          "mention": "Excel",
                          "families": [
                            {
                              "id": "office_software",
                              "name": "Bureautique",
                              "domain_id": "administration_office"
                            },
                            {
                              "id": "data_analysis",
                              "name": "Analyse de données",
                              "domain_id": "data_ai"
                            }
                          ],
                          "domains": [
                            {
                              "id": "administration_office",
                              "name": "Administration & Bureautique"
                            },
                            {
                              "id": "data_ai",
                              "name": "Data & Intelligence artificielle"
                            }
                          ],
                          "broader": {
                            "id": "microsoft_office",
                            "name": "Microsoft Office"
                          }
                        }
                      ],
                      "unresolved": [],
                      "taxonomy_version": "v1"
                    }
                  },
                  "skills-section-names-in-english": {
                    "summary": "Skills section, names in English",
                    "value": {
                      "language": "en",
                      "skills": [
                        {
                          "id": "react",
                          "name": "React",
                          "type": "software",
                          "mention": "React",
                          "families": [
                            {
                              "id": "frontend_development",
                              "name": "Frontend development",
                              "domain_id": "software_development"
                            }
                          ],
                          "domains": [
                            {
                              "id": "software_development",
                              "name": "Software Development"
                            }
                          ],
                          "broader": null
                        },
                        {
                          "id": "node_js",
                          "name": "Node.js",
                          "type": "software",
                          "mention": "Node",
                          "families": [
                            {
                              "id": "backend_development",
                              "name": "Backend development",
                              "domain_id": "software_development"
                            },
                            {
                              "id": "programming_languages",
                              "name": "Programming languages",
                              "domain_id": "software_development"
                            }
                          ],
                          "domains": [
                            {
                              "id": "software_development",
                              "name": "Software Development"
                            }
                          ],
                          "broader": null
                        },
                        {
                          "id": "cobol",
                          "name": "COBOL",
                          "type": "software",
                          "mention": "Cobol",
                          "families": [
                            {
                              "id": "programming_languages",
                              "name": "Programming languages",
                              "domain_id": "software_development"
                            },
                            {
                              "id": "backend_development",
                              "name": "Backend development",
                              "domain_id": "software_development"
                            }
                          ],
                          "domains": [
                            {
                              "id": "software_development",
                              "name": "Software Development"
                            }
                          ],
                          "broader": null
                        },
                        {
                          "id": "project_management",
                          "name": "Project management",
                          "type": "hard",
                          "mention": "gestion de projet",
                          "families": [
                            {
                              "id": "project_management",
                              "name": "Project management",
                              "domain_id": "management_strategy"
                            }
                          ],
                          "domains": [
                            {
                              "id": "management_strategy",
                              "name": "Management, Projects & Strategy"
                            }
                          ],
                          "broader": null
                        }
                      ],
                      "unresolved": [],
                      "taxonomy_version": "v1"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "- `Request body must be a JSON object`: The body is missing, is a JSON array, or `Content-Type` is not `application/json`. Do not retry.\n- `Unknown field(s): unexpected_field. Accepted: 'text' and optional 'language'`: The body contains another field than `text` and `language` (for example `skill`, `skills` or `top_k`); the message names them. Do not retry.\n- `The 'text' field (string) is required`: `text` is missing or not a string. Do not retry.\n- `Text cannot be empty`: `text` is empty after trimming. Do not retry.\n- `'text' must be at most 5000 characters`: `text` is longer than 5,000 characters. Do not retry.\n- `'language' must be 'fr' or 'en'`: `language` is present but is not `fr` or `en` (case-sensitive; `null` is rejected). Do not retry.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ServiceError"
                },
                "examples": {
                  "request-body-must-be-a-json-object": {
                    "summary": "Request body must be a JSON object",
                    "value": {
                      "success": false,
                      "error": "Request body must be a JSON object"
                    }
                  },
                  "unknown-field-s-unexpected-field-accepted-text-and-optional-language": {
                    "summary": "Unknown field(s): unexpected_field. Accepted: 'text' and optional 'language'",
                    "value": {
                      "success": false,
                      "error": "Unknown field(s): unexpected_field. Accepted: 'text' and optional 'language'"
                    }
                  },
                  "the-text-field-string-is-required": {
                    "summary": "The 'text' field (string) is required",
                    "value": {
                      "success": false,
                      "error": "The 'text' field (string) is required"
                    }
                  },
                  "text-cannot-be-empty": {
                    "summary": "Text cannot be empty",
                    "value": {
                      "success": false,
                      "error": "Text cannot be empty"
                    }
                  },
                  "text-must-be-at-most-5000-characters": {
                    "summary": "'text' must be at most 5000 characters",
                    "value": {
                      "success": false,
                      "error": "'text' must be at most 5000 characters"
                    }
                  },
                  "language-must-be-fr-or-en": {
                    "summary": "'language' must be 'fr' or 'en'",
                    "value": {
                      "success": false,
                      "error": "'language' must be 'fr' or 'en'"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "- `Missing API Key`: The `X-API-Key` header is absent. `Authorization: Bearer` is not accepted. Do not retry.\n- `Invalid API Key`: The key is malformed, unknown or revoked. Rotating a key revokes the previous one immediately. Do not retry.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/GatewayError"
                },
                "examples": {
                  "missing-api-key": {
                    "summary": "Missing API Key",
                    "value": {
                      "error": "Missing API Key"
                    }
                  },
                  "invalid-api-key": {
                    "summary": "Invalid API Key",
                    "value": {
                      "error": "Invalid API Key"
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "- `Insufficient credits available`: The account has no credit left. `availableCredits` is the current balance. Fix, then retry.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/GatewayError"
                },
                "examples": {
                  "insufficient-credits-available": {
                    "summary": "Insufficient credits available",
                    "value": {
                      "error": "Insufficient credits available",
                      "availableCredits": 0
                    }
                  }
                }
              }
            }
          },
          "500": {
            "description": "- `Internal server error`: Unexpected gateway failure. Retry with backoff.\n- `Internal server error. Please try again later.`: The body is not valid JSON, is a JSON primitive or exceeds 10 MB, or the service failed unexpectedly. Check the payload: if it is valid, retry. Retry with backoff.",
            "content": {
              "application/json": {
                "schema": {
                  "oneOf": [
                    {
                      "$ref": "#/components/schemas/GatewayError"
                    },
                    {
                      "$ref": "#/components/schemas/ServiceError"
                    }
                  ]
                },
                "examples": {
                  "internal-server-error": {
                    "summary": "Internal server error",
                    "value": {
                      "error": "Internal server error"
                    }
                  },
                  "internal-server-error-please-try-again-later": {
                    "summary": "Internal server error. Please try again later.",
                    "value": {
                      "success": false,
                      "error": "Internal server error. Please try again later."
                    }
                  }
                }
              }
            }
          },
          "502": {
            "description": "- `Upstream API unavailable`: The service did not answer within 60 seconds, or could not be reached. Retry with backoff.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/GatewayError"
                },
                "examples": {
                  "upstream-api-unavailable": {
                    "summary": "Upstream API unavailable",
                    "value": {
                      "error": "Upstream API unavailable"
                    }
                  }
                }
              }
            }
          },
          "503": {
            "description": "- `Credit service temporarily unavailable`: Credits could not be checked or deducted. No credit is consumed, including when the operation itself had completed. Retry with backoff.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/GatewayError"
                },
                "examples": {
                  "credit-service-temporarily-unavailable": {
                    "summary": "Credit service temporarily unavailable",
                    "value": {
                      "error": "Credit service temporarily unavailable"
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/skills": {
      "get": {
        "operationId": "listSkills",
        "summary": "List the skills taxonomy",
        "description": "Download every skill of the taxonomy with its families, domains and broader skill.\n\n**Billing:** 1 credit per successful call.\n\n**Language:** Add `?language=en` for English names; French is the default.\n\n**Size and caching:** The response holds the whole taxonomy (about 4 MB) and costs a credit: cache it on your side, for example once a day, and refresh it when `taxonomy_version` changes.\n\nReference: https://hirelayer.co/api-docs/skills#skills-catalog",
        "tags": [
          "HireLayer Skills"
        ],
        "x-stability": "stable",
        "x-client-timeout-seconds": 65,
        "externalDocs": {
          "url": "https://hirelayer.co/api-docs/skills#skills-catalog"
        },
        "parameters": [
          {
            "name": "language",
            "in": "query",
            "required": false,
            "description": "`fr` (default) or `en`.",
            "schema": {
              "type": "string",
              "enum": [
                "fr",
                "en"
              ]
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The taxonomy (first two of 11,061 skills shown).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ListSkillsResponse"
                },
                "examples": {
                  "example-1": {
                    "summary": "The taxonomy (first two of 11,061 skills shown).",
                    "value": {
                      "language": "fr",
                      "total": 11061,
                      "skills": [
                        {
                          "id": "teamwork",
                          "name": "Travail en équipe",
                          "type": "soft",
                          "families": [
                            {
                              "id": "teamwork",
                              "name": "Travail en équipe & coopération",
                              "domain_id": "soft_skills"
                            }
                          ],
                          "domains": [
                            {
                              "id": "soft_skills",
                              "name": "Compétences comportementales"
                            }
                          ],
                          "broader": null
                        },
                        {
                          "id": "microsoft_office",
                          "name": "Microsoft Office",
                          "type": "software",
                          "families": [
                            {
                              "id": "office_software",
                              "name": "Bureautique",
                              "domain_id": "administration_office"
                            }
                          ],
                          "domains": [
                            {
                              "id": "administration_office",
                              "name": "Administration & Bureautique"
                            }
                          ],
                          "broader": null
                        }
                      ],
                      "taxonomy_version": "v1"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "- `'language' must be 'fr' or 'en'`: The `language` query parameter is present but is not `fr` or `en` (case-sensitive). Do not retry.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ServiceError"
                },
                "examples": {
                  "language-must-be-fr-or-en": {
                    "summary": "'language' must be 'fr' or 'en'",
                    "value": {
                      "success": false,
                      "error": "'language' must be 'fr' or 'en'"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "- `Missing API Key`: The `X-API-Key` header is absent. `Authorization: Bearer` is not accepted. Do not retry.\n- `Invalid API Key`: The key is malformed, unknown or revoked. Rotating a key revokes the previous one immediately. Do not retry.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/GatewayError"
                },
                "examples": {
                  "missing-api-key": {
                    "summary": "Missing API Key",
                    "value": {
                      "error": "Missing API Key"
                    }
                  },
                  "invalid-api-key": {
                    "summary": "Invalid API Key",
                    "value": {
                      "error": "Invalid API Key"
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "- `Insufficient credits available`: The account has no credit left. `availableCredits` is the current balance. Fix, then retry.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/GatewayError"
                },
                "examples": {
                  "insufficient-credits-available": {
                    "summary": "Insufficient credits available",
                    "value": {
                      "error": "Insufficient credits available",
                      "availableCredits": 0
                    }
                  }
                }
              }
            }
          },
          "500": {
            "description": "- `Internal server error`: Unexpected gateway failure. Retry with backoff.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/GatewayError"
                },
                "examples": {
                  "internal-server-error": {
                    "summary": "Internal server error",
                    "value": {
                      "error": "Internal server error"
                    }
                  }
                }
              }
            }
          },
          "502": {
            "description": "- `Upstream API unavailable`: The service did not answer within 60 seconds, or could not be reached. Retry with backoff.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/GatewayError"
                },
                "examples": {
                  "upstream-api-unavailable": {
                    "summary": "Upstream API unavailable",
                    "value": {
                      "error": "Upstream API unavailable"
                    }
                  }
                }
              }
            }
          },
          "503": {
            "description": "- `Credit service temporarily unavailable`: Credits could not be checked or deducted. No credit is consumed, including when the operation itself had completed. Retry with backoff.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/GatewayError"
                },
                "examples": {
                  "credit-service-temporarily-unavailable": {
                    "summary": "Credit service temporarily unavailable",
                    "value": {
                      "error": "Credit service temporarily unavailable"
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/health": {
      "get": {
        "operationId": "getHealth",
        "summary": "Check API health",
        "description": "Check that the Job Extract, Match, Skills and Rank service is up. No API key needed.\n\n**Billing:** Free.\n\n**Scope:** Covers the service behind `/api/v1`. It does not check HireLayer CV Extract (`/api/v3/parser`), and it does not validate API keys.\n\nReference: https://hirelayer.co/api-docs/health#health",
        "tags": [
          "Platform"
        ],
        "security": [],
        "x-stability": "stable",
        "x-client-timeout-seconds": 10,
        "externalDocs": {
          "url": "https://hirelayer.co/api-docs/health#health"
        },
        "responses": {
          "200": {
            "description": "The service is up.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/GetHealthResponse"
                },
                "examples": {
                  "example-1": {
                    "summary": "The service is up.",
                    "value": {
                      "status": "healthy",
                      "service": "HireLayer API",
                      "timestamp": "2026-10-01T09:30:12.417Z"
                    }
                  }
                }
              }
            }
          },
          "502": {
            "description": "- `Upstream API unavailable`: The service is down or did not answer within 60 seconds. Retry with backoff.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/GatewayError"
                },
                "examples": {
                  "upstream-api-unavailable": {
                    "summary": "Upstream API unavailable",
                    "value": {
                      "error": "Upstream API unavailable"
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/me": {
      "get": {
        "operationId": "getMe",
        "summary": "Check an API key",
        "description": "Check that an API key is valid and see the account and credit balance it belongs to. Integrations use it to test a connection.\n\n**Billing:** Free.\n\n**Billing:** Free and not counted as API usage, so a connection test in n8n, Zapier, Make or Power Automate never spends a credit.\n\nReference: https://hirelayer.co/api-docs/health#me",
        "tags": [
          "Platform"
        ],
        "x-stability": "stable",
        "x-client-timeout-seconds": 10,
        "externalDocs": {
          "url": "https://hirelayer.co/api-docs/health#me"
        },
        "responses": {
          "200": {
            "description": "The key is valid.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/GetMeResponse"
                },
                "examples": {
                  "example-1": {
                    "summary": "The key is valid.",
                    "value": {
                      "authenticated": true,
                      "account": {
                        "email": "alex@example.com",
                        "plan": "starter"
                      },
                      "credits": {
                        "available": 742,
                        "unlimited": false
                      }
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "- `Missing API Key`: The `X-API-Key` header is absent. `Authorization: Bearer` is not accepted. Do not retry.\n- `Invalid API Key`: The key is malformed, unknown or revoked. Rotating a key revokes the previous one immediately. Do not retry.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/GatewayError"
                },
                "examples": {
                  "missing-api-key": {
                    "summary": "Missing API Key",
                    "value": {
                      "error": "Missing API Key"
                    }
                  },
                  "invalid-api-key": {
                    "summary": "Invalid API Key",
                    "value": {
                      "error": "Invalid API Key"
                    }
                  }
                }
              }
            }
          },
          "500": {
            "description": "- `Internal server error`: Unexpected gateway failure. Retry with backoff.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/GatewayError"
                },
                "examples": {
                  "internal-server-error": {
                    "summary": "Internal server error",
                    "value": {
                      "error": "Internal server error"
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/api/v2/parser": {
      "post": {
        "operationId": "parseResumeV2",
        "summary": "Submit a resume (legacy V2)",
        "description": "Legacy asynchronous contract: the request is accepted with `202` and the result is posted to `webhook_url`.\n\n**Billing:** 1 credit when the request is accepted (HTTP 202).\n\n**Asynchronous:** The gateway waits up to 45 seconds for the request to be accepted. The webhook then receives `{\"status\": \"success\", …}` with the parsed resume, or `{\"status\": \"failure\", \"error_code\": …, \"error_message\": …}`.\n\n**Billing:** The credit is consumed when the request is accepted, even if processing fails later.\n\nReference: https://hirelayer.co/api-docs/extract-v2#parse-resume-v2",
        "tags": [
          "HireLayer CV Extract"
        ],
        "deprecated": true,
        "x-stability": "legacy",
        "x-client-timeout-seconds": 50,
        "externalDocs": {
          "url": "https://hirelayer.co/api-docs/extract-v2#parse-resume-v2"
        },
        "requestBody": {
          "required": true,
          "content": {
            "multipart/form-data": {
              "schema": {
                "$ref": "#/components/schemas/ParseResumeV2Request"
              }
            }
          }
        },
        "responses": {
          "202": {
            "description": "Accepted. The result is sent to `webhook_url` later.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ParseResumeV2Response"
                },
                "examples": {
                  "example-1": {
                    "summary": "Accepted. The result is sent to `webhook_url` later.",
                    "value": {
                      "message": "CV processing initiated.",
                      "body": null,
                      "error": false
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "- `An error occurred while processing the document or extracting its text. Please try again later.`: Any error from the legacy parser is returned with its status code (`400` for a missing file or `webhook_url`, unsupported type…) and this generic message. Do not retry.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/GatewayError"
                },
                "examples": {
                  "an-error-occurred-while-processing-the-document-or-extracting-its-text-please-try-again-later": {
                    "summary": "An error occurred while processing the document or extracting its text. Please try again later.",
                    "value": {
                      "error": "An error occurred while processing the document or extracting its text. Please try again later."
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "- `Missing API Key`: The `X-API-Key` header is absent. `Authorization: Bearer` is not accepted. Do not retry.\n- `Invalid API Key`: The key is malformed, unknown or revoked. Rotating a key revokes the previous one immediately. Do not retry.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/GatewayError"
                },
                "examples": {
                  "missing-api-key": {
                    "summary": "Missing API Key",
                    "value": {
                      "error": "Missing API Key"
                    }
                  },
                  "invalid-api-key": {
                    "summary": "Invalid API Key",
                    "value": {
                      "error": "Invalid API Key"
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "- `Insufficient credits available`: The account has no credit left. Fix, then retry.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/GatewayError"
                },
                "examples": {
                  "insufficient-credits-available": {
                    "summary": "Insufficient credits available",
                    "value": {
                      "error": "Insufficient credits available"
                    }
                  }
                }
              }
            }
          },
          "415": {
            "description": "- `Content-Type must be multipart/form-data`: The request is not `multipart/form-data`. Do not retry.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/GatewayError"
                },
                "examples": {
                  "content-type-must-be-multipart-form-data": {
                    "summary": "Content-Type must be multipart/form-data",
                    "value": {
                      "error": "Content-Type must be multipart/form-data"
                    }
                  }
                }
              }
            }
          },
          "503": {
            "description": "- `Credit service temporarily unavailable`: Credits could not be checked or deducted. No credit is consumed, including when the operation itself had completed. Retry with backoff.",
            "headers": {
              "Retry-After": {
                "description": "Seconds to wait before retrying.",
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/GatewayError"
                },
                "examples": {
                  "credit-service-temporarily-unavailable": {
                    "summary": "Credit service temporarily unavailable",
                    "value": {
                      "error": "Credit service temporarily unavailable"
                    }
                  }
                }
              }
            }
          }
        }
      }
    }
  },
  "components": {
    "securitySchemes": {
      "ApiKeyAuth": {
        "type": "apiKey",
        "in": "header",
        "name": "X-API-Key",
        "description": "API key from the dashboard. `Authorization: Bearer` is not supported."
      }
    },
    "schemas": {
      "GatewayError": {
        "type": "object",
        "description": "Error returned by the HireLayer gateway (authentication, credits, CV Extract).",
        "properties": {
          "error": {
            "type": "string",
            "description": "Human-readable message."
          },
          "code": {
            "type": "string",
            "description": "Machine-readable code (CV Extract errors only).",
            "enum": [
              "INVALID_MULTIPART_BODY",
              "INVALID_FILE",
              "DOCUMENT_NOT_A_RESUME",
              "DOCUMENT_TEXT_EMPTY",
              "DOCUMENT_UNREADABLE",
              "DOCUMENT_TOO_LARGE",
              "PARSER_UNAVAILABLE"
            ]
          },
          "availableCredits": {
            "type": "integer",
            "description": "Current balance, on `403` from `/api/v1` endpoints."
          }
        },
        "required": [
          "error"
        ]
      },
      "ServiceError": {
        "type": "object",
        "description": "Error returned by the Job Extract, Match, Rank and Skills services.",
        "properties": {
          "success": {
            "const": false
          },
          "error": {
            "type": "string",
            "description": "Human-readable message."
          }
        },
        "required": [
          "success",
          "error"
        ]
      },
      "ParseResumeRequest": {
        "type": "object",
        "properties": {
          "file": {
            "type": "string",
            "format": "binary",
            "description": "The resume: PDF, DOC, DOCX, ODT, PPT, PPTX, ODP, XLS, RTF, TXT, JPG/JPEG, PNG or BMP. The type is detected from the content. Keep it under 4.5 MB."
          },
          "application_id": {
            "description": "Your own reference, echoed in `info_resume.application_id`.",
            "type": "string"
          },
          "webhook_url": {
            "description": "HTTP(S) URL that also receives the result. The response stays synchronous unless you send `Prefer: respond-async` (HTTPS URL required). See [Webhook](#webhook) and [Asynchronous mode](#async).",
            "type": "string",
            "format": "uri"
          },
          "do_not_store_data": {
            "description": "`true`: the resume file is **not stored**. `info_resume.url` is then `null`, and the cropped photo is only reachable through a temporary link valid 10 minutes. Case-insensitive. Defaults to `false` (file stored).",
            "type": "string",
            "enum": [
              "true",
              "false"
            ]
          }
        },
        "required": [
          "file"
        ]
      },
      "ParseResumeResponse": {
        "type": "object",
        "properties": {
          "status": {
            "type": "string",
            "const": "accepted"
          },
          "application_id": {
            "description": "Your `application_id`, or `null` when not sent.",
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ]
          }
        },
        "required": [
          "status",
          "application_id"
        ],
        "description": "Accepted in [asynchronous mode](#async): the outcome is posted to `webhook_url`."
      },
      "ExtractJobCriteriaRequest": {
        "type": "object",
        "properties": {
          "job_text": {
            "description": "Full job description, in any language. Trimmed before validation.",
            "type": "string",
            "minLength": 1,
            "maxLength": 50000
          }
        },
        "required": [
          "job_text"
        ],
        "additionalProperties": false
      },
      "ExtractJobCriteriaResponse": {
        "type": "object",
        "properties": {
          "matching_criteria": {
            "description": "Criteria sorted by `weight`, highest first, with IDs `crit_1`…`crit_n` in that order. Can be empty.",
            "type": "array",
            "items": {
              "title": "MatchingCriterion",
              "type": "object",
              "properties": {
                "id": {
                  "description": "Criterion ID. Job Extract generates `crit_1`…`crit_n`; Match accepts any non-empty string.",
                  "type": "string",
                  "minLength": 1
                },
                "label": {
                  "description": "What is evaluated, in a short phrase.",
                  "type": "string",
                  "minLength": 1
                },
                "weight": {
                  "description": "Importance: `3` essential, `2` important, `1` nice to have.",
                  "type": "integer",
                  "minimum": 1,
                  "maximum": 3
                },
                "is_mandatory": {
                  "description": "Whether the job states it as a hard requirement. Informational: it does not change the Match score.",
                  "type": "boolean"
                },
                "rationale": {
                  "description": "Why the criterion matters for the job.",
                  "type": "string",
                  "minLength": 1
                }
              },
              "required": [
                "id",
                "label",
                "weight",
                "is_mandatory",
                "rationale"
              ]
            }
          }
        },
        "required": [
          "matching_criteria"
        ],
        "description": "Extracted criteria."
      },
      "MatchCandidateRequest": {
        "type": "object",
        "properties": {
          "job_text": {
            "description": "Job description. Trimmed before validation.",
            "type": "string",
            "minLength": 1,
            "maxLength": 50000
          },
          "candidate_text": {
            "description": "Candidate resume as plain text, e.g. `info_resume.text` from HireLayer CV Extract. Trimmed before validation.",
            "type": "string",
            "minLength": 1,
            "maxLength": 50000
          },
          "matching_criteria": {
            "description": "Criteria to evaluate, usually from HireLayer Job Extract. Can be empty. No other criterion field is accepted.",
            "type": "array",
            "items": {
              "title": "MatchingCriterion",
              "type": "object",
              "properties": {
                "id": {
                  "description": "Criterion ID. Job Extract generates `crit_1`…`crit_n`; Match accepts any non-empty string.",
                  "type": "string",
                  "minLength": 1
                },
                "label": {
                  "description": "What is evaluated, in a short phrase.",
                  "type": "string",
                  "minLength": 1
                },
                "weight": {
                  "description": "Importance: `3` essential, `2` important, `1` nice to have.",
                  "type": "integer",
                  "minimum": 1,
                  "maximum": 3
                },
                "is_mandatory": {
                  "description": "Whether the job states it as a hard requirement. Informational: it does not change the Match score.",
                  "type": "boolean"
                },
                "rationale": {
                  "description": "Why the criterion matters for the job.",
                  "type": "string",
                  "minLength": 1
                }
              },
              "required": [
                "id",
                "label",
                "weight",
                "is_mandatory",
                "rationale"
              ],
              "additionalProperties": false
            }
          }
        },
        "required": [
          "job_text",
          "candidate_text",
          "matching_criteria"
        ],
        "additionalProperties": false
      },
      "MatchCandidateResponse": {
        "type": "object",
        "properties": {
          "score": {
            "description": "Weighted average of the criterion statuses. Not rounded.",
            "type": "number",
            "minimum": 0,
            "maximum": 1
          },
          "summary": {
            "description": "Overall assessment, in French.",
            "type": "string"
          },
          "evaluated_criteria": {
            "description": "Every input criterion, in input order, with its evaluation.",
            "type": "array",
            "items": {
              "title": "EvaluatedCriterion",
              "type": "object",
              "properties": {
                "id": {
                  "description": "Criterion ID. Job Extract generates `crit_1`…`crit_n`; Match accepts any non-empty string.",
                  "type": "string",
                  "minLength": 1
                },
                "label": {
                  "description": "What is evaluated, in a short phrase.",
                  "type": "string",
                  "minLength": 1
                },
                "weight": {
                  "description": "Importance: `3` essential, `2` important, `1` nice to have.",
                  "type": "integer",
                  "minimum": 1,
                  "maximum": 3
                },
                "is_mandatory": {
                  "description": "Whether the job states it as a hard requirement. Informational: it does not change the Match score.",
                  "type": "boolean"
                },
                "rationale": {
                  "description": "Why the criterion matters for the job.",
                  "type": "string",
                  "minLength": 1
                },
                "match_status": {
                  "description": "`ideal`: clearly met · `potential`: partly or indirectly met · `not_mentioned`: the resume says nothing · `not_valid`: contradicted.",
                  "type": "string",
                  "enum": [
                    "ideal",
                    "potential",
                    "not_valid",
                    "not_mentioned"
                  ]
                },
                "match_explanation": {
                  "description": "Evidence from the resume, in French.",
                  "type": "string"
                }
              },
              "required": [
                "id",
                "label",
                "weight",
                "is_mandatory",
                "rationale",
                "match_status",
                "match_explanation"
              ]
            }
          }
        },
        "required": [
          "score",
          "summary",
          "evaluated_criteria"
        ],
        "description": "Evaluation of every criterion."
      },
      "RankCandidatesRequest": {
        "type": "object",
        "properties": {
          "job_text": {
            "description": "Job description. Trimmed before validation.",
            "type": "string",
            "minLength": 1,
            "maxLength": 50000
          },
          "candidates": {
            "description": "Candidates to rank against the same job.",
            "minItems": 1,
            "maxItems": 10,
            "type": "array",
            "items": {
              "title": "RankingCandidate",
              "type": "object",
              "properties": {
                "id": {
                  "description": "Your candidate ID. Unique within the request after trimming.",
                  "type": "string",
                  "minLength": 1
                },
                "candidate_text": {
                  "description": "Resume as plain text. Trimmed before validation.",
                  "type": "string",
                  "minLength": 1,
                  "maxLength": 50000
                }
              },
              "required": [
                "id",
                "candidate_text"
              ],
              "additionalProperties": false
            }
          }
        },
        "required": [
          "job_text",
          "candidates"
        ],
        "additionalProperties": false
      },
      "RankCandidatesResponse": {
        "type": "object",
        "properties": {
          "rankings": {
            "description": "One entry per candidate, sorted by `rank`.",
            "type": "array",
            "items": {
              "title": "Ranking",
              "type": "object",
              "properties": {
                "rank": {
                  "description": "Position from 1 (best) to the number of candidates.",
                  "type": "integer",
                  "minimum": 1
                },
                "candidate_id": {
                  "description": "The `id` you sent, trimmed.",
                  "type": "string"
                },
                "score": {
                  "description": "Relevance for the job. Use `rank` for ordering.",
                  "type": "number",
                  "minimum": 0,
                  "maximum": 1
                },
                "rationale": {
                  "description": "Why the candidate holds this position, in French.",
                  "type": "string"
                }
              },
              "required": [
                "rank",
                "candidate_id",
                "score",
                "rationale"
              ]
            }
          }
        },
        "required": [
          "rankings"
        ],
        "description": "Ranked candidates."
      },
      "ResolveSkillsRequest": {
        "type": "object",
        "properties": {
          "text": {
            "description": "Free text in French or English: one skill (`MS Excel`), a compound string (`Pack Office (Word, Excel)`) or a whole skills section (lines, bullets, `;`, comma lists).",
            "type": "string",
            "minLength": 1,
            "maxLength": 5000
          },
          "language": {
            "description": "`fr` (default) or `en`.",
            "type": "string",
            "enum": [
              "fr",
              "en"
            ]
          }
        },
        "required": [
          "text"
        ],
        "additionalProperties": false
      },
      "ResolveSkillsResponse": {
        "type": "object",
        "properties": {
          "language": {
            "description": "Language of the names returned.",
            "type": "string",
            "enum": [
              "fr",
              "en"
            ]
          },
          "skills": {
            "description": "Taxonomy skills named in the text, in the order of the text.",
            "type": "array",
            "items": {
              "title": "ResolvedSkill",
              "type": "object",
              "properties": {
                "id": {
                  "description": "Stable skill id, e.g. `excel`. Store and filter on it.",
                  "type": "string"
                },
                "name": {
                  "description": "Canonical name in the requested language.",
                  "type": "string"
                },
                "type": {
                  "type": "string",
                  "enum": [
                    "hard",
                    "software",
                    "certification",
                    "soft",
                    "language"
                  ]
                },
                "families": {
                  "description": "Families of the skill, the primary one first.",
                  "type": "array",
                  "items": {
                    "title": "SkillFamilyRef",
                    "type": "object",
                    "properties": {
                      "id": {
                        "description": "Stable family id, e.g. `office_software`.",
                        "type": "string"
                      },
                      "name": {
                        "description": "Family name in the requested language.",
                        "type": "string"
                      },
                      "domain_id": {
                        "description": "Id of the domain the family belongs to.",
                        "type": "string"
                      }
                    },
                    "required": [
                      "id",
                      "name",
                      "domain_id"
                    ]
                  }
                },
                "domains": {
                  "description": "Domains of those families, the primary one first.",
                  "type": "array",
                  "items": {
                    "title": "SkillDomainRef",
                    "type": "object",
                    "properties": {
                      "id": {
                        "description": "Stable domain id, e.g. `data_ai`.",
                        "type": "string"
                      },
                      "name": {
                        "description": "Domain name in the requested language.",
                        "type": "string"
                      }
                    },
                    "required": [
                      "id",
                      "name"
                    ]
                  }
                },
                "broader": {
                  "description": "A more general skill to widen a search to (Excel → Microsoft Office), or `null`.",
                  "anyOf": [
                    {
                      "title": "BroaderSkill",
                      "type": "object",
                      "properties": {
                        "id": {
                          "type": "string"
                        },
                        "name": {
                          "type": "string"
                        }
                      },
                      "required": [
                        "id",
                        "name"
                      ]
                    },
                    {
                      "type": "null"
                    }
                  ]
                },
                "mention": {
                  "description": "The part of the text the skill was found in.",
                  "type": "string"
                }
              },
              "required": [
                "id",
                "name",
                "type",
                "families",
                "domains",
                "broader",
                "mention"
              ]
            }
          },
          "unresolved": {
            "description": "Parts of the text that match no taxonomy skill.",
            "type": "array",
            "items": {
              "title": "UnresolvedSkill",
              "type": "object",
              "properties": {
                "text": {
                  "description": "Part of the text matching no skill.",
                  "type": "string"
                },
                "family_hints": {
                  "description": "Families it probably belongs to, possibly none. No skill is guessed.",
                  "type": "array",
                  "items": {
                    "type": "object",
                    "properties": {
                      "id": {
                        "type": "string"
                      },
                      "name": {
                        "type": "string"
                      }
                    },
                    "required": [
                      "id",
                      "name"
                    ]
                  }
                }
              },
              "required": [
                "text",
                "family_hints"
              ]
            }
          },
          "taxonomy_version": {
            "description": "Taxonomy version (`v1`, `v2`…). Results stored with an older version should be resolved again.",
            "type": "string"
          }
        },
        "required": [
          "language",
          "skills",
          "unresolved",
          "taxonomy_version"
        ],
        "description": "Skills found in the text."
      },
      "ListSkillsResponse": {
        "type": "object",
        "properties": {
          "language": {
            "description": "Language of the names returned.",
            "type": "string",
            "enum": [
              "fr",
              "en"
            ]
          },
          "total": {
            "description": "Number of skills in the taxonomy.",
            "type": "integer"
          },
          "skills": {
            "description": "The whole taxonomy, most frequent in resumes first. There is no pagination.",
            "type": "array",
            "items": {
              "title": "TaxonomySkill",
              "type": "object",
              "properties": {
                "id": {
                  "description": "Stable skill id, e.g. `excel`. Store and filter on it.",
                  "type": "string"
                },
                "name": {
                  "description": "Canonical name in the requested language.",
                  "type": "string"
                },
                "type": {
                  "type": "string",
                  "enum": [
                    "hard",
                    "software",
                    "certification",
                    "soft",
                    "language"
                  ]
                },
                "families": {
                  "description": "Families of the skill, the primary one first.",
                  "type": "array",
                  "items": {
                    "title": "SkillFamilyRef",
                    "type": "object",
                    "properties": {
                      "id": {
                        "description": "Stable family id, e.g. `office_software`.",
                        "type": "string"
                      },
                      "name": {
                        "description": "Family name in the requested language.",
                        "type": "string"
                      },
                      "domain_id": {
                        "description": "Id of the domain the family belongs to.",
                        "type": "string"
                      }
                    },
                    "required": [
                      "id",
                      "name",
                      "domain_id"
                    ]
                  }
                },
                "domains": {
                  "description": "Domains of those families, the primary one first.",
                  "type": "array",
                  "items": {
                    "title": "SkillDomainRef",
                    "type": "object",
                    "properties": {
                      "id": {
                        "description": "Stable domain id, e.g. `data_ai`.",
                        "type": "string"
                      },
                      "name": {
                        "description": "Domain name in the requested language.",
                        "type": "string"
                      }
                    },
                    "required": [
                      "id",
                      "name"
                    ]
                  }
                },
                "broader": {
                  "description": "A more general skill to widen a search to (Excel → Microsoft Office), or `null`.",
                  "anyOf": [
                    {
                      "title": "BroaderSkill",
                      "type": "object",
                      "properties": {
                        "id": {
                          "type": "string"
                        },
                        "name": {
                          "type": "string"
                        }
                      },
                      "required": [
                        "id",
                        "name"
                      ]
                    },
                    {
                      "type": "null"
                    }
                  ]
                }
              },
              "required": [
                "id",
                "name",
                "type",
                "families",
                "domains",
                "broader"
              ]
            }
          },
          "taxonomy_version": {
            "description": "Taxonomy version (`v1`, `v2`…). Results stored with an older version should be resolved again.",
            "type": "string"
          }
        },
        "required": [
          "language",
          "total",
          "skills",
          "taxonomy_version"
        ],
        "description": "The taxonomy (first two of 11,061 skills shown)."
      },
      "GetHealthResponse": {
        "type": "object",
        "properties": {
          "status": {
            "description": "`healthy` whenever the service answers.",
            "type": "string",
            "enum": [
              "healthy",
              "unhealthy"
            ]
          },
          "service": {
            "type": "string",
            "const": "HireLayer API"
          },
          "timestamp": {
            "description": "Server time, ISO 8601 UTC.",
            "type": "string",
            "format": "date-time",
            "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"
          }
        },
        "required": [
          "status",
          "service",
          "timestamp"
        ],
        "description": "The service is up."
      },
      "GetMeResponse": {
        "type": "object",
        "properties": {
          "authenticated": {
            "type": "boolean",
            "const": true
          },
          "account": {
            "type": "object",
            "properties": {
              "email": {
                "description": "Email of the account that owns the key.",
                "anyOf": [
                  {
                    "type": "string"
                  },
                  {
                    "type": "null"
                  }
                ]
              },
              "plan": {
                "description": "Current plan.",
                "type": "string",
                "enum": [
                  "free",
                  "starter",
                  "scale",
                  "pay_as_you_go",
                  "enterprise"
                ]
              }
            },
            "required": [
              "email",
              "plan"
            ]
          },
          "credits": {
            "type": "object",
            "properties": {
              "available": {
                "description": "Credits left: monthly credits plus purchased credits. `null` on an unlimited plan or when the balance could not be read.",
                "anyOf": [
                  {
                    "type": "integer"
                  },
                  {
                    "type": "null"
                  }
                ]
              },
              "unlimited": {
                "description": "`true` on plans without a credit limit.",
                "type": "boolean"
              }
            },
            "required": [
              "available",
              "unlimited"
            ]
          }
        },
        "required": [
          "authenticated",
          "account",
          "credits"
        ],
        "description": "The key is valid."
      },
      "ParseResumeV2Request": {
        "type": "object",
        "properties": {
          "file": {
            "type": "string",
            "format": "binary",
            "description": "The resume: PDF, DOCX, ODT, PPTX, ODP, TXT, JPG or PNG."
          },
          "webhook_url": {
            "description": "URL that receives the result when processing ends.",
            "type": "string",
            "format": "uri"
          },
          "application_id": {
            "description": "Your own reference, echoed in the webhook payload.",
            "type": "string"
          }
        },
        "required": [
          "file",
          "webhook_url"
        ]
      },
      "ParseResumeV2Response": {
        "type": "object",
        "properties": {
          "message": {
            "type": "string",
            "const": "CV processing initiated."
          },
          "body": {
            "type": "null"
          },
          "error": {
            "type": "boolean",
            "const": false
          }
        },
        "required": [
          "message",
          "body",
          "error"
        ],
        "description": "Accepted. The result is sent to `webhook_url` later."
      }
    }
  }
}