API et serveur MCP de LKDN Autopilot
Avec les API de LKDN Autopilot, tes programmes, ton CRM, tes automatisations (n8n, Make, Zapier) et tes assistants IA (Claude, ChatGPT) utilisent ton compte LinkedIn connecté, par notre intermédiaire : ils lisent les conversations et les relations, recherchent des personnes, envoient des messages et des demandes de connexion, publient et commentent.
Trois choses à savoir avant tout :
- Un seul compte, le tien. La clé est liée à ton compte LKDN Autopilot et à ton compte LinkedIn. On ne connecte pas d’autres comptes et on ne choisit pas de compte : la clé sait déjà lequel c’est.
- Un seul budget, partagé avec le pilote automatique. Chaque visite, demande de connexion, message, commentaire, réaction et publication faits par les API consomment le même budget quotidien que le pilote automatique, et il en va de même pour chaque lecture qui va jusqu’à LinkedIn (profils, recherches, listes, publications, entreprises), avec les mêmes limites et les mêmes pauses entre une action et la suivante. Si les API utilisent 5 demandes de connexion, le pilote automatique en aura 5 de moins ce jour-là. C’est ainsi que ton compte reste en sécurité.
- Les conversations, nous ne les conservons pas. Quand tu lis une conversation via les API, nous la lisons à ce moment-là depuis ton compte et nous te la transmettons. Nous ne l’enregistrons ni dans nos archives ni dans nos journaux : si tu as besoin de la conserver, c’est ton CRM qui la conserve.
L’accès aux API s’active sur demande, compte par compte : écris-nous à info@lkdnautopilot.com.
Sommaire #
- Démarrer en cinq minutes
- Clés et authentification
- Limites et budget partagé
- Format des réponses
- Idempotency-Key
- Mode simulé
- Endpoints
- Webhooks
- Serveur MCP : Claude, ChatGPT, n8n
- Prompts prêts à l’emploi
- Erreurs
- Confidentialité et responsabilité
- Ce que les API ne font pas
Démarrer en cinq minutes #
- Dans l’app, va sur API et intégrations (en haut de la page d’accueil).
- Crée une clé : un nom (par exemple « mon CRM ») et ce qu’elle peut faire, lecture seule ou lecture et écriture. La clé n’apparaît qu’une seule fois : copie-la et conserve-la en lieu sûr.
- Essaie :
curl https://ayuhpqrbmizgsjstmcrt.supabase.co/functions/v1/public-api/v1/me \
-H "Authorization: Bearer lkdn_sk_LA_TUA_CHIAVE"
La réponse contient ton profil, l’état de la connexion et la formule LinkedIn détectée :
{
"data": {
"id": "per_3mQ8...",
"name": "Giulia Demo",
"headline": "Consulente, Demo Consulting Srl",
"public_identifier": "giulia-demo",
"linkedin_status": "connected",
"linkedin_plan": "premium",
"inmail_credits": 5,
"simulated": false
}
}
L’adresse de base de tous les appels est :
https://ayuhpqrbmizgsjstmcrt.supabase.co/functions/v1/public-api/v1
La spécification OpenAPI complète se trouve dans openapi.json : importe-la dans Postman, Insomnia ou dans un générateur de clients.
Clés et authentification #
Chaque requête porte la clé dans l’en-tête :
Authorization: Bearer lkdn_sk_...
- Une clé a une ou deux autorisations :
read(lire) etwrite(agir : messages, invitations, publications, commentaires, réactions, visites, webhooks). Une clé en lecture seule qui essaie d’agir reçoit403 insufficient_scope. - Tu peux avoir jusqu’à 5 clés actives. Donne une clé différente à chaque programme : si l’une doit être révoquée, les autres continuent de fonctionner.
- La révocation est immédiate : la requête suivante avec cette clé reçoit
401 invalid_api_key. - Nous ne conservons qu’une empreinte de la clé (un hash), jamais la clé elle-même : si tu la perds, crées-en une nouvelle.
- La clé reste sur un serveur, jamais dans une page web ou dans une app qui tourne dans le navigateur. Les API ne répondent pas aux appels faits directement depuis un navigateur.
Limites et budget partagé #
Ton compte LinkedIn a un budget quotidien, le même pour le pilote automatique et pour les API. Nous le fixons en un seul endroit, avec les mêmes règles : la formule LinkedIn détectée, la montée en régime d’un compte nouveau, les limites que tu as choisies et celles que nous pouvons abaisser si le compte est à risque. Les API ne peuvent pas le dépasser, en aucun cas.
| Action | Valeur par défaut par jour | Endpoint |
|---|---|---|
| Visites avec notification | 30 | POST /v1/people/{id}/visits |
| Demandes de connexion | 20 (environ 5 sur un compte LinkedIn gratuit), 100 sur 7 jours | POST /v1/invitations |
| Messages | 25 | POST /v1/conversations, POST /v1/conversations/{id}/messages |
| InMail | 3 | POST /v1/conversations avec inmail: true |
| Commentaires | 10 | POST /v1/posts/{id}/comments |
| Réactions | 20 | POST /v1/posts/{id}/reactions |
| Publications | 2 | POST /v1/posts |
| Retraits de demandes | 10 | DELETE /v1/invitations/{id} |
| Total des actions ci-dessus | 70 | |
| Profils lus (sans notification) | 40 | GET /v1/people/{id} |
| Profils ouverts au total : visites et profils lus ensemble | 70 | POST /v1/people/{id}/visits, GET /v1/people/{id} |
| Résultats de recherche | 300 | POST /v1/searches |
| Listes, publications et pages lues | 40 | GET /v1/me (jusqu’à 2), GET /v1/connections, GET /v1/invitations, GET /v1/people/{id}/posts, GET /v1/posts/{id}, GET /v1/posts/{id}/comments, GET /v1/posts/{id}/reactions, GET /v1/companies/{id} |
Les conversations et les messages (GET /v1/conversations...) ne consomment pas de budget : ils sont déjà synchronisés depuis ton compte, sans requête à LinkedIn pour chaque lecture. Les commentaires et les réactions lisent d’abord la publication : cette lecture est toujours comptée, même si l’action ne part pas ensuite, mais une action n’est jamais refusée à cause du budget des lectures.
Ce sont les valeurs par défaut : celles de ton compte peuvent être plus basses (montée en régime, formule gratuite, limites choisies par toi). Les vraies, celles du jour, sont toujours dans GET /v1/usage, avec ce que tu as déjà utilisé et ce qu’ont utilisé les API.
Aucun chiffre, pas même ceux que nous pouvons relever sur demande, ne dépasse 80 % des limites recommandées pour un compte LinkedIn par l’infrastructure que nous utilisons pour nous connecter : par exemple au maximum 64 demandes de connexion par jour et 160 sur 7 jours, 80 profils ouverts par jour entre visites et lectures, 800 résultats de recherche par jour (2000 avec Sales Navigator ou Recruiter). La base de données refuse tout réglage au-delà de cette marge.
Autres règles qui protègent le compte :
- Les actions sont espacées. Entre une action et la suivante sur ton profil, il s’écoule quelques minutes, avec un intervalle aléatoire, comme le ferait une personne ; de temps en temps la pause est plus longue (parfois trois quarts d’heure). Si tu demandes une action trop tôt, tu reçois
429 action_pacedavecRetry-Afteren secondes. - Les actions vers de nouvelles personnes suivent ta plage d’activité. Les visites, les demandes de connexion et les InMail ne partent que les jours et aux heures que tu as choisis dans l’app (hors plage :
429 outside_activity_window). Les messages dans les conversations, les commentaires, les réactions et les publications, non. - Les personnes à ne pas contacter ne sont pas contactées. Pour qui a demandé à ne pas être contacté, qui tu as exclu ou qui appartient aux catégories que nous ne contactons pas (par exemple le marketing de réseau), la réponse est
403 person_not_contactable, même via les API. - Le pilote automatique ne recontacte pas les personnes que tu contactes via les API. La personne devient la tienne : le pilote automatique l’ignore à partir de ce moment-là.
- Un refus définitif de LinkedIn reste définitif. Si LinkedIn n’accepte plus de demandes vers une personne, l’API répond
422 invitation_not_allowedet ne réessaie pas. - Quand LinkedIn demande de ralentir, le compte ralentit. Si LinkedIn signale trop de requêtes (un
429), toutes les actions et les lectures s’arrêtent jusqu’à minuit dans ton fuseau horaire ; si cela arrive deux jours de suite, pendant 7 jours les demandes de connexion et les messages sont réduits de moitié. Si LinkedIn signale la limite des demandes de connexion, les demandes s’arrêtent jusqu’à la fin du lendemain. Entre-temps tu reçois429 account_backoffavecRetry-After, etGET /v1/usageen donne la raison dansbackoff. Cela vaut pour le pilote automatique et pour les API ensemble. - Requêtes aux API : au maximum 60 par minute par clé et 2000 par jour par compte, lectures comprises (
429 rate_limited,429 daily_request_limit).
Chaque 429 a l’en-tête Retry-After : le nombre de secondes après lequel réessayer. Quand le budget du jour est épuisé, Retry-After pointe vers l’ouverture de ta prochaine plage d’activité. Un agent IA qui reçoit un 429 doit s’arrêter et le dire, pas réessayer en boucle.
Format des réponses #
Les réponses sont en JSON, avec des noms en anglais et toujours les mêmes :
- un objet :
{"data": {...}} - une liste :
{"data": [...], "page": {"next_cursor": "cur_..." }}; pour la page suivante, passecursor=cur_...;next_cursorvautnullà la dernière page. Les curseurs expirent au bout d’une heure et ne valent que pour la liste qui les a fournis. - les dates sont en ISO 8601 en UTC (
2026-10-25T09:30:00.000Z) et leurs champs se terminent par_at. - les
idsont opaques et stables, avec un préfixe qui dit ce qu’ils désignent :per_personne,cnv_conversation,msg_message,inv_demande de connexion,pst_publication,cmt_commentaire,cmp_entreprise,flt_filtre de recherche,whk_webhook. Tu peux les enregistrer dans ton CRM : la même personne a toujours le mêmeid. Ils ne valent que pour ton compte. - là où c’est utile, il y a aussi les références publiques de LinkedIn :
public_identifier(la partie aprèslinkedin.com/in/) etprofile_url. degreeest le niveau de relation :1,2,3ounull(hors réseau ou inconnu).
Chaque réponse a l’en-tête X-Request-Id : cite-le si tu nous écris à propos d’un problème.
Les erreurs suivent la norme RFC 9457 (Content-Type: application/problem+json) :
{
"type": "https://lkdnautopilot.com/api-doc/#errori-daily_budget_exhausted",
"title": "The daily budget for this action is used up, by the autopilot and the API together.",
"status": 429,
"code": "daily_budget_exhausted",
"request_id": "req_9f2c...",
"retry_after": 52310
}
Le champ à lire dans le code est code : il est stable et ne change jamais de sens. La liste complète se trouve dans Erreurs.
Idempotency-Key #
Chaque requête qui agit (POST et DELETE, sauf POST /v1/searches, qui est une lecture) exige l’en-tête Idempotency-Key : une valeur unique choisie par toi, de 8 à 200 caractères, par exemple un UUID.
curl -X POST https://ayuhpqrbmizgsjstmcrt.supabase.co/functions/v1/public-api/v1/invitations \
-H "Authorization: Bearer lkdn_sk_..." \
-H "Idempotency-Key: 6b1f0e5e-2f4a-4c39-9a0e-4d8f2f0a1c11" \
-H "Content-Type: application/json" \
-d '{"person_id": "per_3mQ8...", "message": "Ciao Marco, ho letto il tuo post sulla logistica e mi è piaciuto."}'
- Si tu répètes la même requête avec la même clé (un délai dépassé, une erreur réseau), tu reçois la même réponse et l’action n’est pas répétée. La réponse a
Idempotency-Replayed: true. - La même clé avec une requête différente :
422 idempotency_key_reused. - Si la première requête est encore en cours :
409 idempotency_in_progress. - Si la requête n’a pas agi (un 429, un 400, un 409 d’état du compte), la clé est libérée et tu peux réessayer avec la même.
- Les clés sont mémorisées pendant 24 heures.
502 action_outcome_unknown signifie que LinkedIn ne nous a pas donné de réponse lisible et que l’action est peut-être partie, peut-être pas. Ne réessaie pas avec une nouvelle clé : vérifie d’abord (pour un message, lis la conversation).
Mode simulé #
Tant que ton compte est en préparation, les API répondent avec des données simulées (des personnes fictives) et aucune action ne part réellement : les actions passent quand même par les limites et sont enregistrées. Les réponses simulées ont l’en-tête LKDN-Mode: simulated et, pour les actions, "simulated": true. C’est la bonne façon de construire et de tester une intégration sans toucher personne.
Endpoints #
Tous les chemins sont relatifs à l’adresse de base. Lecture : autorisation read. Action : autorisation write et Idempotency-Key.
Ton compte #
GET /v1/me (lecture). Ton profil, linkedin_status (connected, reconnect_required, not_connected), linkedin_plan (free, premium, sales_navigator), les crédits InMail. Consomme jusqu’à deux lectures de listes (le profil et les crédits InMail).
GET /v1/usage (lecture). Le budget du jour, partagé avec le pilote automatique :
{
"data": {
"date": "2026-10-25",
"timezone": "Europe/Rome",
"linkedin_plan": "premium",
"invitation_note_available": true,
"requests": { "today": 41, "per_day": 2000, "per_minute": 60 },
"budget": {
"invitations": { "used": 7, "limit": 20, "used_by_api": 2, "weekly_limit": 100 },
"messages": { "used": 3, "limit": 25, "used_by_api": 3 },
"list_reads": { "used": 6, "limit": 40, "used_by_api": 6 },
"profile_retrievals": { "used": 21, "limit": 70, "used_by_api": 4 },
"total_actions": { "used": 18, "limit": 70 }
},
"activity_window": { "open_now": true, "start": "09:00", "end": "18:00", "working_day": true },
"backoff": null,
"shared_with_autopilot": true
}
}
backoff vaut null, ou bien indique pourquoi le compte va plus lentement aujourd’hui : {"kind": "all_stop" | "invite_stop" | "halved", "reason": "...", "until": "2026-10-26T23:00:00.000Z"} (tout arrêté, demandes de connexion arrêtées, rythme réduit de moitié) et jusqu’à quand.
Personnes #
GET /v1/people/{id} (lecture). Un profil : id est un per_... ou le public_identifier. La personne n’est pas prévenue. Consomme un « profil lu » (et compte dans les profils ouverts au total). Ne renvoie ni l’e-mail ni les numéros de téléphone d’autres personnes.
POST /v1/people/{id}/visits (action). Visite le profil : la personne voit que tu l’as consulté. Consomme une visite.
GET /v1/people/{id}/posts (lecture). Les publications récentes de la personne. limit jusqu’à 50, cursor. Consomme une lecture de listes par page.
GET /v1/connections (lecture). Tes relations de premier niveau, de la plus récente à la plus ancienne. q filtre par nom, limit jusqu’à 200, cursor. Consomme une lecture de listes par page.
Recherche #
GET /v1/search/filters?type=location&q=verona (lecture). Transforme un lieu (type=location) ou un secteur (type=industry) en un filtre flt_... à utiliser dans la recherche. Utilise-le toujours : la recherche refuse un filtre qui ne vient pas d’ici (400 invalid_filter), parce que LinkedIn ignorerait en silence un filtre inconnu et te donnerait les résultats d’une recherche différente de celle que tu voulais.
POST /v1/searches (lecture). Recherche des personnes :
{
"keywords": "logistica",
"titles": ["CFO", "direttore finanziario"],
"locations": ["flt_..."],
"industries": ["flt_..."],
"degree": [2, 3],
"limit": 10
}
Au moins un parmi keywords, titles, locations, industries. limit jusqu’à 10 (jusqu’à 25 avec Sales Navigator) ; chaque résultat consomme un « résultat de recherche ». Pour la page suivante, répète la même recherche avec cursor. La réponse contient aussi page.total_estimate.
Conversations #
GET /v1/conversations (lecture). Tes conversations, de la plus récente à la plus ancienne : type (direct ou group), participant_id, kind (message, inmail, sponsored, offer), inbox, unread_count, last_activity_at. unread=true pour les seules non lues, limit jusqu’à 100, cursor.
GET /v1/conversations/{id} (lecture). Une conversation.
GET /v1/conversations/{id}/messages (lecture). Les messages, du plus récent au plus ancien : text, from_me, sender_id, sent_at, kind, seen, attachments (type et nom, sans lien). Le texte, nous le lisons depuis ton compte à ce moment-là et nous ne le conservons pas.
POST /v1/conversations/{id}/messages (action). Réponds dans une conversation à deux : {"text": "..."} (jusqu’à 8000 caractères). Les conversations de groupe ne sont pas prises en charge (422 group_conversation_not_supported).
POST /v1/conversations (action). Écris à une personne : {"person_id": "per_...", "text": "..."}. Fonctionne avec les relations de premier niveau (sinon 422 not_first_degree). Pour un InMail à quelqu’un qui n’est pas dans tes relations : {"person_id": "per_...", "text": "...", "inmail": true, "subject": "..."} ; cela consomme un InMail du budget et un crédit InMail de ta formule.
Demandes de connexion #
GET /v1/invitations?direction=sent (lecture). Les demandes que tu as envoyées et qui sont en attente ; direction=received pour celles que tu as reçues. Consomme une lecture de listes par page.
POST /v1/invitations (action). {"person_id": "per_...", "message": "..."}. La note (message, jusqu’à 300 caractères) n’est pas disponible sur un compte LinkedIn gratuit (403 invitation_note_not_available) : avec cette formule, la demande part sans note. Déjà en relation : 409 already_connected ; demande déjà en attente : 409 already_invited.
DELETE /v1/invitations/{id} (action). Retire une demande envoyée et encore en attente.
Publications #
GET /v1/posts/{id} (lecture). Une publication : id est un pst_..., un URN LinkedIn (urn:li:activity:...) ou le numéro de l’activité. Consomme une lecture de listes.
GET /v1/posts/{id}/comments, GET /v1/posts/{id}/reactions (lecture). Commentaires et réactions. Consomme une lecture de listes par page.
POST /v1/posts (action). Publie sur ton profil : {"text": "..."} (jusqu’à 3000 caractères).
POST /v1/posts/{id}/comments (action). {"text": "...", "reply_to": "cmt_..."} ; reply_to pour répondre à un commentaire. L’auteur de la publication reçoit une notification.
POST /v1/posts/{id}/reactions (action). {"type": "like"} ; type est l’une des valeurs like, celebrate, support, love, insightful, funny.
Entreprises #
GET /v1/companies/{id} (lecture). Une page entreprise : id est un cmp_... ou le nom public après linkedin.com/company/. Consomme une lecture de listes.
Webhooks #
GET /v1/webhooks (lecture), POST /v1/webhooks (action), DELETE /v1/webhooks/{id} (action). Voir Webhooks.
Webhooks #
Au lieu de demander chaque minute « y a-t-il du nouveau ? », c’est nous qui t’appelons. Crée un webhook depuis l’app (API et intégrations) ou avec :
curl -X POST https://ayuhpqrbmizgsjstmcrt.supabase.co/functions/v1/public-api/v1/webhooks \
-H "Authorization: Bearer lkdn_sk_..." -H "Idempotency-Key: $(uuidgen)" -H "Content-Type: application/json" \
-d '{"url": "https://crm.example.com/hooks/lkdn", "events": ["message.received", "connection.accepted"]}'
La réponse contient le secret de signature (whsec_...) une seule fois.
| Événement | Quand | data |
|---|---|---|
message.received | une personne t’écrit | conversation_id, message_id, sender_id, sent_at |
connection.accepted | une demande de connexion est acceptée (cela peut arriver jusqu’à 8 heures plus tard) | person_id, public_identifier, accepted_at |
invitation.sent | une demande de connexion part, du pilote automatique ou des API | invitation_id, person_id, source (autopilot ou api), sent_at |
account.status_changed | la connexion de ton compte change d’état | status, previous_status, changed_at ; états : connected, connecting, reconnect_required, disconnected, error |
Le corps de l’appel :
{
"id": "evt_0b6f1f40000040008000000000000001",
"type": "message.received",
"created_at": "2026-10-25T10:00:03.000Z",
"data": {
"conversation_id": "cnv_...",
"message_id": "msg_...",
"sender_id": "per_...",
"sent_at": "2026-10-25T10:00:00.000Z"
}
}
Le texte du message ne transite pas dans le webhook : lis-le avec GET /v1/conversations/{conversation_id}/messages. Ainsi, aucun texte ne reste dans nos files d’envoi.
Chaque appel a les en-têtes LKDN-Event-Id, LKDN-Event-Type et LKDN-Signature: t=<secondi unix>,v1=<firma> (l’horodatage en secondes Unix, puis la signature). La signature est le HMAC-SHA256, en hexadécimal, de la chaîne <t>.<corpo esatto> (l’horodatage, un point, le corps exact) avec ton secret. Vérifie-la toujours, et refuse un appel vieux de plus de 5 minutes :
// Node.js
import { createHmac, timingSafeEqual } from 'node:crypto';
export function verify(secret, rawBody, header, now = Math.floor(Date.now() / 1000)) {
const m = /^t=(\d+),v1=([0-9a-f]{64})$/.exec(header ?? '');
if (!m || Math.abs(now - Number(m[1])) > 300) return false;
const expected = createHmac('sha256', secret).update(`${m[1]}.${rawBody}`).digest('hex');
return timingSafeEqual(Buffer.from(expected), Buffer.from(m[2]));
}
# Python
import hashlib, hmac, re, time
def verify(secret: str, raw_body: str, header: str) -> bool:
m = re.fullmatch(r"t=(\d+),v1=([0-9a-f]{64})", header or "")
if not m or abs(time.time() - int(m.group(1))) > 300:
return False
expected = hmac.new(secret.encode(), f"{m.group(1)}.{raw_body}".encode(), hashlib.sha256).hexdigest()
return hmac.compare_digest(expected, m.group(2))
Réponds avec un code 2xx dans les 10 secondes. Sinon, nous réessayons après 1, 5 et 30 minutes, puis 2, 6, 12 et 24 heures ; après 8 tentatives l’événement est perdu, et après 20 événements perdus d’affilée le webhook se désactive (tu le réactives depuis l’app). Un 410 Gone le désactive immédiatement pour cet événement. Le même événement peut arriver deux fois : utilise id pour le reconnaître. Nous n’acceptons que des adresses https sur le port 443, jamais d’adresses internes ou privées, et nous ne suivons pas les redirections.
Serveur MCP : Claude, ChatGPT, n8n #
Le serveur MCP expose les mêmes fonctions sous forme d’outils pour un assistant IA, avec la même clé et les mêmes limites : il n’existe aucun chemin qui les contourne. Les outils qui agissent l’indiquent dans leur description, et demandent à l’assistant de te montrer le texte exact et d’attendre ton accord.
Adresse :
https://ayuhpqrbmizgsjstmcrt.supabase.co/functions/v1/mcp
Authentification : Authorization: Bearer lkdn_sk_.... Pour les programmes qui ne permettent pas de définir un en-tête, il existe la forme avec la clé dans l’adresse, .../functions/v1/mcp/lkdn_sk_... : traite-la comme un mot de passe, car qui a l’adresse a la clé. Utilise pour cela une clé dédiée, et en lecture seule s’il suffit à l’assistant de lire.
Outils : get_my_profile, get_usage, get_person, visit_profile, list_person_posts, list_connections, find_search_filters, search_people, list_conversations, get_conversation_messages, send_message, start_conversation, list_invitations, send_invitation, withdraw_invitation, get_post, list_post_comments, list_post_reactions, publish_post, comment_on_post, react_to_post, get_company.
Claude Code #
claude mcp add --transport http lkdn-autopilot \
https://ayuhpqrbmizgsjstmcrt.supabase.co/functions/v1/mcp \
--header "Authorization: Bearer lkdn_sk_..."
Claude Desktop #
Dans Paramètres, Développeur, Modifier la configuration (claude_desktop_config.json), avec le pont mcp-remote (il faut Node.js) :
{
"mcpServers": {
"lkdn-autopilot": {
"command": "npx",
"args": ["-y", "mcp-remote", "https://ayuhpqrbmizgsjstmcrt.supabase.co/functions/v1/mcp",
"--header", "Authorization:Bearer ${LKDN_API_KEY}"],
"env": { "LKDN_API_KEY": "lkdn_sk_..." }
}
}
}
Redémarre Claude Desktop : les outils apparaissent dans le menu des outils.
Claude.ai (connecteur personnalisé) #
Dans Paramètres, Connecteurs, Ajouter un connecteur personnalisé : comme URL, utilise la forme avec la clé dans l’adresse, https://ayuhpqrbmizgsjstmcrt.supabase.co/functions/v1/mcp/lkdn_sk_..., et laisse vides les champs OAuth. Le connecteur personnalisé est disponible dans les formules de Claude qui le prévoient.
ChatGPT #
Dans Paramètres, Applications et connecteurs, avec le mode développeur activé : crée un connecteur avec l’URL sous la forme avec la clé dans l’adresse et l’authentification « aucune ». Les outils qui agissent demandent une confirmation avant de partir.
n8n #
Dans le nœud MCP Client Tool d’un AI Agent : Endpoint https://ayuhpqrbmizgsjstmcrt.supabase.co/functions/v1/mcp, transport HTTP Streamable, authentification Bearer avec ta clé. Pour un flux sans IA, utilise le nœud HTTP Request sur les API REST, avec un identifiant « Header Auth » (Authorization = Bearer lkdn_sk_...), et un nœud Webhook comme destination de nos webhooks.
Prompts prêts à l’emploi #
À coller dans Claude ou ChatGPT avec le serveur MCP connecté.
Les réponses du jour
Regarde mes conversations LinkedIn non lues. Pour chacune, dis-moi qui est la personne (nom, poste, entreprise),
ce qu’elle m’a écrit en une ligne et si, selon toi, il faut lui répondre aujourd’hui. Ne réponds à personne : propose-moi
un brouillon de réponse seulement pour celles qui comptent, et attends mon accord sur chaque texte.
Préparer un rendez-vous
Lis le profil LinkedIn de <nom ou lien> et ses dernières publications. Prépare-moi cinq lignes : qui est cette personne,
de quoi elle s’occupe en ce moment, ce qu’elle a écrit récemment, un point commun avec moi et une question intelligente à lui poser.
Ne visite pas le profil avec notification et ne lui écris pas.
Trouver des personnes pour un segment
Cherche sur LinkedIn des titulaires et des directeurs de cabinets dentaires en Vénétie (utilise find_search_filters pour le lieu).
Montre-moi les 10 premiers dans un tableau avec nom, poste, ville et niveau de relation. Avant de chercher, dis-moi
combien de résultats de recherche il me reste aujourd’hui (get_usage). N’envoie pas de demandes de connexion.
Des demandes de connexion avec une vraie note
Pour chacune de ces personnes <liste de liens> : lis le profil, écris-moi une note de connexion de 250 caractères au maximum,
en français, qui parle de quelque chose de vrai dans son profil, sans rien vendre et sans lien.
Montre-moi toutes les notes. N’envoie que celles que j’approuve, une à la fois, et arrête-toi si le budget du jour est épuisé.
Répondre aux commentaires sur mes publications
Prends ma dernière publication (cherche-la parmi les publications de mon profil) et lis les commentaires. Pour ceux auxquels
je n’ai pas encore répondu, propose-moi une réponse courte et cordiale. Ne publie que les réponses que j’approuve.
Le récapitulatif de la semaine
Dis-moi combien de demandes de connexion j’ai en attente depuis plus de deux semaines, et qui sont ces personnes.
Propose-moi lesquelles retirer. N’en retire aucune sans mon accord.
Règles valables pour chaque prompt : l’assistant ne doit pas inventer de faits sur la personne, il doit te montrer chaque texte avant de l’envoyer, et quand il reçoit action_paced, daily_budget_exhausted ou outside_activity_window, il doit s’arrêter et te le dire.
Erreurs #
Chaque erreur a un code stable : c’est un contrat, il ne change jamais de sens. Lis le code, pas le texte.
| Statut | code | Ce que cela veut dire, que faire |
|---|---|---|
| 400 | invalid_request | un champ manque ou n’est pas valide (field, detail indiquent lequel) |
| 400 | invalid_cursor | curseur malformé, expiré ou provenant d’une autre liste : recommence depuis la première page |
| 400 | invalid_filter | un filtre de recherche ne vient pas de GET /v1/search/filters |
| 400 | idempotency_key_required | Idempotency-Key manque sur une requête qui agit |
| 401 | invalid_api_key | clé manquante, inconnue ou révoquée |
| 403 | insufficient_scope | la clé n’a pas l’autorisation write |
| 403 | api_access_not_enabled | les API ne sont pas activées pour ton compte |
| 403 | subscription_inactive | l’abonnement n’est pas actif |
| 403 | person_not_contactable | cette personne ne doit pas être contactée par ce compte |
| 403 | invitation_note_not_available | avec ta formule LinkedIn, la demande ne peut pas avoir de note |
| 403 | linkedin_feature_missing | il faut un produit LinkedIn que le compte n’a pas |
| 404 | not_found | la ressource n’existe pas ou n’appartient pas à ton compte |
| 404 | route_not_found | l’endpoint n’existe pas |
| 405 | method_not_allowed | l’endpoint existe, mais pas avec cette méthode |
| 409 | linkedin_not_connected | aucun compte LinkedIn connecté : connecte-le depuis l’app |
| 409 | linkedin_reconnect_required | le compte doit être reconnecté depuis l’app |
| 409 | linkedin_account_unavailable | le compte est suspendu pour le moment |
| 409 | account_paused | notre équipe a mis en pause les actions de ce compte |
| 409 | idempotency_in_progress | la requête avec cette Idempotency-Key est encore en cours ou ne s’est pas terminée |
| 409 | already_connected | vous êtes déjà en relation |
| 409 | already_invited | il y a déjà une demande en attente vers cette personne |
| 422 | idempotency_key_reused | la même Idempotency-Key avec une requête différente |
| 422 | invitation_not_allowed | LinkedIn n’autorise pas une autre demande à cette personne : c’est définitif |
| 422 | recipient_unreachable | la personne n’est pas joignable |
| 422 | not_first_degree | pour un message, il faut une relation de premier niveau : envoie une demande ou un InMail |
| 422 | inmail_not_allowed | on ne peut pas envoyer d’InMail à cette personne |
| 422 | insufficient_inmail_credits | crédits InMail épuisés |
| 422 | comments_disabled | les commentaires sont fermés sur cette publication |
| 422 | group_conversation_not_supported | les conversations de groupe ne sont pas prises en charge |
| 422 | action_refused | LinkedIn a refusé l’action |
| 422 | invalid_webhook | le webhook ne peut pas être créé (reason indique pourquoi) |
| 429 | rate_limited | trop de requêtes pour cette clé : attends Retry-After |
| 429 | daily_request_limit | requêtes du jour épuisées pour ce compte |
| 429 | daily_budget_exhausted | le budget du jour pour cette action est épuisé, pilote automatique et API ensemble |
| 429 | weekly_budget_exhausted | le budget hebdomadaire de demandes de connexion est épuisé |
| 429 | action_paced | actions espacées pour protéger le compte : attends Retry-After |
| 429 | outside_activity_window | en dehors de ta plage d’activité |
| 429 | linkedin_rate_limited | LinkedIn limite le compte en ce moment : réessaie plus tard |
| 429 | account_backoff | LinkedIn a demandé au compte de ralentir : cette action est en pause jusqu’à Retry-After |
| 500 | internal_error | une erreur de notre côté |
| 502 | linkedin_error | LinkedIn a donné une réponse que nous ne savons pas lire |
| 502 | action_outcome_unknown | l’action est peut-être partie, peut-être pas : vérifie avant de réessayer |
| 503 | api_unavailable | les API sont désactivées en ce moment |
| 503 | service_not_configured | le service n’est pas encore configuré |
| 503 | linkedin_unavailable | LinkedIn n’a pas répondu à temps : réessaie plus tard |
Confidentialité et responsabilité #
- Messages en transit. Les conversations et les messages lus via les API passent par nous et t’arrivent ; nous ne les enregistrons ni dans nos archives ni dans nos journaux. Il en va de même pour les textes que tu envoies : messages, notes, commentaires et publications vont à LinkedIn et ne restent pas chez nous. Du trafic des API, nous n’enregistrons que ce qui a été demandé (le type de requête, le résultat, la durée), pendant 90 jours, et les actions effectuées (quel type, vers quelle personne, quand, sans texte), pendant 180 jours, parce qu’elles servent à faire respecter les limites.
- Le responsable du traitement, c’est toi. Pour les données des personnes que tu lis et contactes, c’est toi le responsable du traitement, comme pour le pilote automatique ; nous sommes sous-traitant selon l’accord (DPA) que tu as accepté. Si tu conserves les conversations dans ton CRM, cette conservation relève de toi.
- Ce que font tes programmes, c’est ton compte qui le fait. Chaque action faite avec l’une de tes clés, par l’un de tes programmes ou par un assistant IA que tu as connecté, est faite en ton nom et sous ta responsabilité, vis-à-vis de LinkedIn et des personnes contactées, comme le prévoient les Conditions d’utilisation. Garde tes clés en sécurité et révoque immédiatement celle que tu penses être tombée entre de mauvaises mains.
- Les limites de LinkedIn sont réelles. LinkedIn n’aime pas l’usage automatisé : nos limites existent pour réduire le risque, elles ne l’annulent pas. Le risque d’une limitation du compte reste le tien.
Ce que les API ne font pas #
- Elles ne connectent pas d’autres comptes, ne créent pas et ne suppriment pas de connexions à LinkedIn : la connexion se fait uniquement depuis l’app.
- Elles ne donnent pas un accès libre à LinkedIn : seulement les opérations de cette page, chacune avec ses limites.
- Elles ne dépassent jamais les limites de ton compte, même si tu le leur demandes.
- Elles ne conservent pas tes conversations.
- Elles ne fonctionnent avec aucune autre plateforme que LinkedIn.