API-referentie
Inbox
Gesprekken met klanten via de chatwidget, WhatsApp en e-mail, met hun berichten. Lees mee, antwoord namens het bedrijf en sluit een gesprek af.
Endpoints
-
GET
/conversationsGesprekken opvragen -
GET
/conversations/{conversation}Gesprek ophalen -
GET
/conversations/{conversation}/messagesBerichten opvragen -
POST
/conversations/{conversation}/messagesBericht sturen -
POST
/conversations/{conversation}/closeGesprek sluiten
Gesprekken opvragen
/api/v1/conversations
Een lijst van gesprekken, laatste bericht eerst. Filter op status, kanaal, klant of wijzigingsdatum. Met filter[status]=open haal je op wat er nog open staat.
- Scope
-
messages.read— Gesprekken en berichten lezen uit de inbox - Vereiste functie
chat_widget|email|whatsapp
Queryparameters
| Naam | Type | Omschrijving |
|---|---|---|
limit
|
integer | Aantal resultaten per pagina. van 1 tot 100 · standaard: 50 |
cursor
|
string | De next_cursor of prev_cursor uit meta van het vorige antwoord. |
sort
|
string | Sortering op created_at of updated_at; een min-teken ervoor is aflopend. een van: -last_message_at, last_message_at, -created_at, created_at, -updated_at, updated_at · standaard: -last_message_at |
filter[status]
|
string | Alleen gesprekken met deze status: open, waiting_on_customer, waiting_on_team, snoozed of closed. een van: open, waiting_on_customer, waiting_on_team, snoozed, closed |
filter[channel]
|
string | Alleen gesprekken via dit kanaal: web (chatwidget), whatsapp of email. een van: web, whatsapp, email |
filter[customer_id]
|
string (uuid) | Alleen wat bij deze klant hoort. |
filter[updated_since]
|
string (date-time) | Alleen wat sinds dit tijdstip is gewijzigd: ISO 8601 mét tijdzone, bijvoorbeeld 2026-09-14T10:15:00Z. Handig om te synchroniseren. |
Voorbeeldverzoek
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"]Antwoord 200
Het antwoord is een lijst met cursorpaginering: data bevat de objecten, meta de paginering.
{
"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
}
}Mogelijke fouten
-
403
insufficient_scope— Deze API-sleutel heeft geen toegang tot deze actie. -
422
validation_failed— De invoer is ongeldig.
Gesprek ophalen
/api/v1/conversations/{conversation}
Eén gesprek op id, met de klantgegevens, het kanaal en het aantal berichten.
- Scope
-
messages.read— Gesprekken en berichten lezen uit de inbox - Vereiste functie
chat_widget|email|whatsapp
Padparameters
| Naam | Type | Omschrijving |
|---|---|---|
conversation verplicht |
string (uuid) | De id (UUID) van het gesprek. |
Voorbeeldverzoek
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"]Antwoord 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"
}
}Mogelijke fouten
-
403
insufficient_scope— Deze API-sleutel heeft geen toegang tot deze actie. -
404
not_found— Niet gevonden.
Berichten opvragen
/api/v1/conversations/{conversation}/messages
De berichten van een gesprek, oudste eerst, zodat je het gesprek van boven naar beneden leest. Met sort=-created_at krijg je het nieuwste eerst.
- Scope
-
messages.read— Gesprekken en berichten lezen uit de inbox - Vereiste functie
chat_widget|email|whatsapp
Padparameters
| Naam | Type | Omschrijving |
|---|---|---|
conversation verplicht |
string (uuid) | De id (UUID) van het gesprek. |
Queryparameters
| Naam | Type | Omschrijving |
|---|---|---|
limit
|
integer | Aantal resultaten per pagina. van 1 tot 100 · standaard: 50 |
cursor
|
string | De next_cursor of prev_cursor uit meta van het vorige antwoord. |
sort
|
string | created_at (standaard) leest het gesprek van boven naar beneden, -created_at toont het nieuwste eerst. een van: created_at, -created_at · standaard: created_at |
Voorbeeldverzoek
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"]Antwoord 200
Het antwoord is een lijst met cursorpaginering: data bevat de objecten, meta de paginering.
{
"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
}
}Mogelijke fouten
-
403
insufficient_scope— Deze API-sleutel heeft geen toegang tot deze actie. -
404
not_found— Niet gevonden. -
422
validation_failed— De invoer is ongeldig.
Bericht sturen
/api/v1/conversations/{conversation}/messages
Stuurt een bericht naar de klant over het kanaal van het gesprek: chat, WhatsApp of e-mail. Neemt het kanaal het bericht niet aan, dan wordt er niets bewaard en volgt 409 conflict — bij WhatsApp is dan meestal het venster van 24 uur verlopen. Antwoorden vraagt de functie van dat kanaal, en de AI-agent gaat op dit gesprek uit, net als wanneer een medewerker antwoordt. Uitgaande berichten hebben een rem tegen misbruik: maximaal 250 per uur per bedrijf (samen met offerte- en factuurmail) en hoogstens 20 per uur in hetzelfde gesprek via de API. Daarboven volgt 429 rate_limited.
- Scope
-
messages.send— Berichten naar klanten sturen en gesprekken sluiten - Vereiste functie
chat_widget|email|whatsapp
Stuur een Idempotency-Key mee, dan maakt een nieuwe poging na een time-out geen dubbel record.
Padparameters
| Naam | Type | Omschrijving |
|---|---|---|
conversation verplicht |
string (uuid) | De id (UUID) van het gesprek. |
Body (JSON)
| Veld | Type | Omschrijving |
|---|---|---|
body
verplicht
|
string | De tekst van het bericht. maximaal 10000 tekens |
Voorbeeldverzoek
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"]Antwoord 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"
}
}Mogelijke fouten
-
403
insufficient_scope— Deze API-sleutel heeft geen toegang tot deze actie. -
422
validation_failed— De invoer is ongeldig. -
422
unknown_field— De invoer bevat een onbekend veld. -
415
unsupported_media_type— Dit formaat wordt niet ondersteund. -
413
payload_too_large— De body van het verzoek is te groot. -
404
not_found— Niet gevonden. -
409
invalid_state_transition— Deze actie kan niet in de huidige status. -
409
conflict— Dit botst met de huidige toestand. -
403
account_suspended— Het account van dit bedrijf is geblokkeerd. -
429
rate_limited— Te veel verzoeken. -
422
idempotency_key_reused— Deze Idempotency-Key is al gebruikt voor een ander verzoek. -
409
idempotency_in_progress— Een verzoek met deze Idempotency-Key is nog bezig.
Gesprek sluiten
/api/v1/conversations/{conversation}/close
Sluit het gesprek af, zoals de knop in de inbox. Een al gesloten gesprek verandert niet.
- Scope
-
messages.send— Berichten naar klanten sturen en gesprekken sluiten - Vereiste functie
chat_widget|email|whatsapp
Stuur een Idempotency-Key mee, dan maakt een nieuwe poging na een time-out geen dubbel record.
Padparameters
| Naam | Type | Omschrijving |
|---|---|---|
conversation verplicht |
string (uuid) | De id (UUID) van het gesprek. |
Voorbeeldverzoek
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"]Antwoord 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"
}
}Mogelijke fouten
-
403
insufficient_scope— Deze API-sleutel heeft geen toegang tot deze actie. -
404
not_found— Niet gevonden. -
422
idempotency_key_reused— Deze Idempotency-Key is al gebruikt voor een ander verzoek. -
409
idempotency_in_progress— Een verzoek met deze Idempotency-Key is nog bezig.
Het object
Alle velden zijn altijd aanwezig; een veld zonder waarde is null.
| Veld | Type | Omschrijving |
|---|---|---|
object |
string | Altijd "conversation". |
id |
string (uuid) | Id van het gesprek. |
status |
string | open, waiting_on_customer, waiting_on_team, snoozed of closed. een van: open, waiting_on_customer, waiting_on_team, snoozed, closed |
channel |
string | Waar het gesprek loopt: web (chatwidget), whatsapp of email. een van: web, whatsapp, email |
priority |
string | low, normal, high of urgent. kan leeg zijn (null) · een van: low, normal, high, urgent |
subject |
string | Het onderwerp, bij e-mail de onderwerpregel. kan leeg zijn (null) |
summary |
string | Korte samenvatting van het gesprek, als die er is. kan leeg zijn (null) |
page_url |
string | De pagina waar de klant de chat begon. kan leeg zijn (null) |
customer_id |
string (uuid) | De klant bij wie dit gesprek hoort, als die bekend is. kan leeg zijn (null) |
customer |
object | De contactgegevens zoals ze bij dit gesprek horen. |
customer.name |
string | Naam van de klant. kan leeg zijn (null) |
customer.email |
string | E-mailadres van de klant. kan leeg zijn (null) |
customer.phone |
string | Telefoonnummer van de klant; bij WhatsApp het nummer waarmee hij schrijft. kan leeg zijn (null) |
assigned_user_id |
string | De medewerker die dit gesprek behandelt. kan leeg zijn (null) |
quote_id |
string (uuid) | De offerte waar dit gesprek bij hoort, als die er is. kan leeg zijn (null) |
invoice_id |
string (uuid) | De factuur waar dit gesprek bij hoort, als die er is. kan leeg zijn (null) |
appointment_id |
string (uuid) | De afspraak waar dit gesprek bij hoort, als die er is. kan leeg zijn (null) |
message_count |
integer | Het aantal berichten in dit gesprek. kan leeg zijn (null) |
last_message_at |
string (date-time) | Wanneer het laatste bericht kwam. kan leeg zijn (null) |
closed_at |
string (date-time) | Wanneer het gesprek is gesloten. kan leeg zijn (null) |
created_at |
string (date-time) | Wanneer het gesprek begon. |
updated_at |
string (date-time) | Wanneer het gesprek voor het laatst wijzigde. |