Aller au contenu

API REST

L’API REST ouvre la Messagerie aux programmes : un script, une synchronisation avec un CRM, un outil d’automatisation. Elle répond sous /api/v1, sur le serveur du chat, et passe par les mêmes fonctions que l’inbox : une réponse envoyée par l’API apparaît aussitôt aux conseillers et part au visiteur.

https://chat.exemple.fr/api/v1

L’adresse exacte de votre serveur est affichée, prête à copier, dans Administration › API et MCP. Les mêmes jetons ouvrent le serveur MCP, pour un agent IA. Pour être prévenu de ce qui se passe plutôt que de le demander, voyez les webhooks.

Un jeton se crée dans Administration › API et MCP, onglet Jetons, bouton Nouveau jeton. Seuls les superviseurs les gèrent ; un conseiller lit « Les jetons se gèrent par les superviseurs. ».

ChampCe qu’il règle
À quoi sert ce jeton ?Son nom, 200 caractères au plus. C’est aussi le nom qui signe ce qu’il écrit.
AccèsAPI REST, MCP, ou les deux. Pris sur une porte qu’il n’ouvre pas, il est refusé.
DroitsLecture seule : lire les conversations, les contacts, chercher. Lecture et écriture : aussi répondre, noter, affecter, résoudre, étiqueter.
Boîtes de réceptionToutes, ou Certaines, choisies une à une.
ValiditéSans expiration, 30 jours, 90 jours, 180 jours ou 1 an.

Un jeton s’écrit msg_<préfixe>_<secret> : un préfixe de huit caractères gardé en clair, qui le distingue dans la liste (msg_k3v9x2ma…), puis un secret de 43 caractères tiré de 32 octets aléatoires. Seul le SHA-256 du secret est conservé.

Gardez-le dans une variable d’environnement, MESSAGERIE_TOKEN, plutôt que dans un fichier, un dépôt ou un message :

Fenêtre de terminal
export MESSAGERIE_TOKEN="msg_k3v9x2ma_…"

Aucun jeton ne supprime quoi que ce soit, et aucun ne gère les jetons : un jeton n’atteint jamais /api/inbox, l’API de l’inbox.

DroitsPermet
Lecture seuleLire les conversations, les contacts, les boîtes, les conseillers ; chercher dans les messages.
Lecture et écritureAussi répondre au visiteur, écrire une note interne, affecter, résoudre, poser et retirer une étiquette.

Une écriture demandée avec un jeton en lecture seule est refusée (TOKEN_READ_ONLY).

Un jeton n’atteint jamais plus que son créateur : ses boîtes sont celles qu’il a cochées, parmi celles que voit son créateur. Un superviseur voit toutes les boîtes ; un jeton qu’il crée avec Toutes les atteint donc toutes.

Pour le jeton, une conversation d’une autre boîte n’existe pas (CONVERSATION_NOT_FOUND), ni un contact qui n’a jamais écrit dans l’une des siennes (CONTACT_NOT_FOUND).

  • Révocation : bouton Révoquer de la liste. Ce qui utilise le jeton est refusé dès maintenant (TOKEN_REVOKED) ; cela ne se défait pas.
  • Expiration : passée sa date, le jeton est refusé (TOKEN_EXPIRED). Les jetons révoqués ou expirés restent visibles sous la liste, repliés.
  • Créateur : si son créateur n’est plus conseiller actif, le jeton est refusé (TOKEN_INVALID).
  • Dernière utilisation : la liste dit « utilisé le … » ; la date est notée au plus toutes les cinq minutes.

Chaque requête porte le jeton dans l’en-tête Authorization :

Authorization: Bearer msg_k3v9x2ma_…

Le premier appel à faire : demander ce que peut le jeton.

Fenêtre de terminal
curl https://chat.exemple.fr/api/v1/me \
-H "Authorization: Bearer $MESSAGERIE_TOKEN"
200 OK
{
"data": {
"label": "Synchronisation CRM",
"prefix": "msg_k3v9x2ma",
"access": "write",
"surfaces": ["rest", "mcp"],
"inboxIds": null,
"expiresAt": null
}
}

