API Captiv · v1
Connectez Captiv à votre stack
Une API REST pour lire vos leads, posts, ressources et analytics — et écrire dans votre pipeline depuis Make, n8n, Zapier, votre CRM ou votre propre code.
curl https://captiv-ai.com/api/v1/me \ -H "Authorization: Bearer cptv_live_VOTRE_CLE"
{
"data": {
"object": "me",
"workspace": { "name": "Mon workspace", "plan": "pro" },
"api_key": { "scopes": ["read:leads", "read:posts"] }
},
"meta": { "request_id": "req_7ad84bf44a494163" }
}01 — Démarrage
Opérationnel en 3 minutes
Créez une clé
Vérifiez l'authentification
curl https://captiv-ai.com/api/v1/me \
-H "Authorization: Bearer cptv_live_VOTRE_CLE"Lisez vos leads qualifiés
curl "https://captiv-ai.com/api/v1/leads?min_score=70&limit=25" \
-H "Authorization: Bearer cptv_live_VOTRE_CLE"02 — Authentification
Clés scopées, workspace cloisonné
Chaque requête porte votre clé dans le header Authorization: Bearer cptv_live_…. Une clé appartient à un workspace: tout ce que l'API lit ou écrit est strictement limité à ce workspace.
- La clé n'est jamais stockée en clairchez Captiv (empreinte SHA-256) et n'est affichée qu'une fois, à la création.
- Une clé compromise se révoque instantanément depuis les Réglages — la révocation est définitive.
- L'API est incluse dans les plans Pro (1 000 req/h) et Agence(10 000 req/h).
Scopes disponibles
read:leads | Lire les leads du workspace (liste, détail, interactions) |
write:leads | Qualifier un lead, ajouter des notes |
read:posts | Lire les posts surveillés et leurs métriques |
write:posts | Attacher un visuel à un post Studio (sans coût IA) |
read:resources | Lire les ressources (lead magnets) et leurs stats |
write:resources | Éditer les blocs d'une ressource (contenu, ordre, ajout, suppression) |
read:analytics | Lire les métriques agrégées du workspace |
write:webhooks | Gérer les webhooks sortants du workspace |
generate:posts | Générer des posts et leurs questions de cadrage — consomme le budget IA du workspace |
generate:resources | Générer des ressources (lead magnets) — consomme le budget IA du workspace |
read:followups | Lire la liste des follow-ups en attente |
write:followups | Ajouter un lead à la liste des follow-ups (l'agent relancera plus tard, sous ses caps) |
read:agent | Lire l'activité de l'agent : ce qu'il a prévu, ce qu'il a fait, la santé du compte LinkedIn et les quotas anti-ban restants (lecture seule) |
03 — Conventions
Un contrat, quatre règles
Enveloppe de succès
Toute réponse 2xx est enveloppée dans { data, meta }. meta.request_id identifie la requête — donnez-le au support en cas de problème (il est aussi dans le header X-Request-Id).
Pagination par curseur
Les listes sont paginées par un curseur opaque — jamais d'offset. Tant que meta.pagination.has_more est vrai, rappelez le même endpoint avec ?cursor=<next_cursor>. Aucune ligne n'est sautée ni dupliquée, même si des écritures arrivent entre deux pages.
cursor=""
while : ; do
page=$(curl -s "https://captiv-ai.com/api/v1/leads?limit=100&cursor=$cursor" \
-H "Authorization: Bearer cptv_live_VOTRE_CLE")
echo "$page" | jq '.data[]'
[ "$(echo "$page" | jq -r '.meta.pagination.has_more')" = "true" ] || break
cursor=$(echo "$page" | jq -r '.meta.pagination.next_cursor')
doneTrois scores, trois sens
Un lead porte trois scores distincts — ne les confondez pas : lead_score (0-100, la source de vérité, celle du dashboard), engagement_score (0-100, pondéré par le comportement réel du lead sur vos ressources) et icp_fit_score (0-100, adéquation à votre ICP).
Isolation stricte
Un id qui n'appartient pas à votre workspace répond 404, jamais 403 : l'API ne confirme jamais l'existence d'une ressource chez un autre client.
04 — Référence
Les endpoints
Base : https://captiv-ai.com/api/v1 — la spécification machine-readable est sur /openapi/v1.yaml.
Introspection de la clé
Retourne le workspace, le plan et les scopes de la clé utilisée. C'est l'endpoint de smoke test : si cet appel répond 200, votre intégration est correctement authentifiée.
curl https://captiv-ai.com/api/v1/me \
-H "Authorization: Bearer cptv_live_VOTRE_CLE"{
"data": {
"object": "me",
"workspace": { "id": "…", "name": "Mon workspace", "plan": "pro" },
"api_key": {
"id": "…", "name": "Sync CRM production",
"environment": "live",
"scopes": ["read:leads", "read:posts"],
"created_at": "2026-08-06T18:00:00Z"
}
},
"meta": { "request_id": "req_…" }
}Lister les leads
Liste paginée des leads capturés par vos posts, du plus récent au plus ancien. Chaque lead porte son profil, ses contacts, ses scores et l'état de son pipeline LinkedIn. Attention au sens des scores : lead_score mesure l'ADÉQUATION AU PROFIL recherché (un « VIP » est à 85+), pas l'engagement — un lead à 95 peut n'avoir jamais rien fait. L'engagement se mesure sur les interactions.
Paramètres de requête
post_id | uuid | Ne retourner que les leads d'un post donné. |
min_score | entier 0-100 | lead_score minimal = adéquation au profil (ICP), pas engagement. VIP = 85+. |
min_interactions | entier | Nombre minimal d'interactions du lead — un vrai signal de comportement. |
resource_opened | booléen | Ne garder que ceux qui ont ouvert la ressource (signal fort). |
search | texte | Recherche sur le prénom, le nom et la société. Le terme est assaini (lettres, chiffres, espace, apostrophe, trait d'union, esperluette) ; deux caractères utiles minimum, sinon le filtre est ignoré. |
connection_status | connected | pending | invitation_ignored | not_requested | not_connected | unreachable_locked | unreachable_no_urn | Où en est la relation LinkedIn. not_requested = jamais invité ; invitation_ignored = restée sans suite. |
limit | entier 1-100 | Taille de page. Défaut : 50. |
cursor | chaîne opaque | Curseur de la page suivante, tel que renvoyé dans meta.pagination.next_cursor. Ne pas le construire soi-même. |
order | created_desc | created_asc | Ordre chronologique. Défaut : created_desc (plus récents d'abord). |
since | datetime ISO 8601 | Ne retourner que les objets créés après cette date. |
until | datetime ISO 8601 | Ne retourner que les objets créés avant cette date. |
curl "https://captiv-ai.com/api/v1/leads?min_score=70&limit=25" \
-H "Authorization: Bearer cptv_live_VOTRE_CLE"{
"data": [
{
"id": "…", "object": "lead", "post_id": "…",
"created_at": "2026-08-05T09:12:00Z", "source": "comment",
"profile": { "first_name": "Marie", "last_name": "…", "job_title": "Head of Sales",
"company": "…", "linkedin_url": "…", "photo_url": "…",
"location_city": "Paris", "location_country": "France" },
"contact": { "email": "…", "personal_email": null, "phone_e164": null },
"scoring": { "lead_score": 86, "label": "vip", "engagement_score": 91,
"icp_fit_score": 86, "strengths": ["…"], "red_flags": [],
"reasoning": "…" },
"pipeline": { "connection_status": "accepted", "resource_sent": true,
"resource_opened": true, "meeting_booked": false, "…": "…" },
"interaction_count": 3
}
],
"meta": {
"request_id": "req_…",
"pagination": { "next_cursor": "eyJ2IjoxLCJjYSI6…", "has_more": true }
}
}Détail d'un lead
Retourne un lead par son id. Un id inexistant — ou appartenant à un autre workspace — répond 404 : l'API ne confirme jamais l'existence d'une ressource hors de votre workspace.
curl https://captiv-ai.com/api/v1/leads/LEAD_ID \
-H "Authorization: Bearer cptv_live_VOTRE_CLE"{ "data": { "id": "…", "object": "lead", "…": "…" }, "meta": { "request_id": "req_…" } }Notes d'un lead
Les 100 dernières notes du lead, plus récentes d'abord.
curl https://captiv-ai.com/api/v1/leads/LEAD_ID/notes \
-H "Authorization: Bearer cptv_live_VOTRE_CLE"{
"data": [
{ "id": "…", "object": "lead_note", "lead_id": "…",
"content": "Rappel prévu jeudi 10h", "source": "api",
"created_at": "2026-08-06T10:00:00Z", "updated_at": null }
],
"meta": { "request_id": "req_…" }
}Ajouter une note à un lead
Cas d'usage type : votre CRM synchronise ses comptes-rendus d'appel vers Captiv. La note est attribuée au créateur de la clé et marquée source « api » pour l'audit. Répond 201.
Corps (JSON)
content | chaîne 1-2000 | Contenu de la note (texte brut). |
curl -X POST https://captiv-ai.com/api/v1/leads/LEAD_ID/notes \
-H "Authorization: Bearer cptv_live_VOTRE_CLE" \
-H "Content-Type: application/json" \
-d '{"content": "Appel du 6/08 : intéressée, rappel jeudi 10h"}'{
"data": { "id": "…", "object": "lead_note", "lead_id": "…",
"content": "Appel du 6/08 : intéressée, rappel jeudi 10h",
"source": "api", "created_at": "…", "updated_at": null },
"meta": { "request_id": "req_…" }
}Lister les interactions
Chaque interaction est un événement (lead × post) : commentaire, réaction, livraison de ressource, ouverture, formulaire… C'est la matière première pour reconstruire une timeline — et c'est ICI que se mesure l'engagement : chaque interaction porte son propre engagement_score et le texte du commentaire.
Paramètres de requête
lead_id | uuid | Ne retourner que les interactions d'un lead. |
post_id | uuid | Ne retourner que les interactions d'un post. |
min_engagement | entier 0-100 | engagement_score minimal. LE filtre d'engagement de l'API. |
has_comment | booléen | Ne garder que les interactions où le lead a écrit un commentaire. |
limit | entier 1-100 | Taille de page. Défaut : 50. |
cursor | chaîne opaque | Curseur de la page suivante, tel que renvoyé dans meta.pagination.next_cursor. Ne pas le construire soi-même. |
order | created_desc | created_asc | Ordre chronologique. Défaut : created_desc (plus récents d'abord). |
since | datetime ISO 8601 | Ne retourner que les objets créés après cette date. |
until | datetime ISO 8601 | Ne retourner que les objets créés avant cette date. |
curl "https://captiv-ai.com/api/v1/lead-interactions?min_engagement=40&has_comment=true" \
-H "Authorization: Bearer cptv_live_VOTRE_CLE"{
"data": [
{ "id": "…", "object": "lead_interaction", "lead_id": "…", "post_id": "…",
"created_at": "…", "kind": "comment", "comment_text": "Intéressé !",
"keyword_matched": true, "engagement_score": 74, "pipeline_status": "…",
"resource": { "sent": true, "sent_at": "…", "opened": true, "opened_at": "…",
"clicked_at": "…", "click_count": 2 },
"connection": { "requested_at": "…", "accepted_at": "…" },
"form_submitted": false, "email_shared": true }
],
"meta": { "request_id": "req_…", "pagination": { "next_cursor": null, "has_more": false } }
}Lister les posts
Liste paginée des posts LinkedIn surveillés par Captiv, avec leurs compteurs de capture.
Paramètres de requête
status | draft | published | monitoring | completed | scheduled | publishing | failed | Filtrer par statut. |
limit | entier 1-100 | Taille de page. Défaut : 50. |
cursor | chaîne opaque | Curseur de la page suivante, tel que renvoyé dans meta.pagination.next_cursor. Ne pas le construire soi-même. |
order | created_desc | created_asc | Ordre chronologique. Défaut : created_desc (plus récents d'abord). |
since | datetime ISO 8601 | Ne retourner que les objets créés après cette date. |
until | datetime ISO 8601 | Ne retourner que les objets créés avant cette date. |
curl "https://captiv-ai.com/api/v1/posts?status=monitoring" \
-H "Authorization: Bearer cptv_live_VOTRE_CLE"{
"data": [
{ "id": "…", "object": "post", "subject": "…", "status": "monitoring",
"linkedin_url": "https://www.linkedin.com/posts/…", "published_at": "…",
"is_lead_magnet": true,
"monitoring": { "active": true, "started_at": "…", "expires_at": "…" },
"metrics": { "leads_count": 132, "captured_leads_count": 118, "comment_count": 214 },
"resource_id": "…", "created_at": "…", "updated_at": "…" }
],
"meta": { "request_id": "req_…", "pagination": { "next_cursor": null, "has_more": false } }
}Détail d'un post
Le post + ses statistiques LinkedIn natives (impressions, réactions, reposts…) quand elles ont été relevées.
curl https://captiv-ai.com/api/v1/posts/POST_ID \
-H "Authorization: Bearer cptv_live_VOTRE_CLE"{
"data": {
"id": "…", "object": "post", "…": "…",
"linkedin_stats": { "impressions": 28400, "reactions": 312, "reposts": 14,
"followers_gained": 57, "profile_viewers": 190,
"fetched_at": "2026-08-06T07:00:00Z" }
},
"meta": { "request_id": "req_…" }
}Transmettre un visuel
Attachez une image à un post Studio — en base64 (le cas « j'ai fait mon visuel dans Claude ») ou par URL https, re-téléchargée et hébergée chez Captiv. Le format réel est sniffé (le MIME déclaré n'est jamais cru), l'image est ré-encodée. Images OU vidéo, jamais les deux (règle LinkedIn) ; 9 visuels max ; un post publié ne change plus.
Corps (JSON)
image_base64 | chaîne base64 ≤ 8 Mo | L'image encodée (exclusif avec url). |
url | URL https | Image publique à re-héberger (exclusif avec image_base64). |
mode | append | replace_cover | Ajouter au carrousel (défaut) ou remplacer la couverture. |
curl -X POST https://captiv-ai.com/api/v1/posts/POST_ID/visual \
-H "Authorization: Bearer cptv_live_VOTRE_CLE" \
-H "Content-Type: application/json" \
-d '{"url": "https://exemple.com/mon-visuel.png"}'{
"data": { "object": "post_visual", "post_id": "…",
"visual_url": "https://…supabase.co/…/artefacts/…/api-1754….jpg",
"cover_url": "…", "visual_urls": ["…"], "mode": "append" },
"meta": { "request_id": "req_…" }
}Lister les ressources
Les lead magnets du workspace. public_url n'est renseignée que si la page publique peut réellement servir la ressource — une URL présente est toujours une page vivante, vous pouvez la relayer sans vérification. Le contenu complet des blocs n'est pas exposé par l'API.
Paramètres de requête
post_id | uuid | Ne retourner que les ressources attachées à un post. |
is_published | true | false | Filtrer sur l'état de publication. |
limit | entier 1-100 | Taille de page. Défaut : 50. |
cursor | chaîne opaque | Curseur de la page suivante, tel que renvoyé dans meta.pagination.next_cursor. Ne pas le construire soi-même. |
order | created_desc | created_asc | Ordre chronologique. Défaut : created_desc (plus récents d'abord). |
since | datetime ISO 8601 | Ne retourner que les objets créés après cette date. |
until | datetime ISO 8601 | Ne retourner que les objets créés avant cette date. |
curl "https://captiv-ai.com/api/v1/resources?is_published=true" \
-H "Authorization: Bearer cptv_live_VOTRE_CLE"{
"data": [
{ "id": "…", "object": "resource", "title": "Le guide complet …",
"subtitle": "…", "slug": "guide-complet", "type": "guide",
"language": "fr", "is_published": true, "published_at": "…",
"gated": true, "view_count": 1240, "format_version": 2,
"public_url": "https://captiv-ai.com/r/guide-complet",
"post_id": "…", "created_at": "…", "updated_at": "…" }
],
"meta": { "request_id": "req_…", "pagination": { "next_cursor": null, "has_more": false } }
}Détail d'une ressource
La ressource + blocks_count et updated_at — l'echo du verrou optimiste, à renvoyer tel quel en expected_updated_at sur toute écriture de blocs.
curl https://captiv-ai.com/api/v1/resources/RESOURCE_ID \
-H "Authorization: Bearer cptv_live_VOTRE_CLE"{ "data": { "id": "…", "object": "resource", "…": "…", "blocks_count": 27 },
"meta": { "request_id": "req_…" } }Lire les blocs
Le tableau complet des blocs (id, type, content, metadata) + updated_at. C'est la lecture qui précède toute édition : les ids servent à cibler, updated_at sert de verrou.
curl https://captiv-ai.com/api/v1/resources/RESOURCE_ID/blocks \
-H "Authorization: Bearer cptv_live_VOTRE_CLE"{
"data": {
"resource_id": "…", "format_version": 2,
"updated_at": "2026-08-07T10:00:00Z",
"blocks": [
{ "id": "b3f2a1c9", "type": "heading", "content": "Le guide", "metadata": null },
{ "id": "b7e4d2b0", "type": "paragraph", "content": "…", "metadata": null }
]
},
"meta": { "request_id": "req_…" }
}Éditer un bloc
Édition DIRECTE du contenu par votre client — aucune IA côté Captiv. Le type est immuable ; les clés metadata absentes sont préservées. La sanitisation éditoriale s'applique (transformations listées dans sanitize_flags). 409 si la ressource a bougé depuis votre lecture.
Corps (JSON)
content | chaîne ≤ 50000 | Nouveau contenu (optionnel). |
metadata | objet | Clés à fusionner en surface (optionnel). |
expected_updated_at | chaîne | L'updated_at lu — fortement recommandé (verrou optimiste). |
curl -X PATCH https://captiv-ai.com/api/v1/resources/RESOURCE_ID/blocks/b7e4d2b0 \
-H "Authorization: Bearer cptv_live_VOTRE_CLE" \
-H "Content-Type: application/json" \
-d '{"content": "Le paragraphe corrigé.", "expected_updated_at": "2026-08-07T10:00:00Z"}'{
"data": { "block": { "id": "b7e4d2b0", "type": "paragraph", "content": "Le paragraphe corrigé.", "metadata": null },
"sanitize_flags": [], "updated_at": "2026-08-07T10:02:11Z" },
"meta": { "request_id": "req_…" }
}Insérer un bloc
Type dans l'allowlist partagée avec le générateur ; content JSON validé pour les types qui en stockent. position optionnelle (défaut : fin). Répond 201 avec l'id généré.
Corps (JSON)
type | chaîne | Type de bloc (heading, paragraph, callout…). |
content | chaîne ≤ 50000 | Contenu (défaut vide). |
position | entier ≥ 0 | Index d'insertion (optionnel). |
expected_updated_at | chaîne | Verrou optimiste (recommandé). |
curl -X POST https://captiv-ai.com/api/v1/resources/RESOURCE_ID/blocks \
-H "Authorization: Bearer cptv_live_VOTRE_CLE" \
-H "Content-Type: application/json" \
-d '{"type": "callout", "content": "À retenir : …", "position": 3}'{ "data": { "block": { "id": "b9a1f4e2", "…": "…" }, "position": 3,
"sanitize_flags": [], "updated_at": "…" }, "meta": { "request_id": "req_…" } }Supprimer un bloc
expected_updated_at passe en query string. 409 si la ressource a bougé.
curl -X DELETE "https://captiv-ai.com/api/v1/resources/RESOURCE_ID/blocks/b9a1f4e2?expected_updated_at=2026-08-07T10:02:11Z" \
-H "Authorization: Bearer cptv_live_VOTRE_CLE"{ "data": { "deleted": true, "block_id": "b9a1f4e2", "blocks_count": 26, "updated_at": "…" },
"meta": { "request_id": "req_…" } }Réordonner les blocs
block_ids doit être une permutation STRICTE des ids existants — ni manquant, ni inconnu, ni doublon : réordonner n'est jamais l'occasion de perdre un bloc.
Corps (JSON)
block_ids | tableau de chaînes | Tous les ids, dans le nouvel ordre. |
expected_updated_at | chaîne | Verrou optimiste (recommandé). |
curl -X PUT https://captiv-ai.com/api/v1/resources/RESOURCE_ID/blocks/order \
-H "Authorization: Bearer cptv_live_VOTRE_CLE" \
-H "Content-Type: application/json" \
-d '{"block_ids": ["b3f2a1c9", "b9a1f4e2", "b7e4d2b0"]}'{ "data": { "reordered": true, "blocks_count": 3, "updated_at": "…" }, "meta": { "request_id": "req_…" } }Auto-vérification avant publication
Le même lint que le produit : chiffres sans source, blocs vides, placeholders… Le lint constate, il ne bloque jamais l'édition — c'est votre relecture automatique avant de publier.
curl https://captiv-ai.com/api/v1/resources/RESOURCE_ID/lint \
-H "Authorization: Bearer cptv_live_VOTRE_CLE"{ "data": { "resource_id": "…", "blocks_count": 27, "clean": false,
"findings": [{ "…": "…" }] }, "meta": { "request_id": "req_…" } }Lien de préversion (fidélité 100 %)
Génère un lien signé (45 min) vers la VRAIE page publique de la ressource — même renderer, même charte que ce que verra le lead, brouillons compris. Aucune vue comptée, jamais indexé. Ce n'est PAS un lien à envoyer à un prospect : il expire.
curl -X POST https://captiv-ai.com/api/v1/resources/RESOURCE_ID/preview \
-H "Authorization: Bearer cptv_live_VOTRE_CLE"{
"data": { "object": "resource_preview", "resource_id": "…",
"preview_url": "https://captiv-ai.com/r/guide-complet?preview=eyJ…",
"expires_at": "2026-08-07T11:15:00Z" },
"meta": { "request_id": "req_…" }
}Créer une ressource (202 + suivi)
Le même moteur que l'écran : voix du créateur, charte, mouvement structurel. La ressource naît TOUJOURS en brouillon — la publier reste un geste explicite dans Captiv, jamais un effet de bord d'un agent — et n'est jamais attachée à un post à la naissance. Réponse 202 immédiate, génération en fond (25-96 s mesurés) à suivre via /v1/resources/{id}/status. Envoyez un Idempotency-Key : rejouer la même clé rend la même réponse, jamais deux ressources. Lot actuel : matière texte (titre, brief, liens).
Corps (JSON)
title | chaîne 2-200 | Le sujet de la ressource (le titre final est dérivé du contenu généré). |
subtitle | chaîne ≤ 800 | Sous-titre — dérivé automatiquement si absent. |
extra_details | chaîne ≤ 6000 | Le brief : chiffres, scènes, verbatims — la matière première de la qualité. |
language | fr | en | Défaut : fr. |
resource_type | chaîne ≤ 40 | Défaut : guide. |
external_links | tableau ≤ 5 | {url, title} — sources à citer dans la ressource. |
curl -X POST https://captiv-ai.com/api/v1/resources \
-H "Authorization: Bearer cptv_live_VOTRE_CLE" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{
"title": "Le guide de préqualification des leads",
"extra_details": "40 relances/semaine automatisées, 3 h gagnées, verbatims clients"
}'{
"data": {
"object": "resource_generation", "status": "running",
"resource": { "id": "…", "object": "resource", "title": "…",
"is_published": false, "…": "…" },
"status_url": "/api/v1/resources/…/status",
"typical_duration_seconds": [25, 96]
},
"meta": { "request_id": "req_…" }
}Suivre une génération de ressource
La génération d'une ressource tourne en fond (25-96 s mesurés). Cette route rend les faits du lifecycle — state (idle, running, completed, failed), horodatages, blocs réellement écrits — sans marteler la ressource entière. Fonctionne aussi pour une génération lancée depuis l'écran Studio.
curl https://captiv-ai.com/api/v1/resources/RESOURCE_ID/status \
-H "Authorization: Bearer cptv_live_VOTRE_CLE"{
"data": { "object": "resource_generation_status", "resource_id": "…",
"state": "completed", "started_at": "…", "finished_at": "…",
"blocks_count": 37, "is_published": false, "updated_at": "…" },
"meta": { "request_id": "req_…" }
}Questions de cadrage personnalisées
Les 3 questions d'interview écrites POUR votre idée (mots exacts repris, matière visée : chiffre, scène, verbatim). Toujours 3 questions : si le sur-mesure échoue, le serveur replie sur la banque déterministe — la provenance est dite dans source.
Corps (JSON)
idea | chaîne 20-1200 | L'idée brute du post. |
is_lead_magnet | booléen | L'idée vise-t-elle un lead magnet ? Défaut : false. |
curl -X POST https://captiv-ai.com/api/v1/studio/questions \
-H "Authorization: Bearer cptv_live_VOTRE_CLE" \
-H "Content-Type: application/json" \
-d '{"idea": "j'\''ai remplacé mes relances client manuelles par un script Make, gain de temps énorme"}'{
"data": {
"object": "post_questions", "source": "sur_mesure",
"questions": [
{ "id": "sur-mesure-1",
"texte": "\"Gain de temps énorme\" : tu l'as mesuré sur combien de relances par semaine ?",
"justification": "Le chiffre vérifiable qui ancre le post" },
{ "id": "sur-mesure-2", "texte": "…", "justification": "…" },
{ "id": "sur-mesure-3", "texte": "…", "justification": "…" }
]
},
"meta": { "request_id": "req_…" }
}Générer un post LinkedIn complet
LE MÊME moteur que l'écran Studio : voix apprise du propriétaire du workspace, cadrage, correction anti-tics, mot à commenter extrait pour un lead magnet. Le post créé est un brouillon Studio normal, visible dans « Mes posts ». Envoyez un en-tête Idempotency-Key (UUID par tentative) : rejouer la même clé rend la même réponse, jamais deux posts. Idée trop mince ? 200 avec status needs_more_input et un feedback actionnable — enrichissez et rappelez. Chaque appel compte dans le pool IA quotidien du workspace et le quota posts/jour du plan.
Corps (JSON)
idea | chaîne 10-4000 | L'idée brute — plus elle a de vécu, meilleur est le post. |
language | fr | en | Langue du post. Défaut : fr. |
resource_id | uuid | Ressource PUBLIÉE du workspace à attacher (flux lead magnet). |
is_lead_magnet | booléen | Intention lead magnet sans ressource encore créée. |
cadrage | tableau ≤ 3 | Paires {question, reponse} issues de /v1/studio/questions. |
style | objet | {forme, ton} pour imposer un style au lieu de celui du profil. |
curl -X POST https://captiv-ai.com/api/v1/studio/posts \
-H "Authorization: Bearer cptv_live_VOTRE_CLE" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{
"idea": "j'\''ai remplacé mes relances client manuelles par un script Make",
"cadrage": [
{ "question": "Tu l'\''as mesuré sur combien de relances ?",
"reponse": "Environ 40 par semaine, je gagnais 3 h" }
]
}'{
"data": {
"object": "post_generation", "status": "generated",
"post": { "id": "…", "object": "post", "subject": "…",
"text": "Le post LinkedIn complet, dans votre voix…",
"trigger_keyword": null, "status": "draft", "…": "…" },
"feedback": null,
"usage": { "input_tokens": 1240, "output_tokens": 812,
"web_searches": 0, "cost_usd": 0.04 }
},
"meta": { "request_id": "req_…" }
}KPI agrégés du workspace
Les mêmes compteurs que le dashboard Captiv (même moteur de calcul), agrégés sur la période demandée : capture, qualification, outreach et ouvertures de ressources. Si un compteur n'a pas pu être lu, il vaut null et partial passe à true — jamais 0 : un zéro se lit « il ne s'est rien passé », et c'est une phrase sur laquelle on décide.
Paramètres de requête
period | 7d | 30d | 90d | Fenêtre d'agrégation. Défaut : 30d. |
curl "https://captiv-ai.com/api/v1/analytics/summary?period=30d" \
-H "Authorization: Bearer cptv_live_VOTRE_CLE"{
"data": {
"object": "analytics_summary", "period": "30d",
"from": "2026-07-07T…", "to": "2026-08-06T…",
"totals": {
"leads_captured": 412, "leads_qualified": 96, "posts_published": 9,
"invitations_sent": 240, "invitations_attempted": 251,
"messages_sent": 187, "resources_delivered": 203,
"resource_opens": 164, "unique_resource_openers": 149, "relation_checks": 96
},
"rates": { "invitation_success_rate": 96, "resource_open_rate": 73 },
"partial": false
},
"meta": { "request_id": "req_…" }
}De quoi reproduire fidèlement la page
Les blocs disent CE QUI est écrit ; ceci dit à quoi la page RESSEMBLE — thème résolu (variables CSS à poser telles quelles), carte de l'auteur, identité de la ressource. À appeler avant de fabriquer un aperçu, sans quoi il sera structurellement juste et visuellement faux. theme.frozen = true signifie que la charte a été figée à la publication : c'est cette apparence qu'ont reçue les leads, pas la charte actuelle du créateur. Le brief privé du créateur ne sort jamais, et les variables CSS sont filtrées (préfixe --resource-, longueur bornée, pas de caractère qui referme une déclaration).
curl "https://captiv-ai.com/api/v1/resources/RESOURCE_ID/render-context" \
-H "Authorization: Bearer cptv_live_VOTRE_CLE"{
"data": {
"object": "resource_render_context", "resource_id": "…",
"updated_at": "2026-08-10T09:00:00Z", "format_version": 2,
"resource": { "title": "…", "subtitle": "…", "language": "fr", "is_published": true },
"theme": {
"css_variables": { "--resource-accent": "#0A66C2", "--resource-bg": "#FAFAF8" },
"frozen": true
},
"author": { "name": "…", "headline": "…", "photo_url": "…", "show_intro": true }
},
"meta": { "request_id": "req_…" }
}Retirer tous les visuels d'un post
Vide l'attache visuelle (couverture comprise) pour repartir proprement. Aucun coût IA, le texte du post n'est pas touché. Le cas d'usage principal est le carrousel : neuf images à 8 Mo ne tiennent pas dans une requête, l'envoi est donc séquentiel — et un envoi qui échoue en cours de route laissait jusqu'ici un carrousel amputé sans moyen de le reprendre. Refusé sur un post publié ou suivi depuis LinkedIn.
curl -X DELETE "https://captiv-ai.com/api/v1/posts/POST_ID/visual" \
-H "Authorization: Bearer cptv_live_VOTRE_CLE"{
"data": {
"object": "post_visual", "post_id": "…",
"removed": 4, "visual_urls": [], "cover_url": null
},
"meta": { "request_id": "req_…" }
}Enregistrer un texte retravaillé
L'équivalent de taper dans l'éditeur du Studio : le texte fourni est rangé tel quel. N'APPELLE AUCUN MODÈLE et ne consomme AUCUN crédit IA — la génération (POST /v1/studio/posts) coûte, l'édition non. Fournissez expected_updated_at (lu au GET) : sans lui, une modification faite au même moment dans Captiv serait écrasée en silence. Refusé sur un post déjà publié, en cours de publication, ou suivi depuis LinkedIn plutôt qu'écrit dans le Studio.
curl -X PATCH "https://captiv-ai.com/api/v1/posts/POST_ID" \
-H "Authorization: Bearer cptv_live_VOTRE_CLE" \
-H "Content-Type: application/json" \
-d '{"text":"Le post retravaille, complet.","expected_updated_at":"2026-08-10T09:00:00Z"}'{
"data": {
"id": "…", "object": "post",
"subject": "…", "status": "draft",
"text": "Le post retravaille, complet.",
"updated_at": "2026-08-10T09:04:12Z",
"is_studio_authored": true,
"metrics": { "leads_count": 0, "captured_leads_count": 0, "comment_count": 0 }
},
"meta": { "request_id": "req_…" }
}Ce que l'agent a prévu et ce qu'il a fait
Les invitations, messages, commentaires et vérifications planifiés par l'agent, avec leur statut et la raison d'un éventuel saut. Filtrez sur la date PRÉVUE (scheduled_since / scheduled_until) pour répondre à « qu'est-ce qui part aujourd'hui ». Lecture seule : aucun endpoint ne permet de créer, reprogrammer, déclencher ni annuler une action — les garde-fous anti-ban restent chez l'agent. Le texte des messages n'est pas exposé.
Paramètres de requête
lead_id | uuid | Les actions visant ce lead. |
post_id | uuid | Les actions liées à ce post. |
action_type | invitation | message | comment | check | followup_notif | Le type d'action. |
status | texte | pending, done, skipped… |
scheduled_since | ISO 8601 | Date PRÉVUE ≥ — c'est ce filtre qui répond à « aujourd'hui ». |
scheduled_until | ISO 8601 | Date prévue ≤. |
limit | entier 1-100 | Taille de page. Défaut : 50. |
cursor | chaîne opaque | Curseur de la page suivante, tel que renvoyé dans meta.pagination.next_cursor. Ne pas le construire soi-même. |
order | created_desc | created_asc | Ordre chronologique. Défaut : created_desc (plus récents d'abord). |
since | datetime ISO 8601 | Ne retourner que les objets créés après cette date. |
until | datetime ISO 8601 | Ne retourner que les objets créés avant cette date. |
curl "https://captiv-ai.com/api/v1/agent/actions?status=pending&action_type=invitation" \
-H "Authorization: Bearer cptv_live_VOTRE_CLE"{
"data": [
{
"id": "…", "object": "agent_action",
"action_type": "invitation", "status": "pending",
"scheduled_at": "2026-08-10T09:30:00Z", "executed_at": null,
"lead_id": "…", "post_id": "…", "priority_score": 87,
"reason": "Score eleve, commentaire recent", "skip_reason": null,
"error_code": null, "created_at": "2026-08-09T18:00:00Z"
}
],
"meta": { "request_id": "req_…", "pagination": { "has_more": false, "next_cursor": null } }
}Santé du compte et plafonds anti-ban
L'état du compte LinkedIn qui agit pour ce workspace : connecté ou non, score de santé, jour de chauffe, et surtout les plafonds quotidiens et hebdomadaires. C'est la réponse à « est-ce que je peux encore inviter aujourd'hui ». Aucun identifiant de connexion ni nom de prestataire n'est exposé.
curl "https://captiv-ai.com/api/v1/agent/status" \
-H "Authorization: Bearer cptv_live_VOTRE_CLE"{
"data": {
"object": "agent_status",
"account": {
"object": "agent_account", "connected": true,
"name": "…", "status": "OK", "health_score": 92,
"connected_at": "2026-05-02T…",
"warmup": { "day": 41, "started_at": "2026-05-02T…" },
"caps": {
"daily_connect": 18, "weekly_connect": 100, "monthly_connect_soft": 300,
"daily_message": 60, "daily_comment": 40
}
},
"queue": { "pending": 5 },
"readonly": true
},
"meta": { "request_id": "req_…" }
}05 — Erreurs
RFC 7807, registre fermé
Toute erreur sort en application/problem+json avec un type stable, un detail lisible et le request_id :
{
"type": "https://captiv-ai.com/docs/api/errors#insufficient_scope",
"title": "Insufficient scope",
"status": 403,
"detail": "This endpoint requires scope \"read:leads\". This key has: read:posts.",
"instance": "/api/v1/leads",
"request_id": "req_7ad84bf44a49416391264075"
}Les erreurs de validation (400) ajoutent un tableau errors[] avec path et message par champ. Registre complet :
| Statut | Code | Titre |
|---|---|---|
| 401 | missing_api_key | Missing API key |
| 401 | invalid_api_key | Invalid API key |
| 401 | expired_api_key | Expired API key |
| 402 | plan_required | Plan upgrade required |
| 403 | insufficient_scope | Insufficient scope |
| 404 | not_found | Resource not found |
| 404 | workspace_gone | Workspace no longer exists |
| 400 | validation_failed | Validation failed |
| 429 | rate_limit_exceeded | Rate limit exceeded |
| 429 | too_many_auth_failures | Too many authentication failures |
| 503 | api_disabled | API temporarily disabled |
| 409 | conflict | Conflict |
| 429 | daily_budget_exceeded | Daily AI budget exceeded |
| 429 | generation_quota_exceeded | Daily generation quota exceeded |
| 429 | concurrency_limit_exceeded | Too many generations in flight |
| 409 | idempotency_key_in_flight | Idempotency key in flight |
| 422 | idempotency_key_reuse | Idempotency key reused with a different payload |
| 500 | internal_error | Internal server error |
06 — Limites
Rate limits, idempotence & versioning
- Rate limits — deux niveaux. Global, par clé : 1 000 req/h (Pro), 10 000 req/h (Agence), avec
X-RateLimit-Limit,X-RateLimit-RemainingetX-RateLimit-Reset(epoch secondes). Par classe, et cette fois par workspace (créer dix clés ne multiplie donc rien) : écritures 300/h (1 500 Agence), téléversements de visuels 60/h (200), générations par type — posts 10/h (30), ressources 3/h (8). Les en-têtesX-RateLimit-Class-*reflètent le compteur qui mordra en premier sur l'endpoint appelé ; un 429 nomme la classe dansrate_limit.classet porteRetry-After. - Réponses compactes —
?compact=truesur les listes (leads, posts, ressources, interactions) renvoie la projection réduite : uniquement les champs qui servent à décider. Conçu pour les agents, qui paient chaque champ en jetons ; le détail complet reste accessible par leGETpar id. Le connecteur MCP l'active par défaut. - Texte écrit par des tiers — noms, titres et commentaires de leads sont du contenu arbitraire. En sortie, Captiv retire ce qui est invisible (largeurs nulles, surcharges bidirectionnelles, bloc de balises, caractères de contrôle) et borne la longueur. Emojis, accents et alphabets non latins passent intacts. Ce qui est écrit en clair reste en clair : si vous branchez un agent, traitez ces champs comme des données, jamais comme des instructions — et donnez-lui une clé lecture seule distincte de vos clés de génération.
- Versioning — la v1 est stable : les changements cassants n'arriveront que dans une future
/v2, la v1 restant maintenue au moins 12 mois après son remplacement. Des champs ou endpoints peuvent s'ajouter à la v1 sans préavis — codez vos parsers en conséquence (ignorez les champs inconnus). - Idempotence — le header
Idempotency-Keyest honoré sur les endpoints de génération : un retry réseau rejoue la réponse d'origine à l'identique (headerIdempotency-Replayed: true) au lieu de payer deux fois. Une clé par requête distincte ; réutiliser une clé avec un autre payload répond 422. - Budget IA — les générations consomment le budget quotidien du workspace (partagé avec l'application). Un refus répond 429
daily_budget_exceededavec le détail chiffré (budget.cap_usd,budget.spent_usd,budget.resets_at— minuit UTC). - Ce que l'API n'expose pas — le déclenchement direct d'actions LinkedIn (invitations, DM). Ces actions restent pilotées par l'agent Captiv et ses garde-fous anti-ban ; l'API les expose en lecture (interactions, analytics).
Une question, un besoin d'endpoint ? Écrivez-nous : support@captiv-ai.com — mentionnez votre request_id pour toute erreur.
07 — Claude
Brancher Claude sur Captiv (MCP)
Captiv expose un serveur MCP (Model Context Protocol, transport Streamable HTTP) sur https://captiv-ai.com/api/mcp. Connectez-le à Claude et parlez à votre workspace en langage naturel : « montre-moi mes leads les plus chauds », « écris-moi un post sur… », « édite le bloc 3 de ma ressource et montre-moi l'aperçu ».
L'authentification est la même clé API que le reste de cette page, envoyée en header Authorization: Bearer. Chaque outil MCP passe par l'API v1 publique : scopes, quotas, budget IA, idempotence et audit s'appliquent à l'identique — un appel MCP est un appel API.
Claude Code (CLI)
claude mcp add captiv --transport http https://captiv-ai.com/api/mcp \
--header "Authorization: Bearer cptv_live_VOTRE_CLE"Claude.ai (connecteur personnalisé)
Paramètres → Connecteurs → « Ajouter un connecteur personnalisé » → URL https://captiv-ai.com/api/mcp. Aucune clé à coller : Claude vous renvoie sur Captiv, vous vous connectez, vous choisissez ce que le connecteur a le droit de faire, et c'est tout. La connexion se fait en OAuth 2.1(PKCE S256).
Par défaut, un connecteur n'obtient que la lecture — leads, posts, ressources, analytics. Les droits d'écriture et de génération se cochent un par un sur l'écran d'autorisation. Vous coupez l'accès quand vous voulez depuis Réglages → API & intégrations ; la coupure est immédiate, elle vaut aussi pour les sessions déjà ouvertes.
API Anthropic (MCP connector)
{
"mcp_servers": [{
"type": "url",
"url": "https://captiv-ai.com/api/mcp",
"name": "captiv",
"authorization_token": "cptv_live_VOTRE_CLE"
}]
}- Outils exposés — leads (liste, détail, notes, interactions), posts (liste, détail), génération Studio (questions de cadrage, post complet, visuel), ressources (blocs, lint, aperçu signé), follow-ups (mise en file, liste, annulation), analytics. Commencez par
whoami. - Follow-ups —
queue_follow_upn'envoie rien. Il inscrit un lead dans la file de relance ; c'est l'agent Captiv qui écrira plus tard, étalé sur plusieurs jours, sous ses quotas quotidiens, ses horaires ouvrés et ses garde-fous anti-ban. Ajoutez-en quinze d'un coup si vous voulez : ils seront dispersés. Un lead déjà en file est refusé — personne ne reçoit deux fois la même relance. - Sécurité — les textes provenant de leads sont balisés comme données non fiables dans les sorties d'outils (anti-injection). Aucun outil n'écrit sur LinkedIn : pas d'invitation, pas de message envoyé, pas de commentaire. La seule mécanique qui débouche un jour sur un message est la file de follow-ups ci-dessus, et elle reste entre les mains de l'agent et de ses caps.
- Scopes — donnez à la clé du connecteur uniquement les scopes dont vous vous servez ; un outil sans scope répond une erreur claire avec le scope manquant.
Prêt à construire
Construisez sur Captiv
Une clé, trois minutes, et vos leads arrivent dans votre stack.