Référence de l'API
Rendez-vous
Les rendez-vous de l’agenda : planifier, déplacer, confirmer, annuler et terminer, et envoyer un message au client.
Endpoints
-
GET
/appointmentsLister les rendez-vous -
GET
/appointments/{appointment}Récupérer un rendez-vous -
POST
/appointmentsPlanifier un rendez-vous -
PATCH
/appointments/{appointment}Modifier un rendez-vous -
POST
/appointments/{appointment}/confirmConfirmer un rendez-vous -
POST
/appointments/{appointment}/cancelAnnuler un rendez-vous -
POST
/appointments/{appointment}/completeTerminer un rendez-vous -
POST
/appointments/{appointment}/notifyEnvoyer un message au client -
DELETE
/appointments/{appointment}Supprimer un rendez-vous
Lister les rendez-vous
/api/v1/appointments
Une liste de rendez-vous, du plus récent au plus ancien. Filtrez par statut, client, utilisateur, heure de début ou date de modification. Pour l'ordre de l'agenda, utilisez filter[starts_from] et filter[starts_until] et triez vous-même sur starts_at.
- Scope
-
appointments.read— Lire les rendez-vous (avec le nom, l'e-mail et le téléphone du client), les types de rendez-vous et les disponibilités - Fonctionnalité requise
appointments
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 signifie décroissant. l'une des valeurs : -created_at, created_at, -updated_at, updated_at · par défaut : -created_at |
filter[status]
|
string | Uniquement les rendez-vous de ce statut : pending (pas encore confirmé), confirmed, cancelled ou completed. l'une des valeurs : pending, confirmed, cancelled, completed |
filter[customer_id]
|
string (uuid) | Uniquement ce qui appartient à ce client. |
filter[user_id]
|
string | Uniquement les rendez-vous de cet utilisateur (l’id de Lister les utilisateurs). |
filter[starts_from]
|
string (date-time) | Uniquement les rendez-vous qui commencent à ce moment ou après : ISO 8601 avec fuseau horaire. |
filter[starts_until]
|
string (date-time) | Uniquement les rendez-vous qui commencent avant ce moment : ISO 8601 avec fuseau horaire. |
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. Prévoyez un chevauchement de quelques minutes avec votre moment précédent, car l'horloge de votre système et celle de Klantly ne sont pas exactement synchronisées, et car une modification juste après votre moment précédent tomberait sinon de justesse en dehors. La limite est inclusive : un élément modifié exactement à cet instant est inclus. |
Exemple de requête
curl "https://app.klantly.com/api/v1/appointments?filter[starts_from]=2026-10-01T00%3A00%3A00Z&sort=created_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', 'appointments', [
'query' => [
'filter[starts_from]' => '2026-10-01T00:00:00Z',
'sort' => 'created_at',
],
]);
$data = json_decode((string) $response->getBody(), true)['data'];const response = await fetch('https://app.klantly.com/api/v1/appointments?filter[starts_from]=2026-10-01T00%3A00%3A00Z&sort=created_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/appointments",
headers={
"Authorization": f"Bearer {os.environ['KLANTLY_API_KEY']}",
},
params={
"filter[starts_from]": "2026-10-01T00:00:00Z",
"sort": "created_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": "appointment",
"id": "9d3f7d83-4f8b-4a0e-9d5c-6b7f8a9bacb4",
"title": "Inmeten veranda",
"description": null,
"status": "confirmed",
"source": "klantly",
"starts_at": "2026-10-01T08:00:00Z",
"ends_at": "2026-10-01T09:00:00Z",
"all_day": false,
"location": "Dorpsstraat 1, Utrecht",
"customer_id": "9d3f6c1e-4b2a-4c8e-9f1a-2b3c4d5e6f70",
"contact": {
"name": "Jan de Vries",
"email": "jan@example.com",
"phone": "+31 6 12345678"
},
"user_id": "usr_0k3j9x21m4zq8p",
"appointment_type_id": "9d3f7ea4-5a9c-4b1f-8e6d-7c8a9bacbdc5",
"deal_id": "9d3f7a20-1c5e-4d7b-8a2f-3e4c5d6f7a81",
"quote_id": null,
"invoice_id": null,
"notes": null,
"cancellation_reason": null,
"confirmed_at": "2026-09-14T10:15:00Z",
"cancelled_at": null,
"rescheduled_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.
Récupérer un rendez-vous
/api/v1/appointments/{appointment}
Un rendez-vous par id. La réponse contient un ETag que vous pouvez renvoyer dans If-Match lors d’une modification.
- Scope
-
appointments.read— Lire les rendez-vous (avec le nom, l'e-mail et le téléphone du client), les types de rendez-vous et les disponibilités - Fonctionnalité requise
appointments
Paramètres de chemin
| Nom | Type | Description |
|---|---|---|
appointment obligatoire |
string (uuid) | L’id (UUID) du rendez-vous. |
Exemple de requête
curl "https://app.klantly.com/api/v1/appointments/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', 'appointments/9d3f6c1e-4b2a-4c8e-9f1a-2b3c4d5e6f70');
$data = json_decode((string) $response->getBody(), true)['data'];const response = await fetch('https://app.klantly.com/api/v1/appointments/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/appointments/9d3f6c1e-4b2a-4c8e-9f1a-2b3c4d5e6f70",
headers={
"Authorization": f"Bearer {os.environ['KLANTLY_API_KEY']}",
},
)
data = response.json()["data"]Réponse 200
{
"data": {
"object": "appointment",
"id": "9d3f7d83-4f8b-4a0e-9d5c-6b7f8a9bacb4",
"title": "Inmeten veranda",
"description": null,
"status": "confirmed",
"source": "klantly",
"starts_at": "2026-10-01T08:00:00Z",
"ends_at": "2026-10-01T09:00:00Z",
"all_day": false,
"location": "Dorpsstraat 1, Utrecht",
"customer_id": "9d3f6c1e-4b2a-4c8e-9f1a-2b3c4d5e6f70",
"contact": {
"name": "Jan de Vries",
"email": "jan@example.com",
"phone": "+31 6 12345678"
},
"user_id": "usr_0k3j9x21m4zq8p",
"appointment_type_id": "9d3f7ea4-5a9c-4b1f-8e6d-7c8a9bacbdc5",
"deal_id": "9d3f7a20-1c5e-4d7b-8a2f-3e4c5d6f7a81",
"quote_id": null,
"invoice_id": null,
"notes": null,
"cancellation_reason": null,
"confirmed_at": "2026-09-14T10:15:00Z",
"cancelled_at": null,
"rescheduled_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.
Planifier un rendez-vous
/api/v1/appointments
Planifie un rendez-vous avec un client ; le nom, l’e-mail et le téléphone viennent du client. Sans ends_at, le rendez-vous dure autant que son type, sinon la durée par défaut des paramètres des rendez-vous. Klantly ne vérifie pas la disponibilité ici : votre planning fait foi. L’API n’envoie elle-même aucun e-mail au client ; utilisez pour cela Envoyer un message au client. Si l’entreprise a des automatisations sur « rendez-vous planifié », elles s’exécutent, comme pour un rendez-vous dans l’agenda.
- Scope
-
appointments.write— Créer, modifier, confirmer, annuler et terminer des rendez-vous (les automatisations de l'entreprise s'exécutent aussi) - Fonctionnalité requise
appointments
Envoyez une Idempotency-Key : une nouvelle tentative après un délai d'attente ne crée alors jamais de doublon.
Corps (JSON)
| Champ | Type | Description |
|---|---|---|
customer_id
obligatoire
|
string (uuid) | Le client du rendez-vous. Obligatoire à la création. |
title
facultatif
|
string | Titre du rendez-vous. peut être vide (null) · au maximum 255 caractères · obligatoire sans appointment_type_id |
description
facultatif
|
string | Description. peut être vide (null) · au maximum 2000 caractères |
location
facultatif
|
string | Lieu, par exemple l’adresse du client. peut être vide (null) · au maximum 255 caractères |
starts_at
obligatoire
|
string (date-time) | Début (UTC). Vide pour une invitation où le client doit encore choisir une heure. En entrée : ISO 8601 avec fuseau horaire. |
ends_at
facultatif
|
string (date-time) | Fin (UTC). Sans ends_at à la création : la durée du type de rendez-vous ou la durée par défaut. peut être vide (null) |
all_day
facultatif
|
boolean | Un rendez-vous sur toute la journée. Les heures de la réponse sont en UTC : reconvertissez-les dans le fuseau de l’entreprise (Europe/Amsterdam) pour la date, sinon un rendez-vous commençant à 00:00 tombe la veille. |
appointment_type_id
facultatif
|
string (uuid) | Le type de rendez-vous, ou null. peut être vide (null) |
user_id
facultatif
|
string | L’utilisateur qui a le rendez-vous, ou null. peut être vide (null) |
status
facultatif
|
string | pending (pas encore confirmé), confirmed, cancelled (annulé) ou completed (terminé). À la création : pending ou confirmed (par défaut). l'une des valeurs : pending, confirmed |
notes
facultatif
|
string | Note interne sur le rendez-vous. peut être vide (null) · au maximum 2000 caractères |
Exemple de requête
curl -X POST "https://app.klantly.com/api/v1/appointments" \
-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",
"title": "Inmeten veranda",
"starts_at": "2026-10-01T10:00:00+02:00",
"appointment_type_id": "9d3f7ea4-5a9c-4b1f-8e6d-7c8a9bacbdc5"
}'$client = new \GuzzleHttp\Client([
'base_uri' => 'https://app.klantly.com/api/v1/',
'headers' => ['Authorization' => 'Bearer ' . getenv('KLANTLY_API_KEY')],
]);
$response = $client->request('POST', 'appointments', [
'headers' => [
'Idempotency-Key' => '6f1c2d3e-4a5b-4c6d-8e7f-9a0b1c2d3e4f',
],
'json' => [
'customer_id' => '9d3f6c1e-4b2a-4c8e-9f1a-2b3c4d5e6f70',
'title' => 'Inmeten veranda',
'starts_at' => '2026-10-01T10:00:00+02:00',
'appointment_type_id' => '9d3f7ea4-5a9c-4b1f-8e6d-7c8a9bacbdc5',
],
]);
$data = json_decode((string) $response->getBody(), true)['data'];const response = await fetch('https://app.klantly.com/api/v1/appointments', {
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",
"title": "Inmeten veranda",
"starts_at": "2026-10-01T10:00:00+02:00",
"appointment_type_id": "9d3f7ea4-5a9c-4b1f-8e6d-7c8a9bacbdc5"
}),
});
const { data } = await response.json();import os
import requests
response = requests.post(
"https://app.klantly.com/api/v1/appointments",
headers={
"Authorization": f"Bearer {os.environ['KLANTLY_API_KEY']}",
"Idempotency-Key": "6f1c2d3e-4a5b-4c6d-8e7f-9a0b1c2d3e4f",
},
json={
"customer_id": "9d3f6c1e-4b2a-4c8e-9f1a-2b3c4d5e6f70",
"title": "Inmeten veranda",
"starts_at": "2026-10-01T10:00:00+02:00",
"appointment_type_id": "9d3f7ea4-5a9c-4b1f-8e6d-7c8a9bacbdc5"
},
)
data = response.json()["data"]Réponse 201
{
"data": {
"object": "appointment",
"id": "9d3f7d83-4f8b-4a0e-9d5c-6b7f8a9bacb4",
"title": "Inmeten veranda",
"description": null,
"status": "confirmed",
"source": "klantly",
"starts_at": "2026-10-01T08:00:00Z",
"ends_at": "2026-10-01T09:00:00Z",
"all_day": false,
"location": "Dorpsstraat 1, Utrecht",
"customer_id": "9d3f6c1e-4b2a-4c8e-9f1a-2b3c4d5e6f70",
"contact": {
"name": "Jan de Vries",
"email": "jan@example.com",
"phone": "+31 6 12345678"
},
"user_id": "usr_0k3j9x21m4zq8p",
"appointment_type_id": "9d3f7ea4-5a9c-4b1f-8e6d-7c8a9bacbdc5",
"deal_id": "9d3f7a20-1c5e-4d7b-8a2f-3e4c5d6f7a81",
"quote_id": null,
"invoice_id": null,
"notes": null,
"cancellation_reason": null,
"confirmed_at": "2026-09-14T10:15:00Z",
"cancelled_at": null,
"rescheduled_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. -
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. -
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.
Modifier un rendez-vous
/api/v1/appointments/{appointment}
Ne modifie que les champs envoyés. Un nouveau starts_at est un déplacement : rescheduled_at est renseigné et, sans ends_at, la durée reste identique. Si un rendez-vous sans date reçoit un starts_at, ends_at est ajouté comme à la création ; un ends_at sans heure de début n’est pas possible (422). Pour changer le statut, utilisez confirmer, annuler ou terminer.
- Scope
-
appointments.write— Créer, modifier, confirmer, annuler et terminer des rendez-vous (les automatisations de l'entreprise s'exécutent aussi) - Fonctionnalité requise
appointments
Envoyez l'ETag dans If-Match : vous n'écraserez jamais par erreur une version plus récente.
Paramètres de chemin
| Nom | Type | Description |
|---|---|---|
appointment obligatoire |
string (uuid) | L’id (UUID) du rendez-vous. |
Corps (JSON)
| Champ | Type | Description |
|---|---|---|
title
facultatif
|
string | Titre du rendez-vous. au maximum 255 caractères |
description
facultatif
|
string | Description. peut être vide (null) · au maximum 2000 caractères |
location
facultatif
|
string | Lieu, par exemple l’adresse du client. peut être vide (null) · au maximum 255 caractères |
starts_at
facultatif
|
string (date-time) | Début (UTC). Vide pour une invitation où le client doit encore choisir une heure. En entrée : ISO 8601 avec fuseau horaire. |
ends_at
facultatif
|
string (date-time) | Fin (UTC). Sans ends_at à la création : la durée du type de rendez-vous ou la durée par défaut. |
all_day
facultatif
|
boolean | Un rendez-vous sur toute la journée. Les heures de la réponse sont en UTC : reconvertissez-les dans le fuseau de l’entreprise (Europe/Amsterdam) pour la date, sinon un rendez-vous commençant à 00:00 tombe la veille. |
appointment_type_id
facultatif
|
string (uuid) | Le type de rendez-vous, ou null. peut être vide (null) |
user_id
facultatif
|
string | L’utilisateur qui a le rendez-vous, ou null. peut être vide (null) |
notes
facultatif
|
string | Note interne sur le rendez-vous. peut être vide (null) · au maximum 2000 caractères |
Exemple de requête
curl -X PATCH "https://app.klantly.com/api/v1/appointments/9d3f6c1e-4b2a-4c8e-9f1a-2b3c4d5e6f70" \
-H "Authorization: Bearer $KLANTLY_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"starts_at": "2026-10-02T09:00:00Z"
}'$client = new \GuzzleHttp\Client([
'base_uri' => 'https://app.klantly.com/api/v1/',
'headers' => ['Authorization' => 'Bearer ' . getenv('KLANTLY_API_KEY')],
]);
$response = $client->request('PATCH', 'appointments/9d3f6c1e-4b2a-4c8e-9f1a-2b3c4d5e6f70', [
'json' => [
'starts_at' => '2026-10-02T09:00:00Z',
],
]);
$data = json_decode((string) $response->getBody(), true)['data'];const response = await fetch('https://app.klantly.com/api/v1/appointments/9d3f6c1e-4b2a-4c8e-9f1a-2b3c4d5e6f70', {
method: 'PATCH',
headers: {
Authorization: `Bearer ${process.env.KLANTLY_API_KEY}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
"starts_at": "2026-10-02T09:00:00Z"
}),
});
const { data } = await response.json();import os
import requests
response = requests.patch(
"https://app.klantly.com/api/v1/appointments/9d3f6c1e-4b2a-4c8e-9f1a-2b3c4d5e6f70",
headers={
"Authorization": f"Bearer {os.environ['KLANTLY_API_KEY']}",
},
json={
"starts_at": "2026-10-02T09:00:00Z"
},
)
data = response.json()["data"]Réponse 200
{
"data": {
"object": "appointment",
"id": "9d3f7d83-4f8b-4a0e-9d5c-6b7f8a9bacb4",
"title": "Inmeten veranda",
"description": null,
"status": "confirmed",
"source": "klantly",
"starts_at": "2026-10-01T08:00:00Z",
"ends_at": "2026-10-01T09:00:00Z",
"all_day": false,
"location": "Dorpsstraat 1, Utrecht",
"customer_id": "9d3f6c1e-4b2a-4c8e-9f1a-2b3c4d5e6f70",
"contact": {
"name": "Jan de Vries",
"email": "jan@example.com",
"phone": "+31 6 12345678"
},
"user_id": "usr_0k3j9x21m4zq8p",
"appointment_type_id": "9d3f7ea4-5a9c-4b1f-8e6d-7c8a9bacbdc5",
"deal_id": "9d3f7a20-1c5e-4d7b-8a2f-3e4c5d6f7a81",
"quote_id": null,
"invoice_id": null,
"notes": null,
"cancellation_reason": null,
"confirmed_at": "2026-09-14T10:15:00Z",
"cancelled_at": null,
"rescheduled_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. -
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
conflict— Ceci est en conflit avec l'état actuel. -
412
precondition_failed— L'enregistrement a été modifié entre-temps.
Confirmer un rendez-vous
/api/v1/appointments/{appointment}/confirm
Passe un rendez-vous au statut confirmé. S’il est déjà confirmé, rien ne change.
- Scope
-
appointments.write— Créer, modifier, confirmer, annuler et terminer des rendez-vous (les automatisations de l'entreprise s'exécutent aussi) - Fonctionnalité requise
appointments
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 |
|---|---|---|
appointment obligatoire |
string (uuid) | L’id (UUID) du rendez-vous. |
Exemple de requête
curl -X POST "https://app.klantly.com/api/v1/appointments/9d3f6c1e-4b2a-4c8e-9f1a-2b3c4d5e6f70/confirm" \
-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', 'appointments/9d3f6c1e-4b2a-4c8e-9f1a-2b3c4d5e6f70/confirm', [
'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/appointments/9d3f6c1e-4b2a-4c8e-9f1a-2b3c4d5e6f70/confirm', {
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/appointments/9d3f6c1e-4b2a-4c8e-9f1a-2b3c4d5e6f70/confirm",
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": "appointment",
"id": "9d3f7d83-4f8b-4a0e-9d5c-6b7f8a9bacb4",
"title": "Inmeten veranda",
"description": null,
"status": "confirmed",
"source": "klantly",
"starts_at": "2026-10-01T08:00:00Z",
"ends_at": "2026-10-01T09:00:00Z",
"all_day": false,
"location": "Dorpsstraat 1, Utrecht",
"customer_id": "9d3f6c1e-4b2a-4c8e-9f1a-2b3c4d5e6f70",
"contact": {
"name": "Jan de Vries",
"email": "jan@example.com",
"phone": "+31 6 12345678"
},
"user_id": "usr_0k3j9x21m4zq8p",
"appointment_type_id": "9d3f7ea4-5a9c-4b1f-8e6d-7c8a9bacbdc5",
"deal_id": "9d3f7a20-1c5e-4d7b-8a2f-3e4c5d6f7a81",
"quote_id": null,
"invoice_id": null,
"notes": null,
"cancellation_reason": null,
"confirmed_at": "2026-09-14T10:15:00Z",
"cancelled_at": null,
"rescheduled_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. -
409
conflict— Ceci est en conflit avec l'état actuel. -
409
invalid_state_transition— Cette action n'est pas possible dans le statut actuel. -
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.
Annuler un rendez-vous
/api/v1/appointments/{appointment}/cancel
Annule le rendez-vous, avec un motif facultatif. Un rendez-vous terminé ne peut plus être annulé. Les automatisations sur « rendez-vous annulé » s’exécutent, comme dans l’agenda.
- Scope
-
appointments.write— Créer, modifier, confirmer, annuler et terminer des rendez-vous (les automatisations de l'entreprise s'exécutent aussi) - Fonctionnalité requise
appointments
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 |
|---|---|---|
appointment obligatoire |
string (uuid) | L’id (UUID) du rendez-vous. |
Corps (JSON)
| Champ | Type | Description |
|---|---|---|
reason
facultatif
|
string | Le motif de l’annulation (facultatif). peut être vide (null) · au maximum 500 caractères |
Exemple de requête
curl -X POST "https://app.klantly.com/api/v1/appointments/9d3f6c1e-4b2a-4c8e-9f1a-2b3c4d5e6f70/cancel" \
-H "Authorization: Bearer $KLANTLY_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: 6f1c2d3e-4a5b-4c6d-8e7f-9a0b1c2d3e4f" \
-d '{
"reason": "Klant is verhinderd"
}'$client = new \GuzzleHttp\Client([
'base_uri' => 'https://app.klantly.com/api/v1/',
'headers' => ['Authorization' => 'Bearer ' . getenv('KLANTLY_API_KEY')],
]);
$response = $client->request('POST', 'appointments/9d3f6c1e-4b2a-4c8e-9f1a-2b3c4d5e6f70/cancel', [
'headers' => [
'Idempotency-Key' => '6f1c2d3e-4a5b-4c6d-8e7f-9a0b1c2d3e4f',
],
'json' => [
'reason' => 'Klant is verhinderd',
],
]);
$data = json_decode((string) $response->getBody(), true)['data'];const response = await fetch('https://app.klantly.com/api/v1/appointments/9d3f6c1e-4b2a-4c8e-9f1a-2b3c4d5e6f70/cancel', {
method: 'POST',
headers: {
Authorization: `Bearer ${process.env.KLANTLY_API_KEY}`,
'Content-Type': 'application/json',
'Idempotency-Key': '6f1c2d3e-4a5b-4c6d-8e7f-9a0b1c2d3e4f',
},
body: JSON.stringify({
"reason": "Klant is verhinderd"
}),
});
const { data } = await response.json();import os
import requests
response = requests.post(
"https://app.klantly.com/api/v1/appointments/9d3f6c1e-4b2a-4c8e-9f1a-2b3c4d5e6f70/cancel",
headers={
"Authorization": f"Bearer {os.environ['KLANTLY_API_KEY']}",
"Idempotency-Key": "6f1c2d3e-4a5b-4c6d-8e7f-9a0b1c2d3e4f",
},
json={
"reason": "Klant is verhinderd"
},
)
data = response.json()["data"]Réponse 200
{
"data": {
"object": "appointment",
"id": "9d3f7d83-4f8b-4a0e-9d5c-6b7f8a9bacb4",
"title": "Inmeten veranda",
"description": null,
"status": "confirmed",
"source": "klantly",
"starts_at": "2026-10-01T08:00:00Z",
"ends_at": "2026-10-01T09:00:00Z",
"all_day": false,
"location": "Dorpsstraat 1, Utrecht",
"customer_id": "9d3f6c1e-4b2a-4c8e-9f1a-2b3c4d5e6f70",
"contact": {
"name": "Jan de Vries",
"email": "jan@example.com",
"phone": "+31 6 12345678"
},
"user_id": "usr_0k3j9x21m4zq8p",
"appointment_type_id": "9d3f7ea4-5a9c-4b1f-8e6d-7c8a9bacbdc5",
"deal_id": "9d3f7a20-1c5e-4d7b-8a2f-3e4c5d6f7a81",
"quote_id": null,
"invoice_id": null,
"notes": null,
"cancellation_reason": null,
"confirmed_at": "2026-09-14T10:15:00Z",
"cancelled_at": null,
"rescheduled_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. -
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
conflict— Ceci est en conflit avec l'état actuel. -
409
invalid_state_transition— Cette action n'est pas possible dans le statut actuel. -
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.
Terminer un rendez-vous
/api/v1/appointments/{appointment}/complete
Termine le rendez-vous. Si la conversion des prospects de l’entreprise est réglée sur « rendez-vous terminé », un prospect devient client, comme dans l’agenda ; avec les autres réglages, il reste prospect.
- Scope
-
appointments.write— Créer, modifier, confirmer, annuler et terminer des rendez-vous (les automatisations de l'entreprise s'exécutent aussi) - Fonctionnalité requise
appointments
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 |
|---|---|---|
appointment obligatoire |
string (uuid) | L’id (UUID) du rendez-vous. |
Exemple de requête
curl -X POST "https://app.klantly.com/api/v1/appointments/9d3f6c1e-4b2a-4c8e-9f1a-2b3c4d5e6f70/complete" \
-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', 'appointments/9d3f6c1e-4b2a-4c8e-9f1a-2b3c4d5e6f70/complete', [
'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/appointments/9d3f6c1e-4b2a-4c8e-9f1a-2b3c4d5e6f70/complete', {
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/appointments/9d3f6c1e-4b2a-4c8e-9f1a-2b3c4d5e6f70/complete",
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": "appointment",
"id": "9d3f7d83-4f8b-4a0e-9d5c-6b7f8a9bacb4",
"title": "Inmeten veranda",
"description": null,
"status": "confirmed",
"source": "klantly",
"starts_at": "2026-10-01T08:00:00Z",
"ends_at": "2026-10-01T09:00:00Z",
"all_day": false,
"location": "Dorpsstraat 1, Utrecht",
"customer_id": "9d3f6c1e-4b2a-4c8e-9f1a-2b3c4d5e6f70",
"contact": {
"name": "Jan de Vries",
"email": "jan@example.com",
"phone": "+31 6 12345678"
},
"user_id": "usr_0k3j9x21m4zq8p",
"appointment_type_id": "9d3f7ea4-5a9c-4b1f-8e6d-7c8a9bacbdc5",
"deal_id": "9d3f7a20-1c5e-4d7b-8a2f-3e4c5d6f7a81",
"quote_id": null,
"invoice_id": null,
"notes": null,
"cancellation_reason": null,
"confirmed_at": "2026-09-14T10:15:00Z",
"cancelled_at": null,
"rescheduled_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. -
409
conflict— Ceci est en conflit avec l'état actuel. -
409
invalid_state_transition— Cette action n'est pas possible dans le statut actuel. -
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.
Envoyer un message au client
/api/v1/appointments/{appointment}/notify
Envoie au client par e-mail une confirmation, un déplacement, une annulation ou un rappel, avec le modèle que l’entreprise a configuré dans Klantly. Le message doit correspondre au statut du rendez-vous. Si l’entreprise a désactivé ce modèle, vous recevez une 409 et rien n’est envoyé. Nécessite le scope appointments.send.
- Scope
-
appointments.send— Envoyer par e-mail les messages de rendez-vous aux clients - Fonctionnalité requise
appointments
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 |
|---|---|---|
appointment obligatoire |
string (uuid) | L’id (UUID) du rendez-vous. |
Corps (JSON)
| Champ | Type | Description |
|---|---|---|
message
obligatoire
|
string | Quel message : confirmation, reschedule (déplacement), cancellation (annulation) ou reminder (rappel). l'une des valeurs : confirmation, reschedule, cancellation, reminder |
Exemple de requête
curl -X POST "https://app.klantly.com/api/v1/appointments/9d3f6c1e-4b2a-4c8e-9f1a-2b3c4d5e6f70/notify" \
-H "Authorization: Bearer $KLANTLY_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: 6f1c2d3e-4a5b-4c6d-8e7f-9a0b1c2d3e4f" \
-d '{
"message": "confirmation"
}'$client = new \GuzzleHttp\Client([
'base_uri' => 'https://app.klantly.com/api/v1/',
'headers' => ['Authorization' => 'Bearer ' . getenv('KLANTLY_API_KEY')],
]);
$response = $client->request('POST', 'appointments/9d3f6c1e-4b2a-4c8e-9f1a-2b3c4d5e6f70/notify', [
'headers' => [
'Idempotency-Key' => '6f1c2d3e-4a5b-4c6d-8e7f-9a0b1c2d3e4f',
],
'json' => [
'message' => 'confirmation',
],
]);
$data = json_decode((string) $response->getBody(), true)['data'];const response = await fetch('https://app.klantly.com/api/v1/appointments/9d3f6c1e-4b2a-4c8e-9f1a-2b3c4d5e6f70/notify', {
method: 'POST',
headers: {
Authorization: `Bearer ${process.env.KLANTLY_API_KEY}`,
'Content-Type': 'application/json',
'Idempotency-Key': '6f1c2d3e-4a5b-4c6d-8e7f-9a0b1c2d3e4f',
},
body: JSON.stringify({
"message": "confirmation"
}),
});
const { data } = await response.json();import os
import requests
response = requests.post(
"https://app.klantly.com/api/v1/appointments/9d3f6c1e-4b2a-4c8e-9f1a-2b3c4d5e6f70/notify",
headers={
"Authorization": f"Bearer {os.environ['KLANTLY_API_KEY']}",
"Idempotency-Key": "6f1c2d3e-4a5b-4c6d-8e7f-9a0b1c2d3e4f",
},
json={
"message": "confirmation"
},
)
data = response.json()["data"]Réponse 200
{
"data": {
"object": "appointment",
"id": "9d3f7d83-4f8b-4a0e-9d5c-6b7f8a9bacb4",
"title": "Inmeten veranda",
"description": null,
"status": "confirmed",
"source": "klantly",
"starts_at": "2026-10-01T08:00:00Z",
"ends_at": "2026-10-01T09:00:00Z",
"all_day": false,
"location": "Dorpsstraat 1, Utrecht",
"customer_id": "9d3f6c1e-4b2a-4c8e-9f1a-2b3c4d5e6f70",
"contact": {
"name": "Jan de Vries",
"email": "jan@example.com",
"phone": "+31 6 12345678"
},
"user_id": "usr_0k3j9x21m4zq8p",
"appointment_type_id": "9d3f7ea4-5a9c-4b1f-8e6d-7c8a9bacbdc5",
"deal_id": "9d3f7a20-1c5e-4d7b-8a2f-3e4c5d6f7a81",
"quote_id": null,
"invoice_id": null,
"notes": null,
"cancellation_reason": null,
"confirmed_at": "2026-09-14T10:15:00Z",
"cancelled_at": null,
"rescheduled_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. -
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
conflict— Ceci est en conflit avec l'état actuel. -
409
invalid_state_transition— Cette action n'est pas possible dans le statut actuel. -
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.
Supprimer un rendez-vous
/api/v1/appointments/{appointment}
Supprime définitivement le rendez-vous, y compris de l’agenda Google lié. Pour simplement l’annuler, utilisez plutôt Annuler un rendez-vous.
- Scope
-
appointments.delete— Supprimer des rendez-vous - Fonctionnalité requise
appointments
Paramètres de chemin
| Nom | Type | Description |
|---|---|---|
appointment obligatoire |
string (uuid) | L’id (UUID) du rendez-vous. |
Exemple de requête
curl -X DELETE "https://app.klantly.com/api/v1/appointments/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('DELETE', 'appointments/9d3f6c1e-4b2a-4c8e-9f1a-2b3c4d5e6f70');
$data = json_decode((string) $response->getBody(), true)['data'];const response = await fetch('https://app.klantly.com/api/v1/appointments/9d3f6c1e-4b2a-4c8e-9f1a-2b3c4d5e6f70', {
method: 'DELETE',
headers: {
Authorization: `Bearer ${process.env.KLANTLY_API_KEY}`,
},
});
const { data } = await response.json();import os
import requests
response = requests.delete(
"https://app.klantly.com/api/v1/appointments/9d3f6c1e-4b2a-4c8e-9f1a-2b3c4d5e6f70",
headers={
"Authorization": f"Bearer {os.environ['KLANTLY_API_KEY']}",
},
)
data = response.json()["data"]Réponse 200
{
"data": {
"object": "note",
"id": "9d3f7b41-2d6f-4e8c-9b3a-4f5d6e7a8b92",
"deleted": true
}
}Erreurs possibles
-
403
insufficient_scope— Cette clé API n'a pas accès à cette action. -
404
not_found— Introuvable. -
409
conflict— Ceci est en conflit avec l'état actuel.
L'objet
Tous les champs sont toujours présents ; un champ sans valeur vaut null.
| Champ | Type | Description |
|---|---|---|
object |
string | Toujours « appointment ». |
id |
string (uuid) | Id unique (UUID). |
title |
string | Titre du rendez-vous. |
description |
string | Description. peut être vide (null) |
status |
string | pending (pas encore confirmé), confirmed, cancelled (annulé) ou completed (terminé). À la création : pending ou confirmed (par défaut). l'une des valeurs : pending, confirmed, cancelled, completed |
source |
string | klantly (le rendez-vous normal) ou google (récupéré de l'agenda Google de l'entreprise). Un rendez-vous avec google compte pour l'occupation de l'agenda, mais il est en lecture seule via l'API et ne produit aucun événement webhook : les modifications se font dans Google Calendar. l'une des valeurs : klantly, google |
starts_at |
string (date-time) | Début (UTC). Vide pour une invitation où le client doit encore choisir une heure. En entrée : ISO 8601 avec fuseau horaire. peut être vide (null) |
ends_at |
string (date-time) | Fin (UTC). Sans ends_at à la création : la durée du type de rendez-vous ou la durée par défaut. peut être vide (null) |
all_day |
boolean | Un rendez-vous sur toute la journée. Les heures de la réponse sont en UTC : reconvertissez-les dans le fuseau de l’entreprise (Europe/Amsterdam) pour la date, sinon un rendez-vous commençant à 00:00 tombe la veille. |
location |
string | Lieu, par exemple l’adresse du client. peut être vide (null) |
customer_id |
string (uuid) | Le client du rendez-vous. Obligatoire à la création. peut être vide (null) |
contact |
object | Les coordonnées avec lesquelles le rendez-vous a été pris. |
contact.name |
string | Nom. peut être vide (null) |
contact.email |
string | Adresse e-mail ; les messages au client y sont envoyés. peut être vide (null) |
contact.phone |
string | Numéro de téléphone. peut être vide (null) |
user_id |
string | L’utilisateur qui a le rendez-vous, ou null. peut être vide (null) |
appointment_type_id |
string (uuid) | Le type de rendez-vous, ou null. peut être vide (null) |
deal_id |
string (uuid) | Le deal du tableau pipeline auquel le rendez-vous appartient (lié par Klantly lui-même). peut être vide (null) |
quote_id |
string (uuid) | Le devis lié, ou null. peut être vide (null) |
invoice_id |
string (uuid) | La facture liée, ou null. peut être vide (null) |
notes |
string | Note interne sur le rendez-vous. peut être vide (null) |
cancellation_reason |
string | Pourquoi le rendez-vous a été annulé, ou null. peut être vide (null) |
confirmed_at |
string (date-time) | Date de confirmation du rendez-vous. peut être vide (null) |
cancelled_at |
string (date-time) | Date d’annulation du rendez-vous. peut être vide (null) |
rescheduled_at |
string (date-time) | Date du dernier déplacement du rendez-vous. peut être vide (null) |
created_at |
string (date-time) | Créé le (UTC). |
updated_at |
string (date-time) | Dernière modification (UTC). |