inboxIds vaut null quand le jeton atteint toutes les boîtes ; sinon, ce sont les boîtes qu’il atteint réellement, ses choix croisés avec ce que voit son créateur.

  • Tout est en JSON. Une réponse porte ses données sous data.
  • Un refus porte un code stable et, parfois, des details, avec le statut HTTP qui le dit.
  • Les dates sont en ISO 8601, en UTC : 2026-10-02T09:14:00.000Z.
  • Les identifiants de conversation, de contact et de conseiller sont des UUID.
  • Les textes des messages sont dans le petit Markdown de la Messagerie : **gras**, *italique*, listes, liens, citations.
MéthodeRouteDroitsRôle
GET/melecturele jeton : nom, droits, accès, boîtes, expiration
GET/conversationslecturelister les conversations
GET/conversations/{id}lecturelire une conversation et tous ses messages
POST/conversationsécritureécrire le premier à un client, par SMS ou par e-mail
POST/conversations/{id}/messagesécriturerépondre au visiteur, ou écrire une note
POST/conversations/{id}/assignécritureaffecter à un conseiller, ou remettre dans la file
POST/conversations/{id}/resolveécriturerésoudre
POST/conversations/{id}/tagsécritureposer une étiquette
DELETE/conversations/{id}/tags/{label}écritureretirer une étiquette
GET/contactslecturelister ou chercher les contacts
GET/contacts/{id}lecturelire la fiche d’un contact
GET/searchlecturechercher dans les messages
GET/inboxeslectureles boîtes de réception du jeton
GET/agentslectureles conseillers actifs
GET/openapi.jsonlecturela spécification OpenAPI 3.1

Toutes les routes sont sous /api/v1. Un {id} qui n’est pas un UUID reçoit le même refus qu’un identifiant inconnu : 404, avec le code de la ressource.

GET /api/v1/conversations

Les conversations que le jeton atteint, la plus récente d’abord (par date du dernier message). Non résolues par défaut.

ParamètreTypeRôle
statustexteunresolved (par défaut), ai : l’IA répond, open, pending, resolved, all.
inboxtexteune boîte de réception seulement, par son identifiant (GET /inboxes).
assigneetexteun conseiller, par son identifiant (GET /agents) ; none pour la file d’attente.
limitentier50 par défaut, de 1 à 200.
Fenêtre de terminal
curl "https://chat.exemple.fr/api/v1/conversations?status=open&assignee=none&limit=20" \
-H "Authorization: Bearer $MESSAGERIE_TOKEN"
200 OK
{
"data": [
{
"id": "4f1c2e8a-7b3d-4c9e-a1f0-2d5e6b7c8a90",
"contact": {
"id": "9a8b7c6d-5e4f-4a3b-8c2d-1e0f9a8b7c6d",
"name": "Léa Martin",
"email": "lea.martin@exemple.fr",
"identified": true
},
"site": "Acme Assurances",
"siteId": "01a0f647-6c2e-7d41-8b5a-3f9e2c7d1a46",
"channel": "web",
"inboxId": "01a0f647-74b7-7450-93a6-8dfe920d8934",
"teamId": null,
"status": "open",
"assignee": null,
"assigneeId": null,
"unread": true,
"handedOff": true,
"preview": "Où en est le remboursement de mon sinistre ?",
"previewAuthor": "visitor",
"previewAgent": null,
"previewFiles": 0,
"lastMessageAt": "2026-10-02T09:14:00.000Z",
"priority": "normal",
"sentiment": "neutral",
"tags": [{ "label": "Sinistre", "color": "#f97316", "byAi": true }],
"snoozedUntil": null
}
]
}
ChampSens
contactid, name, email, et identified : true quand le site a signé l’identité (voir Identité signée).
site, siteIdLe nom du site à l’arrivée de la conversation, et son identifiant.
channelD’où écrit le visiteur : web — le widget —, sms ou rcs — son téléphone (SMS et RCS) —, email — sa messagerie (E-mail).
inboxId, teamIdSa boîte et son équipe ; null si elle n’en a pas.
statusai : l’IA répond seule · open : des conseillers répondent · pending : en attente · resolved : résolue.
assignee, assigneeIdLe conseiller qui l’a, ou null : elle est dans la file.
unreadUn message du visiteur attend une lecture.
handedOffL’IA l’a passée à un conseiller.
preview, previewAuthor, previewAgent, previewFilesLe dernier message : son texte, son auteur (visitor, agent, ai), le nom du conseiller s’il vient de lui, son nombre de fichiers.
lastMessageAtLa date du dernier message.
prioritylow, normal, high ou urgent.
sentimentpositive, neutral, negative, ou null.
tagsSes étiquettes : label, color, et byAi quand l’IA l’a posée.
snoozedUntilPour une conversation mise en attente, l’heure à laquelle elle revient ; sinon null.

