{"openapi":"3.1.0","info":{"title":"Aurélia.jobs V2 Public API","version":"0.3.0","summary":"Surface API externe sûre pour Aurélia.jobs V2.","license":{"name":"Proprietary","url":"https://aurelia.jobs/terms"},"description":"Cette spécification OpenAPI documente uniquement les endpoints externes\ndisponibles et sûrs à exposer : exports d'offres, intégration Jobposting,\ncandidature publique, préqualification candidat et portail candidat.\n\nLes routes admin, agent, workers, OAuth techniques et webhooks providers\nsont volontairement exclues de cette spécification.\n"},"servers":[{"url":"https://aurelia.jobs","description":"Production"}],"tags":[{"name":"Jobs","description":"Exports d'offres publiées."},{"name":"Jobposting","description":"Intégration partenaire Jobposting."},{"name":"Applications","description":"Candidatures publiques."},{"name":"Prequalification","description":"Parcours de préqualification candidat."},{"name":"Candidate portal","description":"Portail candidat et demandes RGPD."},{"name":"Service","description":"Santé et découverte du service."},{"name":"Public careers","description":"Offres publiées des pages carrière publiques."}],"paths":{"/api/jobs.json":{"get":{"tags":["Jobs"],"summary":"Lister les offres publiées en JSON","description":"Retourne les recrutements actifs et publiés du workspace identifié par\nla clé workspace `X-API-Key`.\n","operationId":"listPublishedJobsJson","x-aurelia-status":"implemented","security":[{"WorkspaceApiKey":[]}],"responses":{"200":{"description":"Offres publiées du workspace.","headers":{"Cache-Control":{"schema":{"type":"string"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PublishedJobsResponse"}}}},"401":{"$ref":"#/components/responses/UnauthorizedJson"},"404":{"$ref":"#/components/responses/NotFoundJson"},"500":{"$ref":"#/components/responses/ServerErrorJson"}},"x-required-scopes":["jobs:read"]}},"/api/jobs.xml":{"get":{"tags":["Jobs","Jobposting"],"summary":"Lister les offres publiées en XML","description":"Flux XML historique pour Jobposting/ATS. Cette route utilise le header\n`X-API-Key`, mais avec la clé d'intégration `JOBPOSTING_API_KEY`, pas\nune clé `workspace_api_keys`.\n","operationId":"listPublishedJobsXml","x-aurelia-status":"implemented","security":[{"JobpostingApiKey":[]}],"responses":{"200":{"description":"Flux XML des offres.","headers":{"Cache-Control":{"schema":{"type":"string"}},"X-Jobs-Count":{"schema":{"type":"string"}}},"content":{"application/xml":{"schema":{"type":"string"}}}},"401":{"description":"Clé absente ou invalide.","content":{"text/plain":{"schema":{"type":"string","example":"Unauthorized"}}}},"500":{"description":"Erreur serveur.","content":{"text/plain":{"schema":{"type":"string","example":"Internal Server Error"}}}}},"x-required-scopes":["jobs:feed"]}},"/api/candidatures":{"post":{"tags":["Applications","Jobposting"],"summary":"Recevoir une candidature Jobposting","description":"Crée ou réutilise un candidat, attache éventuellement un CV encodé en\nbase64, crée une candidature et déclenche les traitements non bloquants\nassociés. Cette route est une intégration partenaire spécifique.\n","operationId":"createJobpostingApplication","x-aurelia-status":"implemented","security":[{"JobpostingApiKey":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/JobpostingApplicationRequest"}}}},"responses":{"200":{"description":"Candidature créée ou déjà existante.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/JobpostingApplicationResponse"}}}},"400":{"$ref":"#/components/responses/BadRequestJson"},"401":{"$ref":"#/components/responses/UnauthorizedJson"},"404":{"$ref":"#/components/responses/NotFoundJson"},"500":{"$ref":"#/components/responses/ServerErrorJson"}},"x-required-scopes":["applications:write"]}},"/api/v2/application/submit":{"post":{"tags":["Applications"],"summary":"Soumettre une candidature publique V2","description":"Endpoint appelé par le formulaire carrière public. Il crée ou réutilise\nle candidat, crée la candidature, audite le consentement RGPD et accepte\nun CV optionnel.\n","operationId":"submitPublicApplication","x-aurelia-status":"implemented","security":[],"requestBody":{"required":true,"content":{"multipart/form-data":{"schema":{"$ref":"#/components/schemas/PublicApplicationForm"}}}},"responses":{"200":{"description":"Candidature créée.","content":{"application/json":{"schema":{"type":"object","required":["ok","applicationId"],"properties":{"ok":{"type":"boolean","const":true},"applicationId":{"type":"string","format":"uuid"}}}}}},"400":{"$ref":"#/components/responses/PublicBadRequest"},"404":{"$ref":"#/components/responses/PublicNotFound"},"500":{"$ref":"#/components/responses/PublicServerError"}},"x-required-scopes":["applications:write"]}},"/api/v2/prequalif/{sessionId}/consent":{"post":{"tags":["Prequalification"],"summary":"Enregistrer le consentement de préqualification","description":"`sessionId` correspond actuellement à `candidate_applications.id`.\nLa décision `ai` autorise la conversation IA ; `human` demande une\nrevue humaine seule et révoque le consentement IA.\n","operationId":"recordPrequalificationConsent","x-aurelia-status":"implemented","security":[],"parameters":[{"$ref":"#/components/parameters/SessionId"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["decision"],"properties":{"decision":{"type":"string","enum":["ai","human"]}}}}}},"responses":{"200":{"description":"Consentement enregistré.","content":{"application/json":{"schema":{"type":"object","required":["ok","aiConsent"],"properties":{"ok":{"type":"boolean"},"aiConsent":{"type":"boolean"}}}}}},"400":{"$ref":"#/components/responses/PublicBadRequest"},"404":{"$ref":"#/components/responses/SessionNotFound"},"500":{"$ref":"#/components/responses/PublicServerError"}},"x-required-scopes":["prequalification:write"]}},"/api/v2/prequalif/{sessionId}/stream":{"post":{"tags":["Prequalification"],"summary":"Streamer la conversation de préqualification","description":"Lance ou poursuit la conversation IA de préqualification. Le consentement\nIA doit avoir été enregistré au préalable. Un rate limit en mémoire\nlimite actuellement chaque session à 12 requêtes par minute.\n","operationId":"streamPrequalificationConversation","x-aurelia-status":"implemented","security":[],"parameters":[{"$ref":"#/components/parameters/SessionId"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PrequalificationStreamRequest"}}}},"responses":{"200":{"description":"Stream de réponse UI/IA.","headers":{"X-Aurelia-Prequalif-Mode":{"schema":{"type":"string"},"description":"Présent en fallback local."}},"content":{"text/event-stream":{"schema":{"type":"string"}},"application/octet-stream":{"schema":{"type":"string"}}}},"400":{"$ref":"#/components/responses/PublicBadRequest"},"403":{"description":"Consentement IA manquant.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"$ref":"#/components/responses/SessionNotFound"},"429":{"description":"Rate limit atteint.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"503":{"description":"Provider IA non configuré.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"x-required-scopes":["prequalification:write"]}},"/api/v2/prequalif/{sessionId}/save":{"post":{"tags":["Prequalification"],"summary":"Sauvegarder l'état de préqualification","description":"Fusionne le JSON reçu dans `candidate_applications.prequalif_session`.","operationId":"savePrequalificationState","x-aurelia-status":"implemented","security":[],"parameters":[{"$ref":"#/components/parameters/SessionId"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"responses":{"200":{"description":"État sauvegardé.","content":{"application/json":{"schema":{"type":"object","required":["ok","persisted"],"properties":{"ok":{"type":"boolean"},"persisted":{"type":"boolean"}}}}}},"400":{"$ref":"#/components/responses/PublicBadRequest"},"404":{"$ref":"#/components/responses/SessionNotFound"},"500":{"$ref":"#/components/responses/PublicServerError"}},"x-required-scopes":["prequalification:write"]}},"/api/v2/portal/{token}/export":{"get":{"tags":["Candidate portal"],"summary":"Exporter les données candidat","description":"Export JSON RGPD candidat. Le token est temporairement\n`candidate_applications.id`; la cible produit est un token opaque signé.\n","operationId":"exportCandidateData","x-aurelia-status":"implemented-token-temporary","security":[],"parameters":[{"$ref":"#/components/parameters/PortalToken"}],"responses":{"200":{"description":"Export candidat.","headers":{"content-disposition":{"schema":{"type":"string"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CandidateExport"}}}},"404":{"$ref":"#/components/responses/PublicNotFound"},"500":{"$ref":"#/components/responses/PublicServerError"}},"x-required-scopes":["candidate-portal:read"]}},"/api/v2/portal/{token}/delete":{"post":{"tags":["Candidate portal"],"summary":"Demander la suppression des données candidat","description":"Journalise une demande de suppression RGPD. La suppression effective\nreste traitée par un administrateur workspace dans le délai légal.\n","operationId":"requestCandidateDeletion","x-aurelia-status":"implemented-token-temporary","security":[],"parameters":[{"$ref":"#/components/parameters/PortalToken"}],"responses":{"200":{"description":"Demande enregistrée.","content":{"application/json":{"schema":{"type":"object","required":["ok"],"properties":{"ok":{"type":"boolean"}}}}}},"404":{"$ref":"#/components/responses/PublicNotFound"},"500":{"$ref":"#/components/responses/PublicServerError"}},"x-required-scopes":["candidate-portal:delete"]}},"/api/health":{"get":{"tags":["Service"],"summary":"Vérifier la santé du service","description":"Sonde publique, sans authentification. Retourne l'état du serveur applicatif et l'horodatage de la réponse. Elle sert au healthcheck du conteneur ; un agent peut s'en servir pour vérifier que l'API répond avant d'enchaîner.","operationId":"getServiceHealth","x-aurelia-status":"implemented","x-required-scopes":["public:read"],"security":[],"responses":{"200":{"description":"Le service répond.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ServiceHealth"}}}},"500":{"$ref":"#/components/responses/ServerErrorJson"}}}},"/api/public/v1/service-catalog":{"get":{"tags":["Service"],"summary":"Lister les ressources lisibles par une machine","description":"Catalogue de découverte, sans authentification : fichiers machine du domaine (openapi.json, llms.txt, agent.txt, mcp.json, métadonnée RFC 9728), opérations publiques, portées déclarées et coordonnées de l'éditeur. C'est le point d'entrée recommandé pour un agent qui découvre Aurélia.jobs.","operationId":"getServiceCatalog","x-aurelia-status":"implemented","x-required-scopes":["public:read"],"security":[],"responses":{"200":{"description":"Catalogue de service.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ServiceCatalog"}}}},"500":{"$ref":"#/components/responses/ServerErrorJson"}}}},"/api/public/v1/careers/{workspaceSlug}/jobs":{"get":{"tags":["Public careers"],"summary":"Lister les offres d'une page carrière publique","description":"Retourne, sans authentification, exactement les offres déjà visibles sur la page carrière publique `/careers/{workspaceSlug}` : les recrutements actifs dont la diffusion est publiée. Aucune donnée candidat n'est exposée. Un espace de travail inconnu répond 404.","operationId":"getPublicCareersJobs","x-aurelia-status":"implemented","x-required-scopes":["public:read"],"security":[],"parameters":[{"$ref":"#/components/parameters/WorkspaceSlug"}],"responses":{"200":{"description":"Offres publiées de l'espace de travail.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PublicCareersJobsResponse"}}}},"404":{"$ref":"#/components/responses/NotFoundJson"},"500":{"$ref":"#/components/responses/ServerErrorJson"}}}}},"components":{"securitySchemes":{"WorkspaceApiKey":{"type":"apiKey","in":"header","name":"X-API-Key","description":"Clé workspace `ak_...` validée via `workspace_api_keys`."},"JobpostingApiKey":{"type":"apiKey","in":"header","name":"X-API-Key","description":"Clé d'intégration Jobposting issue de `JOBPOSTING_API_KEY`."}},"parameters":{"SessionId":{"name":"sessionId","in":"path","required":true,"description":"Identifiant de session, actuellement `candidate_applications.id`.","schema":{"type":"string","format":"uuid"}},"PortalToken":{"name":"token","in":"path","required":true,"description":"Token portail candidat. Temporairement un identifiant de candidature.","schema":{"type":"string"}},"WorkspaceSlug":{"name":"workspaceSlug","in":"path","required":true,"description":"Identifiant d'URL de l'espace de travail, tel qu'il apparaît dans /careers/{workspaceSlug}.","schema":{"type":"string","minLength":1}}},"responses":{"BadRequestJson":{"description":"Requête invalide.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"UnauthorizedJson":{"description":"Authentification absente ou invalide.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"NotFoundJson":{"description":"Ressource introuvable.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"ServerErrorJson":{"description":"Erreur serveur.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"PublicBadRequest":{"description":"Requête publique invalide.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PublicErrorResponse"}}}},"PublicNotFound":{"description":"Ressource publique introuvable.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PublicErrorResponse"}}}},"PublicServerError":{"description":"Erreur serveur.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PublicErrorResponse"}}}},"SessionNotFound":{"description":"Session de préqualification introuvable.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PublicErrorResponse"}}}}},"schemas":{"ErrorResponse":{"type":"object","properties":{"error":{"type":"string","description":"Message lisible par un humain."},"code":{"type":"string","description":"Code d'erreur stable, sur lequel un agent peut brancher sa logique.","enum":["bad_request","unauthorized","forbidden","not_found","method_not_allowed","not_acceptable","rate_limited","internal_error"]},"message":{"type":"string","description":"Identique à `error`."},"hint":{"type":"string","description":"Ce qu'il faut corriger pour que l'appel passe."},"documentation_url":{"type":"string","format":"uri"},"status":{"type":"integer"}},"additionalProperties":true,"required":["error","code","message"]},"PublicErrorResponse":{"type":"object","properties":{"ok":{"type":"boolean","const":false},"error":{"type":"string"}},"additionalProperties":true},"PublishedJobsResponse":{"type":"object","required":["workspace","jobs","count","generatedAt"],"properties":{"workspace":{"type":"object","required":["name","slug"],"properties":{"name":{"type":"string"},"logo":{"type":["string","null"]},"slug":{"type":"string"}}},"jobs":{"type":"array","items":{"$ref":"#/components/schemas/PublishedJob"}},"count":{"type":"integer"},"generatedAt":{"type":"string","format":"date-time"}}},"PublishedJob":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"title":{"type":"string"},"location":{"type":"object","properties":{"display":{"type":["string","null"]},"city":{"type":["string","null"]},"postalCode":{"type":["string","null"]},"region":{"type":["string","null"]},"country":{"type":["string","null"]}}},"contract":{"type":"object","properties":{"type":{"type":["string","null"]},"durationValue":{"type":["integer","null"]},"durationUnit":{"type":["string","null"]}}},"salary":{"type":["object","null"],"properties":{"min":{"type":["number","null"]},"max":{"type":["number","null"]}}},"remoteWorkDays":{"type":["integer","null"]},"qualifications":{"type":"object","additionalProperties":true},"company":{"type":"object","properties":{"name":{"type":["string","null"]},"logo":{"type":["string","null"]}}},"descriptions":{"type":"object","properties":{"company":{"type":["string","null"]},"position":{"type":["string","null"]},"profile":{"type":["string","null"]}}},"benefits":{"type":"array","items":{"type":"string"}},"publishedAt":{"type":["string","null"],"format":"date-time"},"applyUrl":{"type":"string","format":"uri"}}},"JobpostingApplicationRequest":{"type":"object","required":["id","job","applicant"],"properties":{"id":{"type":"string","description":"Identifiant ou hash unique de la candidature côté partenaire."},"job":{"type":"object","required":["jobId","source"],"properties":{"jobId":{"type":"string","format":"uuid","description":"Identifiant du recrutement Aurélia."},"source":{"type":"string","description":"Code source partenaire."},"broadcastId":{"type":"string"}}},"applicant":{"type":"object","required":["lastName","email"],"properties":{"firstName":{"type":"string"},"lastName":{"type":"string"},"email":{"type":"string","format":"email"},"phoneNumber":{"type":"string"},"resume":{"type":"object","properties":{"file":{"type":"object","required":["fileName","contentType","data"],"properties":{"fileName":{"type":"string"},"contentType":{"type":"string"},"data":{"type":"string","description":"Contenu du fichier encodé en base64."}}}}}}},"verified":{"type":"boolean"}}},"JobpostingApplicationResponse":{"type":"object","required":["success","message","candidateId","applicationId"],"properties":{"success":{"type":"boolean"},"message":{"type":"string"},"candidateId":{"type":"string","format":"uuid"},"applicationId":{"type":"string","format":"uuid"}}},"PublicApplicationForm":{"type":"object","required":["workspaceSlug","jobId","firstName","lastName","email","consent"],"properties":{"workspaceSlug":{"type":"string"},"jobId":{"type":"string","format":"uuid"},"firstName":{"type":"string"},"lastName":{"type":"string"},"email":{"type":"string","format":"email"},"phone":{"type":"string"},"why":{"type":"string","description":"Message de motivation."},"consent":{"type":"string","enum":["1"]},"cv":{"type":"string","format":"binary","description":"Fichier optionnel PDF, DOC, DOCX, JPG ou PNG."}}},"PrequalificationStreamRequest":{"type":"object","required":["messages"],"properties":{"messages":{"type":"array","items":{"type":"object","additionalProperties":true}},"workspaceName":{"type":"string"},"jobTitle":{"type":"string"},"candidateFirstName":{"type":"string"}}},"CandidateExport":{"type":"object","properties":{"exportedAt":{"type":"string","format":"date-time"},"rgpd":{"type":"object","properties":{"legalBasis":{"type":"string"},"retentionMonths":{"type":"integer"}}},"candidate":{"type":"object","properties":{"firstName":{"type":["string","null"]},"lastName":{"type":["string","null"]},"email":{"type":["string","null"]},"phone":{"type":["string","null"]},"cvFilePath":{"type":["string","null"]},"createdAt":{"type":["string","null"],"format":"date-time"}}},"applications":{"type":"array","items":{"type":"object","additionalProperties":true}},"consents":{"type":"array","items":{"type":"object","additionalProperties":true}}}},"ServiceHealth":{"type":"object","required":["status","ok","timestamp"],"properties":{"status":{"type":"string","const":"ok"},"ok":{"type":"boolean"},"startedAt":{"type":"string","format":"date-time"},"timestamp":{"type":"string","format":"date-time"}},"additionalProperties":true},"ServiceCatalog":{"type":"object","required":["name","description","documents","endpoints","scopes","publisher"],"properties":{"name":{"type":"string"},"description":{"type":"string"},"whenToUse":{"type":"array","description":"Cas d'usage pour lesquels un agent a intérêt à appeler Aurélia.jobs.","items":{"type":"string"}},"documents":{"type":"array","description":"Fichiers lisibles par une machine publiés sur le domaine.","items":{"type":"object","required":["name","url","mediaType"],"properties":{"name":{"type":"string"},"url":{"type":"string","format":"uri"},"mediaType":{"type":"string"},"description":{"type":"string"}}}},"endpoints":{"type":"array","items":{"type":"object","required":["operationId","method","path","authentication","scopes"],"properties":{"operationId":{"type":"string"},"method":{"type":"string"},"path":{"type":"string"},"summary":{"type":"string"},"authentication":{"type":"string"},"scopes":{"type":"array","items":{"type":"string"}}}}},"scopes":{"type":"array","items":{"type":"object","required":["name","description"],"properties":{"name":{"type":"string"},"description":{"type":"string"},"carriedBy":{"type":"string"}}}},"publisher":{"type":"object","required":["legalName","contactEmail"],"properties":{"legalName":{"type":"string"},"brandName":{"type":"string"},"contactEmail":{"type":"string","format":"email"},"siret":{"type":"string"},"vatId":{"type":"string"},"address":{"type":"string"}}}}},"PublicCareersJobsResponse":{"type":"object","required":["workspace","jobs","count","generatedAt"],"properties":{"workspace":{"type":"object","required":["name","slug"],"properties":{"name":{"type":"string"},"slug":{"type":"string"},"logo":{"type":["string","null"]},"careersUrl":{"type":"string","format":"uri"}}},"count":{"type":"integer"},"generatedAt":{"type":"string","format":"date-time"},"jobs":{"type":"array","items":{"type":"object","required":["id","title","url"],"properties":{"id":{"type":"string","format":"uuid"},"title":{"type":"string"},"url":{"type":"string","format":"uri"},"location":{"type":["string","null"]},"company":{"type":["string","null"],"description":"Nom de l'entreprise qui recrute, ou null si le recrutement est publié de façon anonyme."},"contractType":{"type":["string","null"]},"experienceLevel":{"type":["string","null"]},"educationLevel":{"type":["string","null"]},"remoteWorkDays":{"type":["integer","null"]},"salaryMin":{"type":["number","null"],"description":"Renseigné seulement si le recruteur affiche la rémunération."},"salaryMax":{"type":["number","null"],"description":"Renseigné seulement si le recruteur affiche la rémunération."},"publishedAt":{"type":["string","null"],"format":"date-time"}}}}}}}}}