Logo StartupKit
FR
Integrations

Référence API

Authentifiez-vous et interrogez l'API de recrutement pour les offres d'emploi, les candidats et les candidatures.

Pourquoi c’est important

L’API de recrutement offre aux systèmes externes un accès en lecture à vos données de recrutement — les sites d’emploi récupèrent les offres publiées, les systèmes SIRH synchronisent les fiches candidats, les tableaux de bord suivent les indicateurs du pipeline. Les portées des jetons garantissent que chaque intégration ne voit que ce dont elle a besoin.

URL de base

Tous les points d’accès de l’API sont accessibles via :

https://startupkit.app/api/v1

Remplacez startupkit.app par votre domaine Kit réel.

Authentification

Chaque requête nécessite un jeton API dans l’en-tête Authorization :

Authorization: Bearer YOUR_TOKEN

Format alternatif (les deux fonctionnent) :

Authorization: token YOUR_TOKEN

Créez des jetons dans Settings > API. Chaque jeton doit disposer de portées explicites pour accéder aux points d’accès de recrutement.

Portée Accès
job_postings:read Offres d’emploi et étapes
candidates:read Données personnelles des candidats (nom, e-mail, téléphone), téléchargement de CV
applications:read Candidatures, historique des étapes, téléchargement de CV

Les jetons sans portée ne peuvent pas accéder aux points d’accès de recrutement.

Format et cycle de vie des jetons

  • Format : chaîne hexadécimale de 32 caractères (par ex. a1b2c3d4e5f6...)
  • Suivi de la dernière utilisation : chaque requête réussie met à jour last_used_at
  • Expiration : un champ optionnel expires_at peut être défini lors de la création du jeton
  • Alertes d’inactivité : les jetons non utilisés depuis plus de 30 jours déclenchent des notifications administrateur
  • Révocation automatique : les jetons sont automatiquement révoqués lorsqu’un utilisateur est retiré du compte

Bonne pratique : créez des jetons distincts par intégration avec les portées minimales nécessaires.

Portée du compte

Chaque jeton API est lié à un compte spécifique. Le compte est déterminé automatiquement à partir du jeton — aucun paramètre account_id n’est nécessaire.

Lorsqu’un membre de l’équipe est retiré d’un compte, ses jetons pour ce compte sont automatiquement révoqués.

Réponses d’erreur

Statut Signification Causes courantes
400 Requête incorrecte Contexte de compte manquant (cas limite avec l’authentification par session)
401 Non autorisé Jeton manquant, invalide ou expiré
403 Interdit Le jeton ne dispose pas de la portée requise pour ce point d’accès
404 Non trouvé La ressource n’existe pas ou n’appartient pas à votre compte
422 Entité non traitable Erreurs de validation (principalement pour les points d’accès hors recrutement)

Pagination

Les points d’accès de liste renvoient des résultats paginés :

{
  "data": [...],
  "pagination": {
    "current_page": 1,
    "total_pages": 3,
    "total_count": 42,
    "per_page": 20
  }
}

Ajoutez ?page=2 pour récupérer les pages suivantes.


Offres d’emploi

Portée requise : job_postings:read

Lister les offres d’emploi

GET /api/v1/job_postings

Exemple :

curl -H "Authorization: Bearer YOUR_TOKEN" \
  https://startupkit.app/api/v1/job_postings?status=published

Paramètres :

Paramètre Type Description
status string Filtrer par draft, published ou closed
page integer Numéro de page

Réponse :

{
  "data": [
    {
      "id": "job_abc123",
      "title": "Senior Rails Developer",
      "status": "published",
      "department": "Engineering",
      "location": "New York, NY",
      "employment_type": "full_time",
      "remote": true,
      "salary_min": "120000.0",
      "salary_max": "180000.0",
      "salary_currency": "USD",
      "salary_period": "year",
      "published_at": "2026-01-15T10:00:00Z",
      "closed_at": null,
      "created_at": "2026-01-10T08:30:00Z",
      "updated_at": "2026-02-01T14:20:00Z",
      "stages": [
        {
          "id": "stg_def456",
          "name": "Screening",
          "stage_type": "default",
          "position": 0
        }
      ],
      "counts": {
        "total_applications": 24,
        "active_applications": 18,
        "rejected": 6
      }
    }
  ],
  "pagination": { ... }
}

Obtenir une offre d’emploi

GET /api/v1/job_postings/:id

Renvoie la même structure qu’un élément de la réponse de liste.

Lister les étapes

GET /api/v1/job_postings/:job_posting_id/stages

Réponse :

{
  "data": [
    {
      "id": "stg_def456",
      "name": "Screening",
      "stage_type": "default",
      "position": 0
    }
  ]
}

Les étapes sont classées par position. Pas de pagination.


Candidats

Portée requise : candidates:read

Lister les candidats

