API et webhooks — connecter Craft à votre CRM ou à votre site
Comment piloter Craft avec des requêtes signées par une clé et recevoir sur votre propre serveur des événements sur les nouveaux contacts, les clics sur les boutons, les paiements et les posts.
Vous pouvez connecter Craft à votre CRM, au site d’un client ou à n’importe quel service qui vous appartient. Tout ce que sait faire le connecteur MCP est disponible sous forme de simple requête HTTPS avec une clé : tunnels, contacts, diffusions, posts, carrousels, images. Les webhooks fonctionnent dans l’autre sens : Craft envoie un événement à votre serveur quand un nouveau contact apparaît, que quelqu’un clique sur un bouton, atteint l’objectif d’un tunnel, paie, ou qu’un post est publié.
Comment ça marche#
- Dans Craft, vous créez une clé et choisissez ce qu’elle peut faire : lecture seule, ou travail avec les tunnels, contacts, diffusions, posts, etc.
- Votre serveur envoie une requête à
https://craftopen.space/api/v1/tools/<method>avec la clé dans un en-tête. Les paramètres de la méthode vont dans le corps JSON de la requête. - Craft exécute la méthode dans votre compte — exactement comme si vous le faisiez sur le site ou le demandiez à votre IA via le connecteur MCP, avec les mêmes vérifications et limites.
- Pour les événements, vous ajoutez un webhook — l’adresse de votre serveur. Craft y envoie une requête signée et réessaie si votre serveur ne répond pas.
Ce qu’il vous faut#
- N’importe quel forfait : clés et webhooks peuvent être créés avec tous les forfaits, y compris le gratuit.
- Un serveur ou un service capable d’envoyer et de recevoir des requêtes HTTPS : votre propre code, Make, n8n, Zapier, ou un CRM avec des webhooks entrants.
Étape 1. Créer une clé#
Menu du profil → API et webhooks (API & webhooks) (ou Réglages → API et webhooks) → Nouvelle clé (New key).
- Donnez à la clé un nom que vous reconnaîtrez plus tard : « HubSpot », « Site du client ».
- Choisissez ce que la clé peut faire. Une nouvelle clé ne peut que lire par défaut. Tout le reste s’active avec des cases : tunnels, contacts, diffusions, posts, contenu, Fabrique de contenu, comptes. « Tout » ouvre toutes les capacités, y compris celles ajoutées plus tard.
- Choisissez comment la clé publie les posts et les diffusions : - Brouillons uniquement — tout est enregistré en brouillon et vous l’envoyez vous-même dans Craft ; - Programmé — pas avant 10 minutes, pour avoir le temps d’annuler ; - Instantané — publie et envoie au moment de la requête.
- Définissez la limite quotidienne de dépense en images et combien de diffusions par jour la clé peut envoyer depuis un bot.
- Cliquez sur Créer la clé et copiez-la tout de suite.
🔴 La clé n’est affichée qu’une seule fois. Craft n’en conserve que l’empreinte et ne peut pas la récupérer. Perdue ? Révoquez-la et créez-en une nouvelle. Ne mettez jamais la clé dans le code d’une page web ou d’une application mobile — chaque visiteur la verrait. La clé n’a sa place que sur un serveur.
Vous pouvez modifier les permissions et réglages d’une clé à tout moment avec « Réglages » — les changements prennent effet en moins d’une minute. « Révoquer » désactive la clé immédiatement.
Étape 2. Votre première requête#
curl -X POST https://craftopen.space/api/v1/tools/list_funnels \
-H "Authorization: Bearer craft_your_key" \
-H "Content-Type: application/json" \
-d '{}'
Une réponse réussie ressemble toujours à ceci — les données elles-mêmes sont dans data :
{"ok": true, "data": {"funnels": [ ... ]}}
Si quelque chose ne va pas, vous recevez "ok": false et une raison claire :
{"ok": false, "error": {"code": "funnel_not_found", "message": "Воронка не найдена."}}
⚠️ Les messages d’erreur sont pour l’instant rédigés en russe. Construisez votre logique sur error.code — il
est stable et indépendant de la langue.
Méthodes disponibles#
Toutes les méthodes et leurs paramètres avec descriptions :
- dans Craft :
GET https://craftopen.space/api/v1/toolsavec votre clé — la liste indique quelle permission chaque méthode exige et si cette clé peut l’appeler ; - une description OpenAPI : craftopen.space/api/v1/openapi.json — Postman, Insomnia et les générateurs de clients la comprennent.
Les méthodes sont les mêmes que celles du connecteur MCP. Les plus courantes :
| Tâche | Méthode | Permission de la clé |
|---|---|---|
| Lister les tunnels et leurs statistiques | list_funnels, get_funnel_stats |
lecture |
| Trouver les abonnés d’un bot | find_contacts |
lecture |
| Fiche d’un abonné | get_contact |
lecture |
| Ajouter ou retirer un tag | tag_contacts |
contacts |
| Lancer un tunnel pour une personne | run_funnel_for_contact |
contacts, mode « Instantané » |
| Post programmé | list_publishing_accounts → schedule_post |
posts |
| Diffusion Telegram | save_broadcast_draft → send_broadcast_test → send_broadcast |
diffusions |
| Carrousel à partir de votre texte | create_carousel, render_carousel |
contenu |
| Image contre des credits | generate_image |
contenu |
GET https://craftopen.space/api/v1/me indique quelle clé vous utilisez, ses permissions et combien
de requêtes il vous reste aujourd’hui.
Réessayer sans doublons#
Si une requête a été interrompue et que vous ne savez pas si elle est passée, renvoyez-la avec le
même en-tête Idempotency-Key. Le post ne partira pas deux fois et une image ne sera pas facturée deux fois.
curl -X POST https://craftopen.space/api/v1/tools/schedule_post \
-H "Authorization: Bearer craft_your_key" \
-H "Idempotency-Key: post-2026-09-27-lime-1" \
-H "Content-Type: application/json" \
-d '{"account_ids": ["..."], "confirm_usernames": ["@lime_agency"],
"carousel_id": "...", "caption": "Post text",
"scheduled_at": "2026-09-27T19:00:00+03:00"}'
⚠️ Les confirmations font partie de la requête. Là où le site demanderait « êtes-vous sûr »,
l’API attend une confirmation dans les paramètres : les @noms des comptes pour un post
(confirm_usernames), le nombre exact de destinataires pour une diffusion (confirm_recipients),
le nom d’un tunnel actif que vous modifiez, le prix d’un bloc de paiement. Si la
confirmation ne correspond pas à ce que voit Craft, rien n’est envoyé — la réponse vous indique la
bonne valeur.
Erreurs et que faire#
| Statut | Signification |
|---|---|
| 400 | Paramètres invalides — message indique lesquels |
| 401 | Pas de clé, mauvaise clé, ou la clé a été révoquée |
| 403 | Forfait sans API (plan_required), la clé n’a pas la permission (scope_required), ou le mode de publication ne permet pas l’action |
| 404 | Introuvable : tunnel, contact, post ou méthode |
| 409 | Les données ont changé depuis votre lecture, ou une confirmation ne correspondait pas — relisez |
| 429 | Limite de débit — attendez autant de secondes que l’indique l’en-tête Retry-After |
| 500, 503 | Panne temporaire — réessayez dans une minute avec la même Idempotency-Key |
Limites#
- 60 requêtes par minute et 10 000 par jour par compte — toutes clés confondues. La journée est comptée à l’heure de Moscou (UTC+3). Besoin de plus ? Écrivez au support ; la limite est relevée sans changer de forfait.
- Les webhooks ne comptent pas dans la limite.
- Les images consomment des credits aux mêmes prix que sur le site, et jamais au-delà de la limite quotidienne que vous avez fixée pour la clé.
- Diffusions : pas plus que le nombre choisi par jour et par bot. Un test à vous-même avec
send_broadcast_testdu texte strictement identique est obligatoire avant l’envoi.
Webhooks#
API et webhooks → Ajouter un webhook (Add webhook) : saisissez l’adresse de votre serveur (https:// uniquement) et choisissez les
événements. Juste après la création, Craft affiche le secret de signature — conservez-le, il n’est plus affiché
(vous pouvez en émettre un nouveau avec « Nouveau secret »).
Tester envoie un événement ping et montre ce que votre serveur a répondu. Journal liste les
envois récents : ce qui a été envoyé, si c’est arrivé, la réponse, et un bouton « Réessayer ».
Événements#
| Événement | Quand il arrive |
|---|---|
contact.created |
Quelqu’un s’est abonné à un bot ou a écrit pour la première fois à votre Direct Instagram |
funnel.button_clicked |
Quelqu’un a cliqué sur un bouton dans un tunnel |
funnel.goal_reached |
Quelqu’un a atteint l’objectif du tunnel |
payment.succeeded |
Un paiement est passé par un bloc de paiement d’un tunnel |
post.published |
Un post a été publié sur le réseau social |
agent.message_received |
Le message d’un client est parvenu à l’agent IA — sur Instagram ou Telegram |
agent.replied |
L’agent IA a répondu au client et la réponse a été envoyée. Les données contiennent le texte de la réponse |
agent.handed_over |
L’agent IA a transmis le client à l’équipe. Les données contiennent le résumé et indiquent si et à qui il a été remis |
Les événements de l’agent portent platform (instagram ou telegram), account_id (le compte Instagram ou le bot), contact_id et un horodatage, pour que vous puissiez conserver l’historique des conversations de l’agent dans votre propre CRM ou service.
Exemple de corps de requête :
{
"id": "6f1c…",
"type": "contact.created",
"created_at": "2026-09-26T09:04:11+00:00",
"data": {
"platform": "telegram",
"contact_id": "…",
"bot_username": "shop_bot",
"first_name": "Anna",
"username": "anna",
"source": {"type": "link", "ref": "promo"}
}
}
L’id de l’événement reste le même d’une tentative à l’autre — utilisez-le pour écarter les doublons.
Vérifier qu’une requête vient de Craft#
Chaque requête a un en-tête Craft-Signature: t=<time>,v1=<signature>. La signature est
le HMAC-SHA256 de la chaîne <time>.<corps de la requête> avec votre secret. Calculez-la et comparez :
import hmac, hashlib, time
def craft_signature_ok(header: str, body: bytes, secret: str) -> bool:
parts = dict(p.split("=", 1) for p in header.split(","))
if abs(time.time() - int(parts["t"])) > 300: # older than 5 minutes — reject
return False
expected = hmac.new(secret.encode(), f"{parts['t']}.".encode() + body, hashlib.sha256).hexdigest()
return hmac.compare_digest(expected, parts["v1"])
const crypto = require("crypto");
function craftSignatureOk(header, rawBody, secret) {
const parts = Object.fromEntries(header.split(",").map((p) => p.split("=")));
if (Math.abs(Date.now() / 1000 - Number(parts.t)) > 300) return false;
const expected = crypto.createHmac("sha256", secret).update(`${parts.t}.${rawBody}`).digest("hex");
return crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(parts.v1));
}
⚠️ La signature est calculée sur le corps brut de la requête — exactement les octets reçus. Si votre framework analyse d’abord le JSON puis le resérialise, la signature ne correspondra pas.
Nouvelles tentatives#
Craft attend une réponse jusqu’à 10 secondes. Toute réponse 2xx compte comme remise.
Sinon, Craft réessaie après 1 minute, 5 minutes, 30 minutes, 2, 6, 12 et 24 heures — 8
tentatives au total, après quoi l’événement est marqué « échoué » (vous pouvez le renvoyer depuis le journal).
🔴 Après 50 échecs de remise consécutifs, le webhook est désactivé pour ne pas continuer à frapper une adresse morte. Réparez votre serveur et cliquez sur « Activer » — le compteur repart à zéro. Les événements survenus pendant que le webhook était désactivé ne sont pas envoyés.
Répondez vite et faites le travail lent après avoir répondu : si votre serveur met plus de 10 secondes, Craft considère la tentative comme échouée et renvoie l’événement.
Votre propre canal : les réponses de l’agent IA#
Si des clients vous écrivent là où Craft n’est pas connecté (votre propre messagerie, le chat de votre site, un CRM), l’agent IA peut aussi y répondre. Votre système envoie le message du client — Craft renvoie la réponse de l’agent. Votre système la remet au client.
curl -X POST https://craftopen.space/api/v1/agent/reply \
-H "Authorization: Bearer craft_…" -H "Content-Type: application/json" \
-d '{"ig_user_id": "1784…", "contact_id": "client-42", "text": "How much is JET+?", "name": "Ivan"}'
- Quel agent répond —
ig_user_idd’un compte Instagram outg_bot_idd’un bot Telegram avec un agent configuré. Ses règles, sa base de connaissances, son modèle et ses réglages de transfert sont utilisés. contact_id— l’identifiant stable de votre client ; l’agent se souvient de la conversation grâce à lui.name— facultatif, pour le transfert à l’équipe.- Réponse :
reply— le texte pour le client,handed_over— l’agent a transmis le client à l’équipe (le prospect va là où vont les prospects Instagram),paused— l’agent reste muet jusqu’à ce que l’équipe le lui rende,credits_charged— les credits dépensés. - Les réponses coûtent des credits, comme sur Instagram. Plus de credits — vous recevez une erreur
no_credits. - Les événements
agent.message_received,agent.repliedetagent.handed_overse déclenchent aussi pour ce canal.
⚠️ Sur ce canal, l’agent n’envoie que du texte — pas de vidéos ni de fichiers issus des tunnels.
Pas encore disponible#
- Des bibliothèques clientes prêtes à l’emploi — utilisez la description OpenAPI.
- La création de clés et de webhooks via l’API elle-même — uniquement sur la page API et webhooks.
- « Se connecter avec Craft » pour des applications tierces : une clé ne donne accès qu’à votre propre compte.