API-referentie
Reviews
Reviews van klanten en de verzoeken om er een te schrijven. Lezen kan volledig; een review zelf aanmaken bewust niet — die hoort van de klant te komen.
Endpoints
-
GET
/reviewsReviews opvragen -
GET
/reviews/{review}Review ophalen -
GET
/review-requestsReviewverzoeken opvragen -
POST
/review-requestsReviewverzoek versturen
Reviews opvragen
/api/v1/reviews
Een lijst van reviews, nieuwste eerst. Filter op status, bron, score, klant of wijzigingsdatum. Met filter[status]=published haal je op wat openbaar staat.
- Scope
-
reviews.read— Reviews en reviewverzoeken lezen - Vereiste functie
reviews
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: -reviewed_at, reviewed_at, -created_at, created_at, -updated_at, updated_at · standaard: -reviewed_at |
filter[status]
|
string | Alleen reviews met deze status: published (openbaar) of hidden (verborgen). een van: published, hidden |
filter[source]
|
string | Alleen reviews uit deze bron: request (via een reviewverzoek), manual (zelf ingevoerd), configurator of google. een van: request, manual, configurator, google |
filter[rating]
|
integer | Alleen reviews met deze score (1 tot en met 5). van 1 tot 5 |
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/reviews?filter[status]=published&sort=-reviewed_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', 'reviews', [
'query' => [
'filter[status]' => 'published',
'sort' => '-reviewed_at',
],
]);
$data = json_decode((string) $response->getBody(), true)['data'];const response = await fetch('https://app.klantly.com/api/v1/reviews?filter[status]=published&sort=-reviewed_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/reviews",
headers={
"Authorization": f"Bearer {os.environ['KLANTLY_API_KEY']}",
},
params={
"filter[status]": "published",
"sort": "-reviewed_at"
},
)
data = response.json()["data"]Antwoord 200
Het antwoord is een lijst met cursorpaginering: data bevat de objecten, meta de paginering.
{
"data": [
{
"object": "review",
"id": "9d3f9c34-8d9e-4f01-9123-c4d5e6f7a8b3",
"status": "published",
"hidden_reason": null,
"source": "request",
"rating": 5,
"comment": "Strakke veranda, netjes geplaatst en goed opgeruimd.",
"author": {
"name": "Jan de Vries",
"city": "Utrecht"
},
"customer_id": "9d3f6c1e-4b2a-4c8e-9f1a-2b3c4d5e6f70",
"language": "nl",
"is_verified": true,
"consent_publish": true,
"reply": null,
"replied_at": null,
"reviewed_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.
Review ophalen
/api/v1/reviews/{review}
Eén review op id, met de score, de tekst, de schrijver en het antwoord van het bedrijf.
- Scope
-
reviews.read— Reviews en reviewverzoeken lezen - Vereiste functie
reviews
Padparameters
| Naam | Type | Omschrijving |
|---|---|---|
review verplicht |
string (uuid) | De id (UUID) van de review. |
Voorbeeldverzoek
curl "https://app.klantly.com/api/v1/reviews/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', 'reviews/9d3f6c1e-4b2a-4c8e-9f1a-2b3c4d5e6f70');
$data = json_decode((string) $response->getBody(), true)['data'];const response = await fetch('https://app.klantly.com/api/v1/reviews/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/reviews/9d3f6c1e-4b2a-4c8e-9f1a-2b3c4d5e6f70",
headers={
"Authorization": f"Bearer {os.environ['KLANTLY_API_KEY']}",
},
)
data = response.json()["data"]Antwoord 200
{
"data": {
"object": "review",
"id": "9d3f9c34-8d9e-4f01-9123-c4d5e6f7a8b3",
"status": "published",
"hidden_reason": null,
"source": "request",
"rating": 5,
"comment": "Strakke veranda, netjes geplaatst en goed opgeruimd.",
"author": {
"name": "Jan de Vries",
"city": "Utrecht"
},
"customer_id": "9d3f6c1e-4b2a-4c8e-9f1a-2b3c4d5e6f70",
"language": "nl",
"is_verified": true,
"consent_publish": true,
"reply": null,
"replied_at": null,
"reviewed_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.
Reviewverzoeken opvragen
/api/v1/review-requests
De verstuurde en openstaande reviewverzoeken, nieuwste eerst, met hun status en de link voor de klant.
- Scope
-
reviews.read— Reviews en reviewverzoeken lezen - Vereiste functie
reviews
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. |
filter[status]
|
string | Alleen verzoeken met deze status: scheduled, sent, opened, completed, failed, cancelled of expired. een van: scheduled, sent, opened, completed, failed, cancelled, expired |
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/review-requests" \
-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', 'review-requests');
$data = json_decode((string) $response->getBody(), true)['data'];const response = await fetch('https://app.klantly.com/api/v1/review-requests', {
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/review-requests",
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": "review_request",
"id": "9d3f9d45-9e0f-4012-a234-d5e6f7a8b9c4",
"status": "sent",
"channel": "email",
"trigger": "manual",
"customer_id": "9d3f6c1e-4b2a-4c8e-9f1a-2b3c4d5e6f70",
"recipient": {
"name": "Jan de Vries",
"email": "jan@example.com",
"phone": null
},
"language": "nl",
"url": "https://app.klantly.com/review/Xk2p9Qm4Rt7vB1nC8dE5fG3hJ6kL0mN2pQ4rS7tU",
"review_id": null,
"scheduled_at": null,
"sent_at": null,
"opened_at": null,
"completed_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.
Reviewverzoek versturen
/api/v1/review-requests
Vraagt een klant om een review. Met channel=email of whatsapp stuurt Klantly het bericht met het sjabloon van het bedrijf; met channel=link maak je alleen de link aan en deel je hem zelf. Geef customer_id mee, of vul name plus email of phone in. Dezelfde regels als in het scherm: geen tweede openstaand verzoek aan dezelfde klant, de afkoelperiode van het bedrijf, en niemand die zich heeft afgemeld — anders volgt 409 conflict.
- Scope
-
reviews.write— Reviewverzoeken naar klanten sturen (een review zelf aanmaken kan niet) - Vereiste functie
reviews
Stuur een Idempotency-Key mee, dan maakt een nieuwe poging na een time-out geen dubbel record.
Body (JSON)
| Veld | Type | Omschrijving |
|---|---|---|
customer_id
optioneel
|
string (uuid) | De klant die het verzoek krijgt. |
name
optioneel
|
string | Naam van de ontvanger. Nodig als je geen customer_id meegeeft. maximaal 120 tekens |
email
optioneel
|
string (email) | E-mailadres van de ontvanger. Nodig bij channel=email. maximaal 255 tekens |
phone
optioneel
|
string | Telefoonnummer van de ontvanger. Nodig bij channel=whatsapp. maximaal 50 tekens |
channel
optioneel
|
string | Hoe het verzoek bij de klant komt: email, whatsapp of link (dan verstuurt Klantly niets). een van: email, whatsapp, link |
language
optioneel
|
string | De taal van het bericht aan de klant. een van: nl, en, de, fr |
Voorbeeldverzoek
curl -X POST "https://app.klantly.com/api/v1/review-requests" \
-H "Authorization: Bearer $KLANTLY_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: 6f1c2d3e-4a5b-4c6d-8e7f-9a0b1c2d3e4f" \
-d '{
"customer_id": "9d3f6c1e-4b2a-4c8e-9f1a-2b3c4d5e6f70",
"channel": "email"
}'$client = new \GuzzleHttp\Client([
'base_uri' => 'https://app.klantly.com/api/v1/',
'headers' => ['Authorization' => 'Bearer ' . getenv('KLANTLY_API_KEY')],
]);
$response = $client->request('POST', 'review-requests', [
'headers' => [
'Idempotency-Key' => '6f1c2d3e-4a5b-4c6d-8e7f-9a0b1c2d3e4f',
],
'json' => [
'customer_id' => '9d3f6c1e-4b2a-4c8e-9f1a-2b3c4d5e6f70',
'channel' => 'email',
],
]);
$data = json_decode((string) $response->getBody(), true)['data'];const response = await fetch('https://app.klantly.com/api/v1/review-requests', {
method: 'POST',
headers: {
Authorization: `Bearer ${process.env.KLANTLY_API_KEY}`,
'Content-Type': 'application/json',
'Idempotency-Key': '6f1c2d3e-4a5b-4c6d-8e7f-9a0b1c2d3e4f',
},
body: JSON.stringify({
"customer_id": "9d3f6c1e-4b2a-4c8e-9f1a-2b3c4d5e6f70",
"channel": "email"
}),
});
const { data } = await response.json();import os
import requests
response = requests.post(
"https://app.klantly.com/api/v1/review-requests",
headers={
"Authorization": f"Bearer {os.environ['KLANTLY_API_KEY']}",
"Idempotency-Key": "6f1c2d3e-4a5b-4c6d-8e7f-9a0b1c2d3e4f",
},
json={
"customer_id": "9d3f6c1e-4b2a-4c8e-9f1a-2b3c4d5e6f70",
"channel": "email"
},
)
data = response.json()["data"]Antwoord 201
{
"data": {
"object": "review_request",
"id": "9d3f9d45-9e0f-4012-a234-d5e6f7a8b9c4",
"status": "sent",
"channel": "email",
"trigger": "manual",
"customer_id": "9d3f6c1e-4b2a-4c8e-9f1a-2b3c4d5e6f70",
"recipient": {
"name": "Jan de Vries",
"email": "jan@example.com",
"phone": null
},
"language": "nl",
"url": "https://app.klantly.com/review/Xk2p9Qm4Rt7vB1nC8dE5fG3hJ6kL0mN2pQ4rS7tU",
"review_id": null,
"scheduled_at": null,
"sent_at": null,
"opened_at": null,
"completed_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. -
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. -
409
conflict— Dit botst met de huidige toestand. -
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 "review". |
id |
string (uuid) | Id van de review. |
status |
string | published (openbaar) of hidden (verborgen). een van: published, hidden |
hidden_reason |
string | Waarom de review verborgen is, als dat zo is. kan leeg zijn (null) · een van: spam, offensive, not_a_customer, privacy, duplicate, other |
source |
string | Waar de review vandaan komt: request, manual, configurator of google. een van: request, manual, configurator, google |
rating |
integer | De score, 1 tot en met 5. van 1 tot 5 |
comment |
string | Wat de klant schreef. kan leeg zijn (null) |
author |
object | De schrijver, zoals hij openbaar getoond wordt. |
author.name |
string | Naam van de schrijver. kan leeg zijn (null) |
author.city |
string | Woonplaats van de schrijver. kan leeg zijn (null) |
customer_id |
string (uuid) | De klant die de review schreef, als die bekend is. kan leeg zijn (null) |
language |
string | De taal waarin de review is geschreven. kan leeg zijn (null) · een van: nl, en, de, fr |
is_verified |
boolean | True als de review via een reviewverzoek van Klantly is ingevuld: de schrijver is dan aantoonbaar klant. |
consent_publish |
boolean | Of de schrijver toestemming gaf om de review te tonen. |
reply |
string | Het antwoord van het bedrijf op deze review. kan leeg zijn (null) |
replied_at |
string (date-time) | Wanneer het bedrijf antwoordde. kan leeg zijn (null) |
reviewed_at |
string (date-time) | Wanneer de review is geschreven. kan leeg zijn (null) |
created_at |
string (date-time) | Wanneer de review in Klantly kwam. |
updated_at |
string (date-time) | Wanneer de review voor het laatst wijzigde. |