GET /api/v1/candidates

Exemple :

curl -H "Authorization: Bearer YOUR_TOKEN" \
  https://startupkit.app/api/v1/[email protected]

Paramètres :

Paramètre Type Description
search string Rechercher par nom ou e-mail
page integer Numéro de page

Réponse :

{
  "data": [
    {
      "id": "cand_ghi789",
      "first_name": "John",
      "last_name": "Doe",
      "email": "[email protected]",
      "phone": "+1-555-0100",
      "status": "active",
      "github_username": "johndoe",
      "created_at": "2026-01-20T09:15:00Z",
      "applications": [
        {
          "id": "app_jkl012",
          "job_posting_id": "job_abc123",
          "job_posting_title": "Senior Rails Developer",
          "current_stage_name": "Interview",
          "status": "active",
          "submitted_at": "2026-01-20T09:15:00Z"
        }
      ]
    }
  ],
  "pagination": { ... }
}

Obtenir un candidat

GET /api/v1/candidates/:id

Renvoie la même structure qu’un élément de la réponse de liste.


Candidatures

Portée requise : applications:read

Lister les candidatures

GET /api/v1/applications

Exemple :

curl -H "Authorization: Bearer YOUR_TOKEN" \
  https://startupkit.app/api/v1/applications?job_posting_id=job_abc123&status=active

Paramètres :

Paramètre Type Description
job_posting_id string Filtrer par identifiant préfixé de l’offre d’emploi
status string Filtrer par active ou rejected
page integer Numéro de page

Réponse :

{
  "data": [
    {
      "id": "app_jkl012",
      "job_posting_id": "job_abc123",
      "candidate_id": "cand_ghi789",
      "current_stage_name": "Interview",
      "status": "active",
      "submitted_at": "2026-01-20T09:15:00Z",
      "created_at": "2026-01-20T09:15:00Z",
      "updated_at": "2026-02-10T11:30:00Z",
      "candidate": {
        "id": "cand_ghi789",
        "first_name": "John",
        "last_name": "Doe",
        "email": "[email protected]"
      },
      "stage_history": [
        {
          "id": "sp_mno345",
          "stage_name": "Screening",
          "stage_type": "default",
          "status": "completed",
          "started_at": "2026-01-20T09:15:00Z",
          "completed_at": "2026-01-25T16:00:00Z"
        },
        {
          "id": "sp_pqr678",
          "stage_name": "Interview",
          "stage_type": "interview",
          "status": "in_progress",
          "started_at": "2026-01-25T16:00:00Z",
          "completed_at": null
        }
      ]
    }
  ],
  "pagination": { ... }
}

Obtenir une candidature

GET /api/v1/applications/:id

Renvoie la même structure qu’un élément de la réponse de liste. Lorsque le jeton dispose de la portée candidates:read et qu’un CV est joint à la candidature, la réponse inclut les métadonnées du CV :

{
  "id": "app_jkl012",
  "resume_filename": "john_doe_resume.pdf",
  "resume_content_type": "application/pdf",
  "resume_byte_size": 245760,
  ...
}

Ces champs sont omis lorsqu’aucun CV n’est joint ou lorsque la portée candidates:read est absente.

Télécharger le CV

Portées requises : applications:read + candidates:read

GET /api/v1/applications/:application_id/resume

Télécharge le CV du candidat pour la candidature donnée. Renvoie une redirection 302 vers une URL signée à durée limitée (valide 30 minutes).

Exemple :

curl -L -H "Authorization: Bearer YOUR_TOKEN" \
  -o resume.pdf \
  https://startupkit.app/api/v1/applications/app_jkl012/resume

Réponse :

  • 302 Found – Redirection vers l’URL de téléchargement signée. Utilisez -L (suivre les redirections) avec curl.
  • 403 Forbidden – Le jeton ne dispose pas de la portée applications:read ou candidates:read.
  • 404 Not Found – Candidature non trouvée, ou aucun CV joint.

Notes :

  • Les URL signées expirent après 30 minutes. En cas d’expiration, effectuez une nouvelle demande.
  • L’en-tête Content-Disposition est défini sur attachment (déclenche le téléchargement par le navigateur).
  • Types de fichiers de CV : PDF, DOC, DOCX (tels que téléchargés par le candidat).

Masquage des données personnelles des candidats

Lorsqu’un jeton dispose de la portée applications:read mais pas de candidates:read, les données du candidat dans les réponses de candidature sont réduites au seul identifiant :

{
  "candidate": {
    "id": "cand_ghi789"
  }
}

Les champs first_name, last_name et email ne sont pas inclus. Cela permet aux intégrations de sites d’emploi de suivre le statut des candidatures sans exposer les coordonnées des candidats.


Dépannage

Problèmes d’authentification

401 Unauthorized

