Klantly Developers

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

Lister les conversations

GET /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

NomTypeDescription
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
curl "https://app.klantly.com/api/v1/conversations?filter[status]=open&sort=-last_message_at" \
  -H "Authorization: Bearer $KLANTLY_API_KEY"
PHP
$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'];
JavaScript
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();
Python
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.

Exemple de réponse
{
  "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

En outre, chaque endpoint peut renvoyer les erreurs générales, comme une clé invalide ou une limite atteinte. Voir tous les codes d'erreur.

Obtenir une conversation

GET /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

NomTypeDescription
conversation obligatoire string (uuid) L'id (UUID) de la conversation.

Exemple de requête

cURL
curl "https://app.klantly.com/api/v1/conversations/9d3f6c1e-4b2a-4c8e-9f1a-2b3c4d5e6f70" \
  -H "Authorization: Bearer $KLANTLY_API_KEY"
PHP
$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'];
JavaScript
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();
Python
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

Exemple de réponse
{
  "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

En outre, chaque endpoint peut renvoyer les erreurs générales, comme une clé invalide ou une limite atteinte. Voir tous les codes d'erreur.

Lister les messages

GET /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

NomTypeDescription
conversation obligatoire string (uuid) L'id (UUID) de la conversation.

Paramètres de requête

NomTypeDescription
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
curl "https://app.klantly.com/api/v1/conversations/9d3f6c1e-4b2a-4c8e-9f1a-2b3c4d5e6f70/messages" \
  -H "Authorization: Bearer $KLANTLY_API_KEY"
PHP
$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'];
JavaScript
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();
Python
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.

Exemple de réponse
{
  "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

En outre, chaque endpoint peut renvoyer les erreurs générales, comme une clé invalide ou une limite atteinte. Voir tous les codes d'erreur.

Envoyer un message

POST /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

NomTypeDescription
conversation obligatoire string (uuid) L'id (UUID) de la conversation.

Corps (JSON)

ChampTypeDescription
body obligatoire string Le texte du message. au maximum 10000 caractères

Exemple de requête

cURL
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."
}'
PHP
$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'];
JavaScript
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();
Python
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

Exemple de réponse
{
  "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

En outre, chaque endpoint peut renvoyer les erreurs générales, comme une clé invalide ou une limite atteinte. Voir tous les codes d'erreur.

Clôturer la conversation

POST /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

NomTypeDescription
conversation obligatoire string (uuid) L'id (UUID) de la conversation.

Exemple de requête

cURL
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"
PHP
$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'];
JavaScript
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();
Python
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

Exemple de réponse
{
  "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

En outre, chaque endpoint peut renvoyer les erreurs générales, comme une clé invalide ou une limite atteinte. Voir tous les codes d'erreur.

L'objet

Tous les champs sont toujours présents ; un champ sans valeur vaut null.

ChampTypeDescription
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.