GET /api/v1/conversations/{id}

Une conversation entière : les champs de la liste, la fiche complète du contact, le résumé de l’IA, ses métadonnées et tous ses messages — du visiteur, de l’IA, des conseillers, les notes internes et les événements —, dans l’ordre.

Fenêtre de terminal
curl https://chat.exemple.fr/api/v1/conversations/4f1c2e8a-7b3d-4c9e-a1f0-2d5e6b7c8a90 \
-H "Authorization: Bearer $MESSAGERIE_TOKEN"
200 OK
{
"data": {
"id": "4f1c2e8a-7b3d-4c9e-a1f0-2d5e6b7c8a90",
"contact": {
"id": "9a8b7c6d-5e4f-4a3b-8c2d-1e0f9a8b7c6d",
"name": "Léa Martin",
"email": "lea.martin@exemple.fr",
"phone": null,
"identified": true,
"location": null,
"country": "FR",
"timeZone": "Europe/Paris",
"place": { "latitude": 48.8566, "longitude": 2.3522, "approximate": true },
"segment": "Particulier",
"attributes": [{ "label": "Contrat", "value": "AUTO-2291", "kind": "code" }],
"data": {}
},
"site": "Acme Assurances",
"siteId": "01a0f647-6c2e-7d41-8b5a-3f9e2c7d1a46",
"channel": "web",
"inboxId": "01a0f647-74b7-7450-93a6-8dfe920d8934",
"teamId": null,
"data": { "contrat": "AUTO-2291" },
"status": "open",
"snoozedUntil": null,
"assignee": "Claire Dubois",
"assigneeId": "0c1d2e3f-4a5b-4c6d-9e8f-7a6b5c4d3e2f",
"unread": false,
"intent": "suivi remboursement",
"tags": [{ "label": "Sinistre", "color": "#f97316", "byAi": true }],
"sentiment": "neutral",
"priority": "normal",
"suggestions": [],
"summary": "La cliente demande où en est le remboursement de son sinistre du 28 septembre.",
"history": [
{ "subject": "Attestation d’assurance", "at": "2026-06-11T14:02:00.000Z", "status": "resolved" }
],
"messages": [
{
"id": "7d1e0c2a-…",
"at": "2026-10-02T09:12:00.000Z",
"kind": "visitor",
"body": "Où en est le remboursement de mon sinistre ?",
"attachments": []
},
{
"id": "8e2f1d3b-…",
"at": "2026-10-02T09:12:04.000Z",
"kind": "ai",
"body": "Le remboursement est versé sous 5 à 10 jours ouvrés…",
"confidence": 0.62,
"sources": [
{ "title": "Délai de remboursement", "origin": "article", "detail": "…" }
],
"feedback": null
},
{
"id": "9f302e4c-…",
"at": "2026-10-02T09:14:00.000Z",
"kind": "agent",
"author": "Claire Dubois",
"authorId": "0c1d2e3f-4a5b-4c6d-9e8f-7a6b5c4d3e2f",
"body": "Votre dossier est **complet** : le virement part demain.",
"attachments": []
}
]
}
}

En plus des champs de la liste :