Si vous recevez une réponse 401, vérifiez :

  1. Format du jeton : assurez-vous que le jeton correspond exactement à celui affiché dans Settings > API (chaîne hexadécimale de 32 caractères)
  2. En-tête Authorization : doit être Authorization: Bearer TOKEN ou Authorization: token TOKEN
  3. Expiration du jeton : vérifiez si expires_at est dépassé dans Settings > API
  4. Appartenance au compte : vérifiez que le propriétaire du jeton est toujours membre du compte

403 Forbidden

Lorsque vous recevez une erreur 403, le jeton est valide mais ne dispose pas de la portée requise :

  1. Vérifiez les portées requises : chaque point d’accès indique la portée nécessaire (par ex. job_postings:read)
  2. Ajoutez les portées manquantes : modifiez le jeton dans Settings > API et ajoutez la portée requise
  3. Format des portées : doit correspondre exactement — job_postings:read, et non job_postings ou read

Problèmes d’accès aux données

Tableau data vide dans les réponses

Si l’API renvoie {"data": [], "pagination": {...}} alors que vous attendez des résultats :

  1. Isolation des comptes : les jetons API ne voient que les données de leur compte associé
  2. Vérifiez le compte : consultez à quel compte le jeton appartient dans Settings > API
  3. Accès inter-comptes : les jetons ne peuvent pas accéder aux données d’autres comptes, même si l’utilisateur en est membre

Les données personnelles du candidat sont masquées

Si vous ne voyez que {"candidate": {"id": "cand_..."}} sans nom ni e-mail :

  1. Comportement attendu : cela se produit lorsque le jeton dispose de la portée applications:read mais pas de candidates:read
  2. Ajoutez la portée : pour voir les informations complètes du candidat, ajoutez la portée candidates:read à votre jeton
  3. Confidentialité par conception : cela permet aux intégrations de suivre les candidatures sans exposer les coordonnées

Problèmes de requêtes et de filtrage

Erreur 404 lors de la recherche d’enregistrements spécifiques

  1. Utilisez les identifiants préfixés : les offres d’emploi utilisent le format job_abc123, et non des identifiants de base de données comme 42
  2. Sensibilité à la casse : les identifiants préfixés sont sensibles à la casse
  3. Portée du compte : la ressource doit appartenir au compte du jeton

Les paramètres de filtre ne fonctionnent pas

  1. Valeurs de statut valides :
    • Offres d’emploi : draft, published, closed (sensible à la casse)
    • Candidatures : active, rejected (sensible à la casse)
  2. Format des paramètres : utilisez ?status=published, et non ?status=Published ou ?filter[status]=published

Questions fréquentes

Comment fonctionne la pagination ?

Tous les points d’accès de liste renvoient 20 éléments par page (fixe). Utilisez ?page=2 pour la page suivante. L’objet pagination indique total_pages et total_count.

Les jetons expirent-ils automatiquement ?

Uniquement si vous définissez expires_at lors de la création du jeton. Sinon, les jetons restent valides jusqu’à ce que :

  • Ils soient révoqués manuellement dans Settings > API
  • L’utilisateur soit retiré du compte
  • Le compte soit supprimé

Dois-je utiliser un seul jeton pour plusieurs intégrations ?

Non. La bonne pratique est d’utiliser un jeton par intégration avec des portées minimales. Cela facilite :

  • L’audit des requêtes par intégration (via last_used_at)
  • La révocation de l’accès à une intégration spécifique sans affecter les autres
  • L’attribution de permissions différentes à différents systèmes

Quel est le lien entre les webhooks et l’API ?

Les webhooks vous notifient des événements (nouvelle candidature, changement d’étape). L’API vous permet d’interroger l’état actuel. Utilisez les webhooks pour déclencher votre système, puis l’API pour récupérer les détails complets.

Puis-je obtenir plus de 20 éléments par page ?

Non. La taille de page est fixée à 20 éléments pour garantir des performances constantes. Utilisez le paramètre page pour parcourir l’ensemble des résultats.

Aide-mémoire

  • Créez un jeton API dans Settings > API — chaque jeton est lié à ce compte
  • Attribuez uniquement les portées nécessaires à votre intégration (bonne pratique : un jeton par intégration avec des portées minimales)
  • Vérifiez expires_at dans Settings > API pour connaître la date d’expiration du jeton (le cas échéant)
  • Incluez Authorization: Bearer TOKEN dans chaque requête
  • Utilisez les identifiants préfixés (par ex. job_abc123) dans les URL, et non les identifiants de base de données
  • Gérez les réponses 400 et 422 pour les erreurs de validation
  • Gérez les réponses 401 — votre jeton peut être expiré ou révoqué
  • Gérez les réponses 403 — votre jeton peut ne pas disposer de la portée requise
  • Utilisez le paramètre page pour paginer les ensembles de résultats volumineux (20 éléments par page)

Tapez pour rechercher...