Référence de l'API
Boîte de réception
Conversations avec les clients via le widget de chat, WhatsApp et l'e-mail, avec leurs messages. Suivez-les, répondez au nom de l'entreprise et clôturez une conversation.
Endpoints
-
GET
/conversationsLister les conversations -
GET
/conversations/{conversation}Obtenir une conversation -
GET
/conversations/{conversation}/messagesLister les messages -
POST
/conversations/{conversation}/messagesEnvoyer un message -
POST
/conversations/{conversation}/closeClôturer la conversation
Lister les conversations
/api/v1/conversations
Une liste de conversations, dernier message en premier. Filtrez par statut, canal, client ou date de modification. Avec filter[status]=open vous obtenez ce qui est encore ouvert.
- Scope
-
messages.read— Lire les conversations et les messages de la boîte de réception - Fonctionnalité requise
chat_widget|email|whatsapp
Paramètres de requête
| Nom | Type | Description |
|---|---|---|
limit
|
integer | Nombre de résultats par page. de 1 à 100 · par défaut : 50 |
cursor
|
string | Le next_cursor ou prev_cursor de meta dans la réponse précédente. |
sort
|
string | Tri par created_at ou updated_at ; un signe moins devant trie par ordre décroissant. l'une des valeurs : -last_message_at, last_message_at, -created_at, created_at, -updated_at, updated_at · par défaut : -last_message_at |
filter[status]
|
string | Uniquement les conversations avec ce statut : open, waiting_on_customer, waiting_on_team, snoozed ou closed. l'une des valeurs : open, waiting_on_customer, waiting_on_team, snoozed, closed |
filter[channel]
|
string | Uniquement les conversations sur ce canal : web (widget de chat), whatsapp ou email. l'une des valeurs : web, whatsapp, email |
filter[customer_id]
|
string (uuid) | Uniquement ce qui appartient à ce client. |
filter[updated_since]
|
string (date-time) | Uniquement ce qui a changé depuis ce moment : ISO 8601 avec fuseau horaire, par exemple 2026-09-14T10:15:00Z. Pratique pour synchroniser. |
Exemple de requête
curl "https://app.klantly.com/api/v1/conversations?filter[status]=open&sort=-last_message_at" \
-H "Authorization: Bearer $KLANTLY_API_KEY"$client = new \GuzzleHttp\Client([
'base_uri' => 'https://app.klantly.com/api/v1/',
'headers' => ['Authorization' => 'Bearer ' . getenv('KLANTLY_API_KEY')],
]);
$response = $client->request('GET', 'conversations', [
'query' => [
'filter[status]' => 'open',
'sort' => '-last_message_at',
],
]);
$data = json_decode((string) $response->getBody(), true)['data'];const response = await fetch('https://app.klantly.com/api/v1/conversations?filter[status]=open&sort=-last_message_at', {
headers: {
Authorization: `Bearer ${process.env.KLANTLY_API_KEY}`,
},
});
const { data } = await response.json();import os
import requests
response = requests.get(
"https://app.klantly.com/api/v1/conversations",
headers={
"Authorization": f"Bearer {os.environ['KLANTLY_API_KEY']}",
},
params={
"filter[status]": "open",
"sort": "-last_message_at"
},
)
data = response.json()["data"]Réponse 200
La réponse est une liste avec pagination par curseur : data contient les objets, meta la pagination.
{
"data": [
{
"object": "conversation",
"id": "9d3f9a12-6b7c-4d8e-9f01-a2b3c4d5e6f1",
"status": "open",
"channel": "web",
"priority": "normal",
"subject": "Vraag over mijn offerte",
"summary": null,
"page_url": "https://example.com/verandas",
"customer_id": "9d3f6c1e-4b2a-4c8e-9f1a-2b3c4d5e6f70",
"customer": {
"name": "Jan de Vries",
"email": "jan@example.com",
"phone": "+31 6 12345678"
},
"assigned_user_id": null,
"quote_id": null,
"invoice_id": null,
"appointment_id": null,
"message_count": 4,
"last_message_at": null,
"closed_at": null,
"created_at": "2026-09-14T10:15:00Z",
"updated_at": "2026-09-14T10:15:00Z"
}
],
"meta": {
"limit": 50,
"next_cursor": "eyJpZCI6IjlkM2Y2YzFlIn0",
"prev_cursor": null
}
}Erreurs possibles
-
403
insufficient_scope— Cette clé API n'a pas accès à cette action. -
422
validation_failed— Les données saisies ne sont pas valides.
Obtenir une conversation
/api/v1/conversations/{conversation}
Une conversation par id, avec les coordonnées du client, le canal et le nombre de messages.
- Scope
-
messages.read— Lire les conversations et les messages de la boîte de réception - Fonctionnalité requise
chat_widget|email|whatsapp
Paramètres de chemin
| Nom | Type | Description |
|---|---|---|
conversation obligatoire |
string (uuid) | L'id (UUID) de la conversation. |
Exemple de requête
curl "https://app.klantly.com/api/v1/conversations/9d3f6c1e-4b2a-4c8e-9f1a-2b3c4d5e6f70" \
-H "Authorization: Bearer $KLANTLY_API_KEY"$client = new \GuzzleHttp\Client([
'base_uri' => 'https://app.klantly.com/api/v1/',
'headers' => ['Authorization' => 'Bearer ' . getenv('KLANTLY_API_KEY')],
]);
$response = $client->request('GET', 'conversations/9d3f6c1e-4b2a-4c8e-9f1a-2b3c4d5e6f70');
$data = json_decode((string) $response->getBody(), true)['data'];const response = await fetch('https://app.klantly.com/api/v1/conversations/9d3f6c1e-4b2a-4c8e-9f1a-2b3c4d5e6f70', {
headers: {
Authorization: `Bearer ${process.env.KLANTLY_API_KEY}`,
},
});
const { data } = await response.json();import os
import requests
response = requests.get(
"https://app.klantly.com/api/v1/conversations/9d3f6c1e-4b2a-4c8e-9f1a-2b3c4d5e6f70",
headers={
"Authorization": f"Bearer {os.environ['KLANTLY_API_KEY']}",
},
)
data = response.json()["data"]Réponse 200
{
"data": {
"object": "conversation",
"id": "9d3f9a12-6b7c-4d8e-9f01-a2b3c4d5e6f1",
"status": "open",
"channel": "web",
"priority": "normal",
"subject": "Vraag over mijn offerte",
"summary": null,
"page_url": "https://example.com/verandas",
"customer_id": "9d3f6c1e-4b2a-4c8e-9f1a-2b3c4d5e6f70",
"customer": {
"name": "Jan de Vries",
"email": "jan@example.com",
"phone": "+31 6 12345678"
},
"assigned_user_id": null,
"quote_id": null,
"invoice_id": null,
"appointment_id": null,
"message_count": 4,
"last_message_at": null,
"closed_at": null,
"created_at": "2026-09-14T10:15:00Z",
"updated_at": "2026-09-14T10:15:00Z"
}
}Erreurs possibles
-
403
insufficient_scope— Cette clé API n'a pas accès à cette action. -
404
not_found— Introuvable.
Lister les messages
/api/v1/conversations/{conversation}/messages
Les messages d'une conversation, du plus ancien au plus récent, pour la lire de haut en bas. Avec sort=-created_at vous obtenez le plus récent en premier.
- Scope
-
messages.read— Lire les conversations et les messages de la boîte de réception - Fonctionnalité requise
chat_widget|email|whatsapp
Paramètres de chemin
| Nom | Type | Description |
|---|---|---|
conversation obligatoire |
string (uuid) | L'id (UUID) de la conversation. |
Paramètres de requête
| Nom | Type | Description |
|---|---|---|
limit
|
integer | Nombre de résultats par page. de 1 à 100 · par défaut : 50 |
cursor
|
string | Le next_cursor ou prev_cursor de meta dans la réponse précédente. |
sort
|
string | created_at (par défaut) lit la conversation de haut en bas, -created_at affiche le plus récent en premier. l'une des valeurs : created_at, -created_at · par défaut : created_at |
Exemple de requête
curl "https://app.klantly.com/api/v1/conversations/9d3f6c1e-4b2a-4c8e-9f1a-2b3c4d5e6f70/messages" \
-H "Authorization: Bearer $KLANTLY_API_KEY"$client = new \GuzzleHttp\Client([
'base_uri' => 'https://app.klantly.com/api/v1/',
'headers' => ['Authorization' => 'Bearer ' . getenv('KLANTLY_API_KEY')],
]);
$response = $client->request('GET', 'conversations/9d3f6c1e-4b2a-4c8e-9f1a-2b3c4d5e6f70/messages');
$data = json_decode((string) $response->getBody(), true)['data'];const response = await fetch('https://app.klantly.com/api/v1/conversations/9d3f6c1e-4b2a-4c8e-9f1a-2b3c4d5e6f70/messages', {
headers: {
Authorization: `Bearer ${process.env.KLANTLY_API_KEY}`,
},
});
const { data } = await response.json();import os
import requests
response = requests.get(
"https://app.klantly.com/api/v1/conversations/9d3f6c1e-4b2a-4c8e-9f1a-2b3c4d5e6f70/messages",
headers={
"Authorization": f"Bearer {os.environ['KLANTLY_API_KEY']}",
},
)
data = response.json()["data"]Réponse 200
La réponse est une liste avec pagination par curseur : data contient les objets, meta la pagination.
{
"data": [
{
"object": "message",
"id": "9d3f9b23-7c8d-4e9f-8012-b3c4d5e6f7a2",
"conversation_id": "9d3f9a12-6b7c-4d8e-9f01-a2b3c4d5e6f1",
"sender": "customer",
"user_id": null,
"body": "Kan de monteur morgen langskomen?",
"email_subject": null,
"attachment": {
"name": "offerte.pdf",
"mime_type": "application/pdf",
"size": 24680
},
"whatsapp_status": null,
"created_at": "2026-09-14T10:15:00Z"
}
],
"meta": {
"limit": 50,
"next_cursor": "eyJpZCI6IjlkM2Y2YzFlIn0",
"prev_cursor": null
}
}Erreurs possibles
-
403
insufficient_scope— Cette clé API n'a pas accès à cette action. -
404
not_found— Introuvable. -
422
validation_failed— Les données saisies ne sont pas valides.
Envoyer un message
/api/v1/conversations/{conversation}/messages
Envoie un message au client sur le canal de la conversation : chat, WhatsApp ou e-mail. Si le canal ne l'accepte pas, rien n'est enregistré et vous obtenez 409 conflict — sur WhatsApp, la fenêtre de 24 heures est généralement expirée. Répondre nécessite la fonctionnalité de ce canal, et l'agent IA s'arrête sur cette conversation, comme lorsqu'un collègue répond. Les messages sortants ont une limite anti-abus : au maximum 250 par heure et par entreprise (partagée avec les e-mails de devis et de facture) et au maximum 20 par heure dans la même conversation via l'API. Au-delà, vous obtenez 429 rate_limited.
- Scope
-
messages.send— Envoyer des messages aux clients et clôturer des conversations - Fonctionnalité requise
chat_widget|email|whatsapp
Envoyez une Idempotency-Key : une nouvelle tentative après un délai d'attente ne crée alors jamais de doublon.
Paramètres de chemin
| Nom | Type | Description |
|---|---|---|
conversation obligatoire |
string (uuid) | L'id (UUID) de la conversation. |
Corps (JSON)
| Champ | Type | Description |
|---|---|---|
body
obligatoire
|
string | Le texte du message. au maximum 10000 caractères |
Exemple de requête
curl -X POST "https://app.klantly.com/api/v1/conversations/9d3f6c1e-4b2a-4c8e-9f1a-2b3c4d5e6f70/messages" \
-H "Authorization: Bearer $KLANTLY_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: 6f1c2d3e-4a5b-4c6d-8e7f-9a0b1c2d3e4f" \
-d '{
"body": "Dag Jan, we komen morgen tussen 9 en 11 uur langs."
}'$client = new \GuzzleHttp\Client([
'base_uri' => 'https://app.klantly.com/api/v1/',
'headers' => ['Authorization' => 'Bearer ' . getenv('KLANTLY_API_KEY')],
]);
$response = $client->request('POST', 'conversations/9d3f6c1e-4b2a-4c8e-9f1a-2b3c4d5e6f70/messages', [
'headers' => [
'Idempotency-Key' => '6f1c2d3e-4a5b-4c6d-8e7f-9a0b1c2d3e4f',
],
'json' => [
'body' => 'Dag Jan, we komen morgen tussen 9 en 11 uur langs.',
],
]);
$data = json_decode((string) $response->getBody(), true)['data'];const response = await fetch('https://app.klantly.com/api/v1/conversations/9d3f6c1e-4b2a-4c8e-9f1a-2b3c4d5e6f70/messages', {
method: 'POST',
headers: {
Authorization: `Bearer ${process.env.KLANTLY_API_KEY}`,
'Content-Type': 'application/json',
'Idempotency-Key': '6f1c2d3e-4a5b-4c6d-8e7f-9a0b1c2d3e4f',
},
body: JSON.stringify({
"body": "Dag Jan, we komen morgen tussen 9 en 11 uur langs."
}),
});
const { data } = await response.json();import os
import requests
response = requests.post(
"https://app.klantly.com/api/v1/conversations/9d3f6c1e-4b2a-4c8e-9f1a-2b3c4d5e6f70/messages",
headers={
"Authorization": f"Bearer {os.environ['KLANTLY_API_KEY']}",
"Idempotency-Key": "6f1c2d3e-4a5b-4c6d-8e7f-9a0b1c2d3e4f",
},
json={
"body": "Dag Jan, we komen morgen tussen 9 en 11 uur langs."
},
)
data = response.json()["data"]Réponse 201
{
"data": {
"object": "message",
"id": "9d3f9b23-7c8d-4e9f-8012-b3c4d5e6f7a2",
"conversation_id": "9d3f9a12-6b7c-4d8e-9f01-a2b3c4d5e6f1",
"sender": "customer",
"user_id": null,
"body": "Kan de monteur morgen langskomen?",
"email_subject": null,
"attachment": {
"name": "offerte.pdf",
"mime_type": "application/pdf",
"size": 24680
},
"whatsapp_status": null,
"created_at": "2026-09-14T10:15:00Z"
}
}Erreurs possibles
-
403
insufficient_scope— Cette clé API n'a pas accès à cette action. -
422
validation_failed— Les données saisies ne sont pas valides. -
422
unknown_field— Les données contiennent un champ inconnu. -
415
unsupported_media_type— Ce format n'est pas pris en charge. -
413
payload_too_large— Le corps de la requête est trop volumineux. -
404
not_found— Introuvable. -
409
invalid_state_transition— Cette action n'est pas possible dans le statut actuel. -
409
conflict— Ceci est en conflit avec l'état actuel. -
403
account_suspended— Le compte de cette entreprise est bloqué. -
429
rate_limited— Trop de requêtes. -
422
idempotency_key_reused— Cette Idempotency-Key a déjà été utilisée pour une autre requête. -
409
idempotency_in_progress— Une requête avec cette Idempotency-Key est encore en cours.
Clôturer la conversation
/api/v1/conversations/{conversation}/close
Clôture la conversation, comme le bouton dans la boîte de réception. Une conversation déjà clôturée ne change pas.
- Scope
-
messages.send— Envoyer des messages aux clients et clôturer des conversations - Fonctionnalité requise
chat_widget|email|whatsapp
Envoyez une Idempotency-Key : une nouvelle tentative après un délai d'attente ne crée alors jamais de doublon.
Paramètres de chemin
| Nom | Type | Description |
|---|---|---|
conversation obligatoire |
string (uuid) | L'id (UUID) de la conversation. |
Exemple de requête
curl -X POST "https://app.klantly.com/api/v1/conversations/9d3f6c1e-4b2a-4c8e-9f1a-2b3c4d5e6f70/close" \
-H "Authorization: Bearer $KLANTLY_API_KEY" \
-H "Idempotency-Key: 6f1c2d3e-4a5b-4c6d-8e7f-9a0b1c2d3e4f"$client = new \GuzzleHttp\Client([
'base_uri' => 'https://app.klantly.com/api/v1/',
'headers' => ['Authorization' => 'Bearer ' . getenv('KLANTLY_API_KEY')],
]);
$response = $client->request('POST', 'conversations/9d3f6c1e-4b2a-4c8e-9f1a-2b3c4d5e6f70/close', [
'headers' => [
'Idempotency-Key' => '6f1c2d3e-4a5b-4c6d-8e7f-9a0b1c2d3e4f',
],
]);
$data = json_decode((string) $response->getBody(), true)['data'];const response = await fetch('https://app.klantly.com/api/v1/conversations/9d3f6c1e-4b2a-4c8e-9f1a-2b3c4d5e6f70/close', {
method: 'POST',
headers: {
Authorization: `Bearer ${process.env.KLANTLY_API_KEY}`,
'Idempotency-Key': '6f1c2d3e-4a5b-4c6d-8e7f-9a0b1c2d3e4f',
},
});
const { data } = await response.json();import os
import requests
response = requests.post(
"https://app.klantly.com/api/v1/conversations/9d3f6c1e-4b2a-4c8e-9f1a-2b3c4d5e6f70/close",
headers={
"Authorization": f"Bearer {os.environ['KLANTLY_API_KEY']}",
"Idempotency-Key": "6f1c2d3e-4a5b-4c6d-8e7f-9a0b1c2d3e4f",
},
)
data = response.json()["data"]Réponse 200
{
"data": {
"object": "conversation",
"id": "9d3f9a12-6b7c-4d8e-9f01-a2b3c4d5e6f1",
"status": "open",
"channel": "web",
"priority": "normal",
"subject": "Vraag over mijn offerte",
"summary": null,
"page_url": "https://example.com/verandas",
"customer_id": "9d3f6c1e-4b2a-4c8e-9f1a-2b3c4d5e6f70",
"customer": {
"name": "Jan de Vries",
"email": "jan@example.com",
"phone": "+31 6 12345678"
},
"assigned_user_id": null,
"quote_id": null,
"invoice_id": null,
"appointment_id": null,
"message_count": 4,
"last_message_at": null,
"closed_at": null,
"created_at": "2026-09-14T10:15:00Z",
"updated_at": "2026-09-14T10:15:00Z"
}
}Erreurs possibles
-
403
insufficient_scope— Cette clé API n'a pas accès à cette action. -
404
not_found— Introuvable. -
422
idempotency_key_reused— Cette Idempotency-Key a déjà été utilisée pour une autre requête. -
409
idempotency_in_progress— Une requête avec cette Idempotency-Key est encore en cours.
L'objet
Tous les champs sont toujours présents ; un champ sans valeur vaut null.
| Champ | Type | Description |
|---|---|---|
object |
string | Toujours "conversation". |
id |
string (uuid) | Id de la conversation. |
status |
string | open, waiting_on_customer, waiting_on_team, snoozed ou closed. l'une des valeurs : open, waiting_on_customer, waiting_on_team, snoozed, closed |
channel |
string | Où se déroule la conversation : web (widget de chat), whatsapp ou email. l'une des valeurs : web, whatsapp, email |
priority |
string | low, normal, high ou urgent. peut être vide (null) · l'une des valeurs : low, normal, high, urgent |
subject |
string | L'objet ; pour un e-mail, la ligne d'objet. peut être vide (null) |
summary |
string | Un court résumé de la conversation, s'il y en a un. peut être vide (null) |
page_url |
string | La page où le client a démarré le chat. peut être vide (null) |
customer_id |
string (uuid) | Le client auquel cette conversation appartient, si connu. peut être vide (null) |
customer |
object | Les coordonnées telles quelles pour cette conversation. |
customer.name |
string | Nom du client. peut être vide (null) |
customer.email |
string | Adresse e-mail du client. peut être vide (null) |
customer.phone |
string | Numéro de téléphone du client ; sur WhatsApp, le numéro depuis lequel il écrit. peut être vide (null) |
assigned_user_id |
string | Le collaborateur qui traite cette conversation. peut être vide (null) |
quote_id |
string (uuid) | Le devis auquel cette conversation se rapporte, le cas échéant. peut être vide (null) |
invoice_id |
string (uuid) | La facture à laquelle cette conversation se rapporte, le cas échéant. peut être vide (null) |
appointment_id |
string (uuid) | Le rendez-vous auquel cette conversation se rapporte, le cas échéant. peut être vide (null) |
message_count |
integer | Le nombre de messages dans cette conversation. peut être vide (null) |
last_message_at |
string (date-time) | Quand le dernier message est arrivé. peut être vide (null) |
closed_at |
string (date-time) | Quand la conversation a été clôturée. peut être vide (null) |
created_at |
string (date-time) | Quand la conversation a commencé. |
updated_at |
string (date-time) | Quand la conversation a changé pour la dernière fois. |