ChampSens
contactLa fiche entière : phone, location, country, timeZone, place (un point, approximate quand il vient du fuseau horaire), segment, attributes transmis par le site, data déclarées par la page ou un conseiller.
dataLes métadonnées jointes à la conversation par la page ou un conseiller.
intent, summaryL’intention et le résumé qu’en a faits l’IA, ou null.
suggestionsLes réponses que le copilote propose pour la suite, de 0 à 3.
historyLes autres conversations du contact : subject, at, status.
pagesLes pages que le visiteur a ouvertes depuis le début de la conversation, la plus récente d’abord, vingt au plus : url, title, at, leftAt — null tant qu’elle est ouverte. Ce que dit son widget, non vérifié.
messagesTous les messages, dans l’ordre — voir ci-dessous.

Chaque message a un id, une date at et un kind :

kindChampsCe que c’est
visitorbody, attachmentsCe qu’a écrit le visiteur. body est vide s’il n’a envoyé que des fichiers.
agentauthor, authorId, body, attachmentsUne réponse d’un conseiller — ou d’un jeton.
noteauthor, authorId, body, attachmentsUne note interne, que seule l’équipe voit.
aibody, confidence (0 à 1), sources, feedbackUne réponse de l’IA, et les passages d’où elle vient.
eventeventCe qui s’est passé : { "type": "assigned", "agent": "Claire Dubois", "by": "Synchronisation CRM" }, resolved, reopened, takeover, transferred, tool…
handoffreason, summary, confidence, assignee, teamL’IA a passé la main, avec ce qu’il faut pour reprendre.

Un fichier joint (attachments) porte id, name, mime, size, analysis (ce qu’en a dit l’IA, à la demande d’un conseiller, ou null) et url : un chemin signé, relatif à l’adresse du serveur, qui lit le fichier sans jeton pendant environ un jour.

Un message supprimé pour tout le monde porte deleted (by, at) et un body vide.

Une réponse (agent, ai) partie hors du widget porte delivery : by — sms (SMS ou RCS) ou email (au visiteur parti qui a laissé son adresse) —, status — pending, sent, delivered, read ou failed — et, en échec, error : le code du fournisseur (TWILIO_21610 : le client a répondu STOP) ou de la messagerie (NUMBER_UNAVAILABLE…). Voir SMS et RCS.

POST /api/v1/conversations/{id}/messages · écriture · réponse 201

Champ du corpsTypeRequisRôle
bodytexteouiLe texte, en Markdown léger : **gras**, *italique*, listes, liens.
kindtextenonreply (par défaut) : au visiteur. note : à l’équipe seule.
resolvebooléennonRésoudre la conversation avec cette réponse. Sans effet sur une note.
Fenêtre de terminal
curl -X POST https://chat.exemple.fr/api/v1/conversations/4f1c2e8a-7b3d-4c9e-a1f0-2d5e6b7c8a90/messages \
-H "Authorization: Bearer $MESSAGERIE_TOKEN" \
-H "Content-Type: application/json" \
-d '{"body": "Votre dossier est **complet** : le virement part demain.", "resolve": true}'

La réponse est la conversation telle qu’elle est ensuite, comme GET /conversations/{id}.

  • Une réponse part au visiteur, signée du nom du jeton. Elle fait quitter la conversation à l’IA ; une conversation résolue est rouverte. Le jeton ne prend pas la conversation : une conversation de la file y reste, sans conseiller.
  • Une note n’est vue que de l’équipe ; elle ne change ni l’état ni le conseiller.
  • Un texte vide, ou fait d’espaces, est refusé (EMPTY_MESSAGE).

POST /api/v1/conversations · écriture · réponse 201

Écrit à un client qui n’a rien demandé : par SMS, depuis un numéro de Numéros SMS, ou par e-mail : depuis l’adresse du site s’il en a une — la réponse du client revient dans la conversation —, sinon par le serveur d’e-mails (CHAT_SMTP_URL).

