Aperçu
L'API LeadGrid te permet de créer et gérer des dossiers, de mettre à jour les étapes, d'attacher des notes et de synchroniser des données avec tes propres outils. Chaque requête retourne du JSON.
Tous les horodatages sont en ISO 8601 UTC. Tous les montants sont des entiers ou des décimaux dans la plus petite unité pratique (p. ex. euros, pas centimes). La pagination utilise page et per_page comme paramètres de requête ; les réponses incluent un objet meta avec le nombre total.
Authentification
Chaque requête doit comporter une clé API dans l'en-tête Authorization. Les clés commencent par lg_live_ et sont liées à une seule organisation.
- 1Rends-toi dans Paramètres → API et clique sur Créer une clé API.
- 2Choisis les scopes dont tu as besoin (voir le tableau ci-dessous) et définis éventuellement une date d'expiration. La clé complète est affichée une seule fois . Copie-la immédiatement.
- 3Envoie la clé comme token Bearer à chaque requête.
curl https://leadgrid.io/api/v1/dossiers \ -H "Authorization: Bearer lg_live_your_key_here"
| Champ | Type | Description |
|---|---|---|
| dossiers:read | scope | Lister et récupérer des dossiers. |
| dossiers:write | scope | Créer, mettre à jour et archiver des dossiers. Également requis pour déplacer des étapes. |
| contacts:read | scope | Lister et récupérer des contacts, et lire leurs liens vers les dossiers. |
| contacts:write | scope | Créer, mettre à jour et supprimer des contacts. Requis en plus de dossiers:write pour lier ou délier des contacts à un dossier. |
| flows:read | scope | Lister les flows et lire leurs étapes. |
| notes:read | scope | Lire les notes sur les dossiers. |
| notes:write | scope | Ajouter de nouvelles notes aux dossiers. |
Dossiers
Les dossiers sont les entités que tu suis, candidats en recrutement ou prospects en vente. Chaque dossier appartient à exactement un flow et se trouve dans exactement une étape.
/dossiersLister les dossiers de ton organisation. Supporte le filtrage et la pagination.
| Champ | Type | Description |
|---|---|---|
| type | string | 'candidate' or 'sales'. |
| status | string | 'active', 'won', 'lost' or 'archived'. |
| stage_id | uuid | Return only dossiers currently in this stage. |
| page | integer | 1-based page number. Default: 1. |
| per_page | integer | Items per page (max 100). Default: 25. |
curl "https://leadgrid.io/api/v1/dossiers?type=sales&status=active" \ -H "Authorization: Bearer lg_live_your_key"
{
"data": [
{
"id": "6f2b…",
"type": "sales",
"name": "Rabobank, Talent rollout",
"company": "Rabobank",
"contact_person": "Mark de Vries",
"deal_size": 45000,
"deal_currency": "EUR",
"status": "active",
"current_stage_id": "c3e1…",
"assigned_to": "ab12…",
"created_at": "2026-04-10T09:21:14Z"
}
],
"meta": { "total": 34, "page": 1, "per_page": 25 }
}/dossiersCréer un nouveau dossier. Si flow_id est omis, le flow par défaut pour le type donné est utilisé ; le dossier démarre à la première étape de ce flow. Passe éventuellement un contact_id pour rattacher le dossier à un Contact existant au lieu d'en créer un nouveau. Envoie application/json pour une création simple, ou multipart/form-data avec un champ 'cv' pour créer le dossier ET joindre un CV PDF en un seul appel atomique : si l'upload échoue, le dossier est annulé.
| Champ | Type | Description |
|---|---|---|
| type* | string | 'candidate' or 'sales'. |
| name* | string | For candidates: the person's name. For sales: deal or account name. |
| string | Primary contact email. | |
| phone | string | Primary contact phone. |
| company | string | Candidate: current employer. Sales: target company. |
| role | string | Candidate: role they're applying for. Sales: role of the contact. |
| contact_id | uuid | Link the dossier to an existing Contact instead of creating a new one. Must belong to your organization. |
| flow_id | uuid | Override the default flow. Must belong to your organization. |
| assigned_to | uuid | User ID of the member to assign this dossier to. |
| intake_notes | string | Director/intake notes shown in the dossier drawer. |
| contact_person | string | Sales only. Named contact at the target company. |
| deal_size | number | Sales only. Expected contract value. |
| deal_currency | string | Sales only. ISO 4217 currency code (e.g. 'EUR'). |
| cv | file (pdf) | multipart/form-data only. Optional PDF CV (max 10 MB). Uploaded and attached in the same call. If the upload fails, the dossier is rolled back. |
# JSON, plain create
curl -X POST https://leadgrid.io/api/v1/dossiers \
-H "Authorization: Bearer lg_live_your_key" \
-H "Content-Type: application/json" \
-d '{
"type": "sales",
"name": "KLM, Cabin crew hiring",
"company": "KLM",
"contact_person": "Pieter van Leeuwen",
"deal_size": 62000,
"deal_currency": "EUR"
}'
# multipart, create + attach CV in one call
curl -X POST https://leadgrid.io/api/v1/dossiers \
-H "Authorization: Bearer lg_live_your_key" \
-F "type=candidate" \
-F "name=Sophie van Dijk" \
-F "role=Senior Frontend Engineer" \
-F "email=sophie@example.com" \
-F "cv=@./resume.pdf"{
"data": {
"id": "a91c…",
"type": "candidate",
"name": "Sophie van Dijk",
"cv_url": "<org-id>/dossiers/a91c…/cv.pdf",
"status": "active",
"current_stage_id": "b77f…",
"created_at": "2026-04-15T12:03:40Z"
}
}/dossiers/:idRécupérer un seul dossier par son ID.
curl https://leadgrid.io/api/v1/dossiers/a91c… \ -H "Authorization: Bearer lg_live_your_key"
{
"data": {
"id": "a91c…",
"type": "sales",
"name": "KLM, Cabin crew hiring",
"deal_size": 62000,
"current_stage_id": "b77f…"
}
}/dossiers/:idMettre à jour un sous-ensemble quelconque de champs. Définir current_stage_id déplace le dossier vers une nouvelle étape et émet un webhook dossier.stage_changed.
| Champ | Type | Description |
|---|---|---|
| name | string | Rename the dossier. |
| string | Update primary contact email. | |
| phone | string | Update phone. |
| company | string | Update company / employer. |
| role | string | Update role. |
| contact_person | string | Sales only. |
| deal_size | number | Sales only. |
| deal_currency | string | Sales only. |
| status | string | 'active', 'won', 'lost' or 'archived'. |
| assigned_to | uuid | Reassign to another member. Null to unassign. |
| intake_notes | string | Replace intake notes. |
| current_stage_id | uuid | Move to a new stage. Must belong to the dossier's flow. |
curl -X PATCH https://leadgrid.io/api/v1/dossiers/a91c… \
-H "Authorization: Bearer lg_live_your_key" \
-H "Content-Type: application/json" \
-d '{ "current_stage_id": "d8e2…", "status": "active" }'{
"data": {
"id": "a91c…",
"current_stage_id": "d8e2…",
"status": "active"
}
}/dossiers/:idArchive le dossier (suppression douce). Définit le statut sur 'archived' et émet dossier.deleted. Les données sont conservées et peuvent être restaurées via PATCH.
curl -X DELETE https://leadgrid.io/api/v1/dossiers/a91c… \ -H "Authorization: Bearer lg_live_your_key"
{
"data": {
"id": "a91c…",
"status": "archived"
}
}/dossiers/:id/cvUploader un CV PDF (max. 10 Mo) et l'attacher à un dossier existant. L'upload remplace tout CV précédent. Accepte multipart/form-data avec un champ 'cv', ou application/pdf avec les octets PDF comme corps brut. Émet dossier.updated.
# multipart/form-data curl -X POST https://leadgrid.io/api/v1/dossiers/a91c…/cv \ -H "Authorization: Bearer lg_live_your_key" \ -F "cv=@./resume.pdf" # raw application/pdf curl -X POST https://leadgrid.io/api/v1/dossiers/a91c…/cv \ -H "Authorization: Bearer lg_live_your_key" \ -H "Content-Type: application/pdf" \ --data-binary @./resume.pdf
{
"data": {
"id": "a91c…",
"cv_url": "<org-id>/dossiers/a91c…/cv.pdf"
}
}Contacts
Les Contacts sont les personnes de ton réseau : candidats, prospects, clients, fournisseurs et partenaires. Un même Contact peut porter plusieurs kinds à la fois et être rattaché à un nombre quelconque de dossiers.
/contactsLister les contacts de ton organisation. Supporte le filtrage par kind, statut de pool et recherche libre, avec pagination.
| Champ | Type | Description |
|---|---|---|
| kind | string | Filter by kind. Repeat the parameter to combine values: 'candidate', 'prospect', 'client', 'supplier' or 'partner'. |
| pool | string | 'in_pool' for contacts currently in the talent pool, 'expired' for contacts whose pool window has passed. |
| search | string | Free-text search over full_name, email, company and role. |
| page | integer | 1-based page number. Default: 1. |
| per_page | integer | Items per page (max 100). Default: 25. |
curl "https://leadgrid.io/api/v1/contacts?kind=candidate&kind=client&search=sophie" \ -H "Authorization: Bearer lg_live_your_key"
{
"data": [
{
"id": "c12a…",
"full_name": "Sophie van Dijk",
"email": "sophie@example.com",
"phone": "+31 6 12345678",
"linkedin_url": "https://linkedin.com/in/sophievandijk",
"company": "Adyen",
"role": "Senior Frontend Engineer",
"city": "Amsterdam",
"kind": ["candidate", "client"],
"notes": null,
"dossier_count": 2,
"created_at": "2026-04-08T11:14:02Z"
}
],
"meta": { "total": 142, "page": 1, "per_page": 25 }
}/contactsCréer un nouveau contact. full_name est le seul champ obligatoire. Si un contact avec la même adresse e-mail existe déjà dans ton organisation (insensible à la casse), l'API retourne 409 avec une erreur duplicate_contact.
| Champ | Type | Description |
|---|---|---|
| full_name* | string | The contact's full name. |
| string | Primary email. Must be unique per organization (case-insensitive). Returns 409 on conflict. | |
| phone | string | Primary phone number. |
| linkedin_url | string | Public LinkedIn profile URL. |
| company | string | Current employer or account. |
| role | string | Job title or role. |
| city | string | City of residence. |
| kind | string[] | Array of kinds: 'candidate', 'prospect', 'client', 'supplier', 'partner'. Defaults to an empty array. |
| notes | string | Free-form internal notes shown on the contact drawer. |
curl -X POST https://leadgrid.io/api/v1/contacts \
-H "Authorization: Bearer lg_live_your_key" \
-H "Content-Type: application/json" \
-d '{
"full_name": "Sophie van Dijk",
"email": "sophie@example.com",
"company": "Adyen",
"role": "Senior Frontend Engineer",
"city": "Amsterdam",
"kind": ["candidate"]
}'{
"data": {
"id": "c12a…",
"full_name": "Sophie van Dijk",
"email": "sophie@example.com",
"company": "Adyen",
"role": "Senior Frontend Engineer",
"city": "Amsterdam",
"kind": ["candidate"],
"dossier_count": 0,
"created_at": "2026-04-30T08:21:14Z"
}
}/contacts/:idRécupérer un seul contact par son ID, avec ses kinds et le nombre agrégé de dossiers associés.
curl https://leadgrid.io/api/v1/contacts/c12a… \ -H "Authorization: Bearer lg_live_your_key"
{
"data": {
"id": "c12a…",
"full_name": "Sophie van Dijk",
"email": "sophie@example.com",
"company": "Adyen",
"role": "Senior Frontend Engineer",
"city": "Amsterdam",
"kind": ["candidate", "client"],
"dossier_count": 2
}
}/contacts/:idMettre à jour partiellement n'importe quel champ d'un contact. N'envoie que les clés que tu veux modifier.
| Champ | Type | Description |
|---|---|---|
| full_name | string | Rename the contact. |
| string | Update primary email. Still subject to the per-org uniqueness check. | |
| phone | string | Update phone number. |
| linkedin_url | string | Update LinkedIn URL. |
| company | string | Update company. |
| role | string | Update role. |
| city | string | Update city. |
| kind | string[] | Replace the full kinds array. Send the complete set of kinds you want on the contact. |
| notes | string | Replace internal notes. |
curl -X PATCH https://leadgrid.io/api/v1/contacts/c12a… \
-H "Authorization: Bearer lg_live_your_key" \
-H "Content-Type: application/json" \
-d '{ "kind": ["candidate", "client"], "city": "Rotterdam" }'{
"data": {
"id": "c12a…",
"kind": ["candidate", "client"],
"city": "Rotterdam"
}
}/contacts/:idSupprimer définitivement le contact. Les liens dans dossier_contacts sont supprimés en cascade, mais les dossiers liés eux-mêmes restent intacts.
curl -X DELETE https://leadgrid.io/api/v1/contacts/c12a… \ -H "Authorization: Bearer lg_live_your_key"
{
"data": {
"id": "c12a…",
"deleted": true
}
}Liens vers les dossiers
Un lien dossier-contact associe un Contact à un dossier et enregistre le rôle qu'il joue sur cette deal ou ce recrutement (primary, hiring manager, decision maker, champion, gatekeeper, introducer ou other). Un dossier peut avoir plusieurs contacts ; un contact peut figurer sur plusieurs dossiers.
/dossiers/:id/contactsLister les contacts liés à un dossier, avec leur rôle et l'indication s'ils sont le contact principal.
curl https://leadgrid.io/api/v1/dossiers/a91c…/contacts \ -H "Authorization: Bearer lg_live_your_key"
{
"data": [
{
"contact_id": "c12a…",
"full_name": "Sophie van Dijk",
"email": "sophie@example.com",
"company": "Adyen",
"role_on_dossier": "primary",
"is_primary": true
},
{
"contact_id": "c44b…",
"full_name": "Mark de Vries",
"email": "mark@rabobank.nl",
"company": "Rabobank",
"role_on_dossier": "decision_maker",
"is_primary": false
}
],
"meta": { "total": 2, "page": 1, "per_page": 25 }
}/dossiers/:id/contactsLier un contact existant à un dossier avec un rôle. Mettre is_primary à true rétrograde tout contact principal précédent sur ce dossier.
| Champ | Type | Description |
|---|---|---|
| contact_id* | uuid | The contact to link. Must belong to your organization. |
| role_on_dossier* | string | One of 'primary', 'hiring_manager', 'decision_maker', 'champion', 'gatekeeper', 'introducer' or 'other'. |
| is_primary | boolean | Default: false. Setting true demotes the previous primary contact on this dossier. |
curl -X POST https://leadgrid.io/api/v1/dossiers/a91c…/contacts \
-H "Authorization: Bearer lg_live_your_key" \
-H "Content-Type: application/json" \
-d '{
"contact_id": "c44b…",
"role_on_dossier": "decision_maker",
"is_primary": false
}'{
"data": {
"dossier_id": "a91c…",
"contact_id": "c44b…",
"role_on_dossier": "decision_maker",
"is_primary": false
}
}/dossiers/:id/contacts/:contact_idDélier un contact d'un dossier. Le contact lui-même est conservé.
curl -X DELETE https://leadgrid.io/api/v1/dossiers/a91c…/contacts/c44b… \ -H "Authorization: Bearer lg_live_your_key"
{
"data": {
"dossier_id": "a91c…",
"contact_id": "c44b…",
"unlinked": true
}
}Flows
Les flows sont les pipelines par lesquels les dossiers progressent. Chaque flow comporte des étapes ordonnées avec des délais et des probabilités de gain optionnels.
/flowsLister les flows de ton organisation. Les étapes sont imbriquées et ordonnées par position.
| Champ | Type | Description |
|---|---|---|
| type | string | Filter to 'candidate' or 'sales'. |
| page | integer | Page number. Default: 1. |
| per_page | integer | Items per page. Default: 25. |
curl "https://leadgrid.io/api/v1/flows?type=sales" \ -H "Authorization: Bearer lg_live_your_key"
{
"data": [
{
"id": "f01a…",
"name": "Sales Flow",
"type": "sales",
"is_default": true,
"stages": [
{
"id": "s1…",
"name": "Lead",
"position": 1,
"deadline_days": 3,
"win_probability": 14,
"color": "#FF5C35"
},
{
"id": "s2…",
"name": "Discovery",
"position": 2,
"deadline_days": 5,
"win_probability": 29,
"color": "#22C55E"
}
]
}
],
"meta": { "total": 1, "page": 1, "per_page": 25 }
}/flows/:id/stagesRécupérer les étapes d'un seul flow, triées par position. Utile si tu connais déjà le flow_id et veux uniquement les étapes.
curl https://leadgrid.io/api/v1/flows/f01a…/stages \ -H "Authorization: Bearer lg_live_your_key"
{
"data": [
{
"id": "s1…",
"name": "Lead",
"position": 1,
"deadline_days": 3,
"win_probability": 14
}
],
"meta": { "total": 6, "page": 1, "per_page": 6 }
}Notes
Les notes constituent la chronologie des mises à jour attachées à un dossier. Elles sont triées de la plus ancienne à la plus récente et sont toujours internes par défaut.
/dossiers/:id/notesLister les notes d'un dossier, les plus anciennes en premier.
curl https://leadgrid.io/api/v1/dossiers/a91c…/notes \ -H "Authorization: Bearer lg_live_your_key"
{
"data": [
{
"id": "n1…",
"dossier_id": "a91c…",
"content": "Had a great first call, strong culture fit.",
"is_internal": true,
"created_at": "2026-04-14T09:12:30Z"
}
],
"meta": { "total": 3, "page": 1, "per_page": 25 }
}/dossiers/:id/notesAjouter une nouvelle note à un dossier. Émet un webhook note.created.
| Champ | Type | Description |
|---|---|---|
| content* | string | The note text. Cannot be empty. |
| is_internal | boolean | Default: true. Internal notes are not shared. |
curl -X POST https://leadgrid.io/api/v1/dossiers/a91c…/notes \
-H "Authorization: Bearer lg_live_your_key" \
-H "Content-Type: application/json" \
-d '{ "content": "Followed up by email." }'{
"data": {
"id": "n2…",
"dossier_id": "a91c…",
"content": "Followed up by email.",
"is_internal": true,
"created_at": "2026-04-15T12:04:10Z"
}
}Webhooks
Configure un endpoint webhook dans Paramètres → API. LeadGrid envoie une requête POST avec un corps JSON lorsque l'un de ces événements se produit.
| Champ | Type | Description |
|---|---|---|
| dossier.created | event | A new dossier was created (via API, UI or email). |
| dossier.updated | event | Any field on a dossier changed. Fires alongside stage_changed when applicable. |
| dossier.stage_changed | event | current_stage_id was updated. |
| dossier.deleted | event | Dossier was archived (status set to 'archived'). |
| note.created | event | A new note was added to a dossier. |
POST https://your-app.com/webhooks/leadgrid
Content-Type: application/json
X-LeadGrid-Signature: t=1713178230,v1=3b2c4f…
{
"id": "evt_…",
"type": "dossier.stage_changed",
"created_at": "2026-04-15T12:04:10Z",
"data": {
"id": "a91c…",
"current_stage_id": "d8e2…",
"status": "active"
}
}Vérification de signature
Chaque requête webhook inclut un en-tête X-LeadGrid-Signature contenant un horodatage et une signature HMAC-SHA256 de `${"timestamp"}.${"body"}` signée avec le secret de ton endpoint. Vérifie-la avant de faire confiance au payload.
import crypto from "node:crypto";
export function verifyLeadGridSignature(
header: string,
body: string,
secret: string,
) {
const parts = Object.fromEntries(
header.split(",").map((p) => p.split("=")),
);
const { t, v1 } = parts as { t: string; v1: string };
const expected = crypto
.createHmac("sha256", secret)
.update(`${t}.${body}`)
.digest("hex");
return crypto.timingSafeEqual(
Buffer.from(expected),
Buffer.from(v1),
);
}Erreurs & limites de débit
Les erreurs utilisent les codes de statut HTTP standard. Le corps contient toujours un objet error avec un code stable et un message lisible.
{
"error": {
"code": "not_found",
"message": "Dossier not found."
}
}| Champ | Type | Description |
|---|---|---|
| unauthorized | 401 | Missing, malformed or invalid API key. Also returned for expired keys. |
| plan_required | 402 | Your organization is on Free or Pro. API access requires Growth. |
| forbidden | 403 | The API key doesn't include the required scope for this action. |
| not_found | 404 | The resource doesn't exist, or doesn't belong to your organization. |
| invalid_body | 400 | Missing required field, unknown value or malformed JSON. |
| rate_limited | 429 | You've exceeded the rate limit for your plan. Retry after the time in the Retry-After header. |
| internal | 500 | Unexpected server error. Safe to retry. |
X-RateLimit-Limit et X-RateLimit-Remaining en-têtes pour que tu puisses ralentir avant d'atteindre la limite.