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. Triez sur starts_at pour l’ordre de l’agenda ; les rendez-vous sans date (une invitation) sont alors exclus.
- 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 sur created_at, updated_at ou starts_at ; un signe moins devant signifie décroissant. Avec starts_at, les rendez-vous sans date sont exclus. l'une des valeurs : -created_at, created_at, -updated_at, updated_at, -starts_at, starts_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. |
Exemple de requête
curl "https://app.klantly.com/api/v1/appointments?filter[starts_from]=2026-10-01T00%3A00%3A00Z&sort=starts_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' => 'starts_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=starts_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": "starts_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",
"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",
"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",
"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",
"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. -
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",
"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
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",
"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
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",
"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
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",
"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
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.
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 |
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). |