Champ du corpsTypeRequisRôle
channeltexteouisms ou email.
bodytexteouiLe message, 4 000 caractères au plus.
contactIdUUIDnonUn contact connu.
phonetextenonPour sms : le numéro, au format international (+33612345678), si le contact n’en a pas.
emailtextenonPour email : l’adresse, si le contact n’en a pas.
nametextenonLe nom d’un nouveau contact. Aucun : son numéro ou son adresse.
numberIdUUIDnonPour sms : le numéro d’envoi. Aucun : celui du site du contact, ou le premier prêt.
siteIdUUIDnonPour email à une nouvelle adresse : le site. Aucun : le premier site actif.
Fenêtre de terminal
curl -X POST https://chat.exemple.fr/api/v1/conversations \
-H "Authorization: Bearer $MESSAGERIE_TOKEN" \
-H "Content-Type: application/json" \
-d '{"channel": "sms", "phone": "+33612345678", "body": "Votre attestation est prête dans votre espace client."}'

La réponse est la conversation, comme GET /conversations/{id}. Par SMS, c’est celle de ce téléphone sur ce numéro — où la réponse du client arrivera ; par e-mail, la conversation du widget du contact, encore en cours, ou une nouvelle : l’e-mail part aussitôt. Une nouvelle conversation arrive dans la boîte de son site, qui doit être l’une de celles du jeton. Signée du nom du jeton, elle reste dans la file, sans conseiller.

RefusQuand
NUMBER_UNAVAILABLEaucun numéro prêt à envoyer — ou celui de numberId ne l’est pas
MAIL_UNAVAILABLEle serveur n’écrit pas d’e-mails (CHAT_SMTP_URL)
EMAIL_REPLIES_OFFle site n’écrit pas d’e-mails à ses clients (Répondre par e-mail décoché)
INBOX_NOT_FOUNDla boîte du site n’est pas l’une de celles du jeton
INVALID_REQUESTun numéro ou une adresse qui ne se lit pas : details.field

POST /api/v1/conversations/{id}/assign · écriture

Champ du corpsTypeRequisRôle
assigneeIdUUID ou nullouiUn conseiller actif (GET /agents), ou null pour remettre la conversation dans la file.
Fenêtre de terminal
curl -X POST https://chat.exemple.fr/api/v1/conversations/4f1c2e8a-7b3d-4c9e-a1f0-2d5e6b7c8a90/assign \
-H "Authorization: Bearer $MESSAGERIE_TOKEN" \
-H "Content-Type: application/json" \
-d '{"assigneeId": "0c1d2e3f-4a5b-4c6d-9e8f-7a6b5c4d3e2f"}'

Le conseiller en est averti dans l’inbox. Une conversation que l’IA tenait passe aux conseillers. Un conseiller inconnu ou inactif est refusé (AGENT_NOT_FOUND) ; affecter au conseiller qui l’a déjà ne change rien. Rend la conversation.

POST /api/v1/conversations/{id}/resolve · écriture · sans corps

Marque la conversation comme résolue ; une conversation mise en attente sort de l’attente. Un nouveau message du visiteur la rouvrira. Résoudre une conversation déjà résolue ne change rien. Rend la conversation.

POST /api/v1/conversations/{id}/tags · écriture

Champ du corpsTypeRequisRôle
labeltexteouiLe nom de l’étiquette, de 1 à 60 caractères.
Fenêtre de terminal
curl -X POST https://chat.exemple.fr/api/v1/conversations/4f1c2e8a-7b3d-4c9e-a1f0-2d5e6b7c8a90/tags \
-H "Authorization: Bearer $MESSAGERIE_TOKEN" \
-H "Content-Type: application/json" \
-d '{"label": "Remboursement"}'

Une étiquette déclarée dans Administration › Réponses types et étiquettes, onglet Étiquettes, prend son nom et sa couleur — la casse ne compte pas. Une autre est posée telle quelle, en gris. Poser une étiquette déjà présente ne change rien. Rend la conversation.

DELETE /api/v1/conversations/{id}/tags/{label} · écriture

{label} est le nom de l’étiquette, encodé pour une adresse (Service%20client). Retirer une étiquette absente ne change rien. Rend la conversation.

Fenêtre de terminal
curl -X DELETE https://chat.exemple.fr/api/v1/conversations/4f1c2e8a-7b3d-4c9e-a1f0-2d5e6b7c8a90/tags/Sinistre \
-H "Authorization: Bearer $MESSAGERIE_TOKEN"

GET /api/v1/contacts

