Publier un poste depuis votre propre système
Mis à jour
Si vos postes vivent déjà ailleurs — un ATS, un outil interne, un tableur que quelqu’un garde jalousement — voici comment ils arrivent dans Orbit sans que personne ne les ressaisisse.
Ce qu’il vous faut
Une clé portant la portée lecture et gestion des offres, créée dans Orbit → Paramètres → Clés d’API. Une clé en lecture seule répond 403 à toutes les requêtes de cette page, délibérément : publier place une annonce devant le public, et la clé qui alimente une page carrières ne devrait pas pouvoir en plus publier des annonces.
export ORBIT_API_KEY="…une clé lecture et gestion des offres…"
La forme : deux appels
Créer et publier sont séparés.
POST /v1/jobscrée un brouillon. Rien n’est public.POST /v1/jobs/{jobId}/publishle met en ligne. Publier est gratuit.
C’est délibéré. Publier place le poste sur votre page d’offre hébergée, permet aux candidats de postuler et l’ajoute au flux des chercheurs d’emploi Wipperoz. Un appel unique qui ferait tout cela signifierait qu’une clé prise dans une boucle mal configurée publie des annonces avant que quiconque ne lise un log.
Cela laisse aussi une personne dans la boucle quand vous en voulez une : créez les brouillons depuis votre système et laissez un recruteur les publier depuis Orbit après les avoir lus. Si vous n’en voulez pas, appelez publish vous-même. Les deux sont pris en charge ; le choix vous revient, pas à nous.
Offres gérées
Une annonce publiée reçoit des candidatures et les liste dans leur ordre d’arrivée. Gérer une offre est le service payant d’Orbit par-dessus : ses candidats sont classés, votre vivier est comparé à l’offre et vous pouvez les présélectionner, depuis Orbit ou via l’API (voir Présélectionner un candidat). Un recruteur l’active offre par offre, dans Orbit — la portée lecture et gestion des offres crée, modifie, publie et clôture des postes, et ne gère pas les offres.
Une seule chose en parvient à cette API : l’intitulé et la catégorie d’une offre gérée sont verrouillés, comme l’explique Modifier un poste plus bas.
Créer le brouillon
curl -X POST https://api.wipperoz.com/v1/jobs \
-H "Authorization: Bearer $ORBIT_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: ats-job-4471" \
-d '{
"title": "Ingénieur backend senior",
"category": "engineering",
"description": "<p>Prendre en charge les services derrière notre pipeline de recrutement.</p>",
"responsibilities": ["Concevoir et livrer des services sur AWS Lambda et DynamoDB"],
"skills": [
{"name": "TypeScript", "level": "required"},
{"name": "DynamoDB", "level": "nice_to_have"}
],
"employmentType": "full_time",
"contractType": "permanent",
"salary": {"min": 150000, "max": 180000, "currency": "AUD", "period": "year"},
"location": {"country": "AU", "state": "NSW", "city": "Sydney", "remotePolicy": "hybrid"}
}'
{
"job": {
"id": "job_01J9A0B1C2EXAMPLE",
"status": "draft",
"title": "Ingénieur backend senior",
"category": "engineering",
"applyLink": "https://www.wipperoz.com/fr/apply/job_01J9A0B1C2EXAMPLE?src=careers&account=acc_01J8Z3EXAMPLE"
}
}
Gardez l’id. C’est par lui que vous publierez, modifierez et clôturerez le poste, et c’est l’identifiant à stocker en face du poste dans votre propre système.
Ici, seul title est obligatoire. Publier demande en plus une description et, la première fois qu’un poste passe en ligne, une category et une location avec un country (pour un poste à distance, le pays où les candidats peuvent se trouver) ; rien d’autre ne bloque jamais la publication. description accepte du HTML, ce que produit l’éditeur d’Orbit ; du texte brut convient aussi.
Catégories
category indique de quel type d’emploi il s’agit, dans une liste fixe. Envoyez la valeur ; le libellé est ce qu’affiche Orbit.
| Valeur | Affichée dans Orbit comme |
|---|---|
engineering |
Ingénierie |
data |
Données |
product |
Produit |
design |
Design |
marketing |
Marketing |
sales |
Ventes |
customer_success |
Succès client |
operations |
Opérations |
finance |
Finance |
hr_people |
RH et gestion des talents |
legal |
Juridique |
healthcare |
Santé |
education |
Éducation |
hospitality |
Hôtellerie et restauration |
retail |
Commerce de détail |
logistics |
Logistique |
construction_trades |
Construction et métiers |
manufacturing |
Industrie |
admin_support |
Administration et support |
other |
Autre |
Toute autre valeur reçoit un 400 qui nomme celles acceptées. other est là pour le poste qui n’entre dans aucune.
Le publier
curl -X POST https://api.wipperoz.com/v1/jobs/job_01J9A0B1C2EXAMPLE/publish \
-H "Authorization: Bearer $ORBIT_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: ats-job-4471-publish" \
-d '{"expiryDays": 30}'
{
"job": {"id": "job_01J9A0B1C2EXAMPLE", "status": "published", "url": "…"},
"firstPublish": true
}
expiryDaysvaut30,60,90, ounullpour aucune expiration.nullest la valeur par défaut : un poste qui disparaît à une date que personne n’a choisie est pire qu’un poste qui reste en ligne.firstPublishvautfalsequand le poste avait déjà été en ligne — un poste clos que vous rouvrez conserve son URL.- Un poste auquel il manque ce que la publication exige reçoit un
422avec une listemissing, plutôt qu’un400vague :titleoudescriptionà chaque publication, etcategoryetlocation(sanscountry) à la première.
Modifier un poste
curl -X PATCH https://api.wipperoz.com/v1/jobs/job_01J9A0B1C2EXAMPLE \
-H "Authorization: Bearer $ORBIT_API_KEY" \
-H "Content-Type: application/json" \
-d '{"salary": {"min": 170000, "max": 200000, "currency": "AUD", "period": "year"}}'
N’envoyez que les champs que vous changez ; les autres sont laissés tels quels.
Sur un brouillon, la modification s’applique immédiatement. Sur un poste publié, les nouveaux mots sont mis en attente au lieu de remplacer ce que les candidats lisent en ce moment, et la réponse le dit :
{"job": {"…": "…tel qu'il se lit encore aujourd'hui"}, "pendingRevision": true}
Les candidats postulent au regard des mots présents sur la page, et les changer sous une candidature ouverte revient à modifier ce que quelqu’un a accepté après qu’il l’a accepté. Un recruteur promeut donc la modification dans Orbit — ou vous la promouvez vous-même dans le même appel :
-d '{"salary": {...}, "publishEdits": true}'
Deux champs sautent la file et s’appliquent toujours immédiatement : expiresAt et maxMatches. Tous deux existent pour arrêter quelque chose, et garder « arrêter à cinquante correspondances » derrière une promotion laisserait l’appariement tourner au-delà du plafond que vous avez fixé.
Un poste en ligne garde le pays avec lequel il a été publié : promouvoir une location en attente sans country reçoit un 422 avec location dans missing, et ne change rien.
Une offre gérée garde son intitulé et sa catégorie
Une fois l’offre gérée, une modification qui change son title ou sa category — directement, ou en promouvant une modification en attente avec publishEdits — reçoit un 409 et ne change rien : ni l’annonce en ligne, ni ce qui est en attente. La réponse :
{
"error": {
"code": "managed_ad_locked",
"message": "This job is a managed ad, so its title cannot change. Post the new role as a new job.",
"requestId": "5f7a9c1e-2b3d-4e5f-8a9b-0c1d2e3f4a5b",
"fields": ["title"]
}
}
fields nomme ce que la modification aurait changé. Renvoyer la valeur actuelle n’est pas un changement : une synchronisation qui envoie tous les champs à chaque passage continue de fonctionner.
Le verrou est ce qui empêche de renommer une offre gérée pour en faire un autre emploi. Si le poste en amont est vraiment devenu un autre emploi, publiez-le comme un nouveau. Si le nouvel intitulé est simplement le bon, un recruteur arrête de gérer l’offre dans Orbit, dans l’onglet Paramètres du poste, et la modification passe. Cette API n’indique pas si une offre est gérée ; ce 409 est l’endroit où une intégration l’apprend.
Clôturer un poste
curl -X POST https://api.wipperoz.com/v1/jobs/job_01J9A0B1C2EXAMPLE/close \
-H "Authorization: Bearer $ORBIT_API_KEY"
La page hébergée cesse d’accepter les candidatures et indique que le poste est clos, le poste quitte le flux des chercheurs d’emploi, et l’accès aux CV que ce poste avait accordé à vos recruteurs prend fin avec lui — la raison de cet accès était une candidature ouverte. Clôturer une offre gérée rend aussi sa place à votre formule.
Les candidatures déjà reçues restent, et restent consultables dans Orbit. Clôturer n’est pas supprimer, et cette API n’a pas de suppression. Seul un poste publié peut être clos ; un brouillon ou un poste déjà clos reçoit un 409.
Des tentatives répétées qui ne publient pas deux fois
Envoyez une Idempotency-Key sur chaque POST. N’importe quelle valeur qui identifie l’intention convient — l’identifiant du poste dans votre propre système est idéal.
- Une nouvelle tentative avec la même clé renvoie la première réponse, avec
Idempotent-Replay: true. Pas de seconde annonce, pas de seconde publication. - La même clé avec un corps différent reçoit un
409. Deux intentions sous un même nom sont un bug qu’il vaut mieux connaître. - Les clés sont mémorisées 24 heures, par compte.
- Une requête refusée libère sa clé : un
422que vous corrigez en ajoutant ce qui manquait peut être retenté avec la même clé.
Sans l’en-tête, deux créations identiques font deux annonces. Les réseaux expirent : envoyez l’en-tête.
Tenir une synchronisation honnête
- Stockez notre
iden face de votre poste. C’est la seule prise stable. - Clôturez ce qui a été clos en amont. Une annonce périmée coûte son après-midi à un candidat, ce qui est pire qu’une annonce absente.
- Ne recréez pas à chaque synchronisation. Faites un
PATCHsur le poste déjà créé ; un nouveauPOSTfabrique une seconde annonce, avec une seconde URL. - Associez une fois pour toutes une
categoryà chaque famille de postes, et envoyez-la à chaque création. Un brouillon qui n’en a pas ne peut pas passer en ligne. - Envoyez une
locationavec uncountryà chaque création. Un brouillon qui n’en a pas ne peut pas non plus passer en ligne ; pour un poste à distance, envoyez le pays où les candidats peuvent se trouver. - Traitez
managed_ad_lockedcomme une décision, pas comme une nouvelle tentative. Retenter le même renommage reçoit le même409. - Limite de débit : 120 requêtes par minute et par clé. Quarante postes font quarante appels, largement dans les clous.
Référence
Create a draft jobPOST /v1/jobs
Publish a jobPOST /v1/jobs/{jobId}/publish
Edit a jobPATCH /v1/jobs/{jobId}
Close a jobPOST /v1/jobs/{jobId}/close