Les contacts — visiteurs anonymes et clients identifiés par leur site —, le plus récent d’abord, 200 au plus. Un jeton limité à des boîtes n’atteint que ceux qui y ont écrit.

ParamètreTypeRôle
qtexteUn morceau de nom, d’e-mail, de numéro de téléphone ou d’identifiant client.
200 OK
{
"data": [
{
"id": "9a8b7c6d-5e4f-4a3b-8c2d-1e0f9a8b7c6d",
"name": "Léa Martin",
"email": "lea.martin@exemple.fr",
"identified": true,
"site": "Acme Assurances",
"location": null,
"country": "FR",
"timeZone": "Europe/Paris",
"place": { "latitude": 48.8566, "longitude": 2.3522, "approximate": true },
"conversations": 3,
"lastMessageAt": "2026-10-02T09:14:00.000Z"
}
]
}

conversations compte les conversations du contact que le jeton atteint.

GET /api/v1/contacts/{id}

La fiche d’un contact — ce que son site a transmis, ce que la page ou un conseiller a déclaré — et ses conversations, la plus récente d’abord.

200 OK
{
"data": {
"contact": {
"id": "9a8b7c6d-5e4f-4a3b-8c2d-1e0f9a8b7c6d",
"name": "Léa Martin",
"email": "lea.martin@exemple.fr",
"phone": null,
"identified": true,
"location": null,
"country": "FR",
"timeZone": "Europe/Paris",
"place": { "latitude": 48.8566, "longitude": 2.3522, "approximate": true },
"segment": "Particulier",
"attributes": [{ "label": "Contrat", "value": "AUTO-2291", "kind": "code" }],
"data": {}
},
"site": "Acme Assurances",
"conversations": [
{
"id": "4f1c2e8a-7b3d-4c9e-a1f0-2d5e6b7c8a90",
"subject": "suivi remboursement",
"status": "open",
"at": "2026-10-02T09:14:00.000Z"
}
]
}
}

Le subject d’une conversation est l’intention qu’en a dégagée l’IA, ou à défaut le premier message du visiteur.

GET /api/v1/search

Les messages qui contiennent tous ces mots, dans n’importe quel ordre, accents et majuscules à part — réponses et notes internes comprises —, les plus récents d’abord, 20 au plus.

ParamètreTypeRôle
qtexte, requisTrois caractères au moins.
Fenêtre de terminal
curl "https://chat.exemple.fr/api/v1/search?q=remboursement%20delai" \
-H "Authorization: Bearer $MESSAGERIE_TOKEN"
200 OK
{
"data": [
{
"conversationId": "4f1c2e8a-7b3d-4c9e-a1f0-2d5e6b7c8a90",
"messageId": "7d1e0c2a-…",
"contactName": "Léa Martin",
"author": "visitor",
"at": "2026-10-02T09:12:00.000Z",
"body": "Quel est le délai de remboursement ?"
}
]
}

author vaut visitor, agent, ai ou note.

GET /api/v1/inboxes

Les boîtes actives que le jeton atteint : ce qu’attend le filtre inbox de la liste.

200 OK
{
"data": [
{
"id": "01a0f647-74b7-7450-93a6-8dfe920d8934",
"name": "Service client",
"description": "Questions générales"
}
]
}

GET /api/v1/agents

Les conseillers actifs, à qui une conversation peut être affectée, avec leurs équipes. Les jetons n’y figurent pas.

200 OK
{
"data": [
{
"id": "0c1d2e3f-4a5b-4c6d-9e8f-7a6b5c4d3e2f",
"name": "Claire Dubois",
"email": "claire.dubois@acme.fr",
"role": "agent",
"teamIds": ["01a0f647-7a1c-7c2e-9d3f-4b5a6c7d8e9f"]
}
]
}

role vaut agent ou supervisor.

L’API n’a pas de curseur : une liste rend ses premiers éléments, les plus récents d’abord. Pour aller plus loin, resserrez la demande — un status, une boîte, un conseiller, une recherche.

QuoiLimite
Requêtes par jeton240 par minute sur l’API REST, autant sur le MCP ; au-delà, 429 RATE_LIMITED.
Conversations par liste50 par défaut, 200 au plus (limit).
Contacts par liste200.
Résultats d’une recherche20, les plus récents.
Mots cherchés3 caractères au moins.
Étiquette60 caractères.

Un refus est un objet JSON, avec le statut HTTP qui convient :

400 Bad Request
{
"code": "INVALID_REQUEST",
"details": { "issues": [{ "field": "status", "message": "Invalid option" }] }
}
CodeStatutSens
TOKEN_INVALID401Pas de jeton, un jeton mal formé ou inconnu, un jeton qui n’ouvre pas l’API REST, ou dont le créateur n’est plus conseiller actif.
TOKEN_EXPIRED401Le jeton a dépassé sa date d’expiration.
TOKEN_REVOKED401Le jeton a été révoqué.
TOKEN_READ_ONLY403Une écriture avec un jeton en lecture seule.
INVALID_REQUEST400Un paramètre ou un corps mal formé : details.issues dit lequel (field) et pourquoi (message).
EMPTY_MESSAGE400Un message vide.
CONVERSATION_NOT_FOUND404Une conversation qui n’existe pas, ou que le jeton n’atteint pas.
CONTACT_NOT_FOUND404Un contact qui n’existe pas, ou que le jeton n’atteint pas.
AGENT_NOT_FOUND404Un conseiller inconnu, ou qui n’est plus actif.
NUMBER_UNAVAILABLE, MAIL_UNAVAILABLE, EMAIL_REPLIES_OFF404, 503, 409Écrire en premier : pas de numéro prêt, pas d’e-mail, ou pas pour ce site.
RATE_LIMITED429Plus de 240 requêtes en une minute pour ce jeton.
INTERNAL_ERROR500Une erreur du serveur — elle est journalisée de son côté.

Ces codes sont stables : un programme décide sur le code, jamais sur un texte.

Un jeton agit sous son propre nom. Ce qu’il écrit est signé du nom du jeton dans le fil — « Synchronisation CRM » — et ses actions s’y lisent comme celles d’un conseiller : « Synchronisation CRM a confié la conversation à Claire Dubois. »

Ce nom ne figure dans aucune liste de conseillers, ne peut pas recevoir de conversation et ne reçoit aucune alerte. Une réponse envoyée par un jeton fait quitter la conversation à l’IA, mais ne la lui affecte pas : elle reste où elle était — dans la file, ou chez son conseiller.

Un script qui note, dans chaque conversation ouverte de la file, le contrat trouvé dans un CRM :

#!/usr/bin/env bash
API=https://chat.exemple.fr/api/v1
AUTH="Authorization: Bearer $MESSAGERIE_TOKEN"
curl -s "$API/conversations?status=open&assignee=none&limit=200" -H "$AUTH" |
jq -r '.data[] | select(.contact.identified) | .id' |
while read -r id; do
curl -s -X POST "$API/conversations/$id/messages" -H "$AUTH" \
-H "Content-Type: application/json" \
-d '{"kind": "note", "body": "Contrat vérifié dans le CRM : **à jour**."}' > /dev/null
done

Le même appel en JavaScript :

const response = await fetch(
'https://chat.exemple.fr/api/v1/conversations?status=open&limit=20',
{ headers: { Authorization: `Bearer ${process.env.MESSAGERIE_TOKEN}` } },
)
const body = await response.json()
if (!response.ok) throw new Error(body.code)
for (const conversation of body.data) console.log(conversation.contact.name, conversation.preview)

Le bouton Documentation de l’écran API et MCP ouvre la référence complète, écrite à partir du code qui tourne : chaque route avec ses paramètres et des exemples en cURL, JavaScript et Python, les outils du serveur MCP et les webhooks. Les adresses y sont celles de votre serveur.

La spécification OpenAPI 3.1 se lit avec un jeton, pour un générateur de client ou un outil comme Postman :

Fenêtre de terminal
curl https://chat.exemple.fr/api/v1/openapi.json \
-H "Authorization: Bearer $MESSAGERIE_TOKEN"

Un logiciel libre d’Eodia, studio de logiciel IA-natif — frère de basedb.