Référence de l'API
Clients
Clients et prospects : créer, rechercher, modifier, convertir un prospect en client et consulter l'historique.
Endpoints
-
GET
/customersLister les clients -
GET
/customers/{customer}Récupérer un client -
POST
/customersCréer un client -
PATCH
/customers/{customer}Modifier un client -
POST
/customers/{customer}/convertConvertir un prospect en client -
GET
/customers/{customer}/activitiesHistorique d'un client
Lister les clients
/api/v1/customers
Une liste de clients et de prospects, les plus récents d'abord. Filtrez par statut, type, adresse e-mail ou date de modification, recherchez avec q et naviguez avec le curseur de meta.
- Scope
-
customers.read— Lire les clients et les prospects
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. |
q
|
string | Recherche dans le nom, l'adresse e-mail, le nom de l'entreprise et le numéro de téléphone. au moins 2 caractères · au maximum 100 caractères |
sort
|
string | Le champ sur lequel trier ; un signe moins devant signifie décroissant. Les champs que vous pouvez choisir et la valeur par défaut sont indiqués avec ce paramètre. l'une des valeurs : -created_at, created_at, -updated_at, updated_at · par défaut : -created_at |
filter[status]
|
string | Uniquement les prospects ou uniquement les clients. l'une des valeurs : lead, customer |
filter[type]
|
string | Uniquement les particuliers ou uniquement les entreprises. l'une des valeurs : individual, business |
filter[email]
|
string (email) | Exactement cette adresse e-mail (sans tenir compte des majuscules). |
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/customers?limit=50&filter[status]=lead" \
-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', 'customers', [
'query' => [
'limit' => 50,
'filter[status]' => 'lead',
],
]);
$data = json_decode((string) $response->getBody(), true)['data'];const response = await fetch('https://app.klantly.com/api/v1/customers?limit=50&filter[status]=lead', {
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/customers",
headers={
"Authorization": f"Bearer {os.environ['KLANTLY_API_KEY']}",
},
params={
"limit": 50,
"filter[status]": "lead"
},
)
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": "customer",
"id": "9d3f6c1e-4b2a-4c8e-9f1a-2b3c4d5e6f70",
"type": "business",
"status": "lead",
"name": "Jan de Vries",
"email": "jan@example.com",
"phone": "+31 6 12345678",
"company_name": "De Vries Bouw",
"vat_number": "NL123456789B01",
"coc_number": "12345678",
"address": "Dorpsstraat 1",
"postal_code": "3511 AB",
"city": "Utrecht",
"country": "NL",
"email_unsubscribed": false,
"converted_at": null,
"last_activity_at": "2026-09-14T10:15:00Z",
"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 client
/api/v1/customers/{customer}
Un seul client par id. La réponse contient un ETag que vous pouvez envoyer dans If-Match lors d'une modification.
- Scope
-
customers.read— Lire les clients et les prospects
Paramètres de chemin
| Nom | Type | Description |
|---|---|---|
customer obligatoire |
string (uuid) | L'id (UUID) du client. |
Exemple de requête
curl "https://app.klantly.com/api/v1/customers/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', 'customers/9d3f6c1e-4b2a-4c8e-9f1a-2b3c4d5e6f70');
$data = json_decode((string) $response->getBody(), true)['data'];const response = await fetch('https://app.klantly.com/api/v1/customers/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/customers/9d3f6c1e-4b2a-4c8e-9f1a-2b3c4d5e6f70",
headers={
"Authorization": f"Bearer {os.environ['KLANTLY_API_KEY']}",
},
)
data = response.json()["data"]Réponse 200
{
"data": {
"object": "customer",
"id": "9d3f6c1e-4b2a-4c8e-9f1a-2b3c4d5e6f70",
"type": "business",
"status": "lead",
"name": "Jan de Vries",
"email": "jan@example.com",
"phone": "+31 6 12345678",
"company_name": "De Vries Bouw",
"vat_number": "NL123456789B01",
"coc_number": "12345678",
"address": "Dorpsstraat 1",
"postal_code": "3511 AB",
"city": "Utrecht",
"country": "NL",
"email_unsubscribed": false,
"converted_at": null,
"last_activity_at": "2026-09-14T10:15:00Z",
"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.
Créer un client
/api/v1/customers
Crée un nouveau prospect. L'adresse e-mail est obligatoire et unique au sein de votre entreprise : une adresse existante renvoie une erreur de validation. Les automatisations et l'historique client fonctionnent exactement comme lors d'une création dans Klantly.
- Scope
-
customers.write— Créer et modifier les clients et les prospects
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 |
|---|---|---|
email
obligatoire
|
string (email) | Adresse e-mail ; unique au sein de votre entreprise. au maximum 255 caractères · unique au sein de votre entreprise |
type
facultatif
|
string | individual (particulier) ou business (entreprise). l'une des valeurs : individual, business |
name
facultatif
|
string | Nom de la personne de contact. peut être vide (null) · au maximum 255 caractères |
phone
facultatif
|
string | Numéro de téléphone. peut être vide (null) · au maximum 255 caractères |
address
facultatif
|
string | Rue et numéro. peut être vide (null) · au maximum 255 caractères |
city
facultatif
|
string | Ville. peut être vide (null) · au maximum 255 caractères |
postal_code
facultatif
|
string | Code postal. peut être vide (null) · au maximum 64 caractères |
country
facultatif
|
string | Pays. peut être vide (null) · au moins 2 caractères · au maximum 2 caractères |
company_name
facultatif
|
string | Nom de l'entreprise, pour un client professionnel. peut être vide (null) · au maximum 255 caractères |
vat_number
facultatif
|
string | Numéro de TVA. peut être vide (null) · au maximum 20 caractères |
coc_number
facultatif
|
string | Numéro d'immatriculation (registre du commerce). peut être vide (null) · au maximum 30 caractères |
Exemple de requête
curl -X POST "https://app.klantly.com/api/v1/customers" \
-H "Authorization: Bearer $KLANTLY_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: 6f1c2d3e-4a5b-4c6d-8e7f-9a0b1c2d3e4f" \
-d '{
"email": "jan@example.com",
"name": "Jan de Vries",
"type": "business",
"company_name": "De Vries Bouw",
"city": "Utrecht"
}'$client = new \GuzzleHttp\Client([
'base_uri' => 'https://app.klantly.com/api/v1/',
'headers' => ['Authorization' => 'Bearer ' . getenv('KLANTLY_API_KEY')],
]);
$response = $client->request('POST', 'customers', [
'headers' => [
'Idempotency-Key' => '6f1c2d3e-4a5b-4c6d-8e7f-9a0b1c2d3e4f',
],
'json' => [
'email' => 'jan@example.com',
'name' => 'Jan de Vries',
'type' => 'business',
'company_name' => 'De Vries Bouw',
'city' => 'Utrecht',
],
]);
$data = json_decode((string) $response->getBody(), true)['data'];const response = await fetch('https://app.klantly.com/api/v1/customers', {
method: 'POST',
headers: {
Authorization: `Bearer ${process.env.KLANTLY_API_KEY}`,
'Content-Type': 'application/json',
'Idempotency-Key': '6f1c2d3e-4a5b-4c6d-8e7f-9a0b1c2d3e4f',
},
body: JSON.stringify({
"email": "jan@example.com",
"name": "Jan de Vries",
"type": "business",
"company_name": "De Vries Bouw",
"city": "Utrecht"
}),
});
const { data } = await response.json();import os
import requests
response = requests.post(
"https://app.klantly.com/api/v1/customers",
headers={
"Authorization": f"Bearer {os.environ['KLANTLY_API_KEY']}",
"Idempotency-Key": "6f1c2d3e-4a5b-4c6d-8e7f-9a0b1c2d3e4f",
},
json={
"email": "jan@example.com",
"name": "Jan de Vries",
"type": "business",
"company_name": "De Vries Bouw",
"city": "Utrecht"
},
)
data = response.json()["data"]Réponse 201
{
"data": {
"object": "customer",
"id": "9d3f6c1e-4b2a-4c8e-9f1a-2b3c4d5e6f70",
"type": "business",
"status": "lead",
"name": "Jan de Vries",
"email": "jan@example.com",
"phone": "+31 6 12345678",
"company_name": "De Vries Bouw",
"vat_number": "NL123456789B01",
"coc_number": "12345678",
"address": "Dorpsstraat 1",
"postal_code": "3511 AB",
"city": "Utrecht",
"country": "NL",
"email_unsubscribed": false,
"converted_at": null,
"last_activity_at": "2026-09-14T10:15:00Z",
"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. -
403
limit_reached— La limite de l'abonnement est atteinte. -
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 client
/api/v1/customers/{customer}
Modifie uniquement les champs que vous envoyez. Le statut ne change pas via cet endpoint ; utilisez pour cela « Convertir un prospect en client ».
- Scope
-
customers.write— Créer et modifier les clients et les prospects
Envoyez l'ETag dans If-Match : vous n'écraserez jamais par erreur une version plus récente.
Paramètres de chemin
| Nom | Type | Description |
|---|---|---|
customer obligatoire |
string (uuid) | L'id (UUID) du client. |
Corps (JSON)
| Champ | Type | Description |
|---|---|---|
email
facultatif
|
string (email) | Adresse e-mail ; unique au sein de votre entreprise. au maximum 255 caractères · unique au sein de votre entreprise |
type
facultatif
|
string | individual (particulier) ou business (entreprise). l'une des valeurs : individual, business |
name
facultatif
|
string | Nom de la personne de contact. peut être vide (null) · au maximum 255 caractères |
phone
facultatif
|
string | Numéro de téléphone. peut être vide (null) · au maximum 255 caractères |
address
facultatif
|
string | Rue et numéro. peut être vide (null) · au maximum 255 caractères |
city
facultatif
|
string | Ville. peut être vide (null) · au maximum 255 caractères |
postal_code
facultatif
|
string | Code postal. peut être vide (null) · au maximum 64 caractères |
country
facultatif
|
string | Pays. peut être vide (null) · au moins 2 caractères · au maximum 2 caractères |
company_name
facultatif
|
string | Nom de l'entreprise, pour un client professionnel. peut être vide (null) · au maximum 255 caractères |
vat_number
facultatif
|
string | Numéro de TVA. peut être vide (null) · au maximum 20 caractères |
coc_number
facultatif
|
string | Numéro d'immatriculation (registre du commerce). peut être vide (null) · au maximum 30 caractères |
Exemple de requête
curl -X PATCH "https://app.klantly.com/api/v1/customers/9d3f6c1e-4b2a-4c8e-9f1a-2b3c4d5e6f70" \
-H "Authorization: Bearer $KLANTLY_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"phone": "+31 6 12345678",
"city": "Amersfoort"
}'$client = new \GuzzleHttp\Client([
'base_uri' => 'https://app.klantly.com/api/v1/',
'headers' => ['Authorization' => 'Bearer ' . getenv('KLANTLY_API_KEY')],
]);
$response = $client->request('PATCH', 'customers/9d3f6c1e-4b2a-4c8e-9f1a-2b3c4d5e6f70', [
'json' => [
'phone' => '+31 6 12345678',
'city' => 'Amersfoort',
],
]);
$data = json_decode((string) $response->getBody(), true)['data'];const response = await fetch('https://app.klantly.com/api/v1/customers/9d3f6c1e-4b2a-4c8e-9f1a-2b3c4d5e6f70', {
method: 'PATCH',
headers: {
Authorization: `Bearer ${process.env.KLANTLY_API_KEY}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
"phone": "+31 6 12345678",
"city": "Amersfoort"
}),
});
const { data } = await response.json();import os
import requests
response = requests.patch(
"https://app.klantly.com/api/v1/customers/9d3f6c1e-4b2a-4c8e-9f1a-2b3c4d5e6f70",
headers={
"Authorization": f"Bearer {os.environ['KLANTLY_API_KEY']}",
},
json={
"phone": "+31 6 12345678",
"city": "Amersfoort"
},
)
data = response.json()["data"]Réponse 200
{
"data": {
"object": "customer",
"id": "9d3f6c1e-4b2a-4c8e-9f1a-2b3c4d5e6f70",
"type": "business",
"status": "lead",
"name": "Jan de Vries",
"email": "jan@example.com",
"phone": "+31 6 12345678",
"company_name": "De Vries Bouw",
"vat_number": "NL123456789B01",
"coc_number": "12345678",
"address": "Dorpsstraat 1",
"postal_code": "3511 AB",
"city": "Utrecht",
"country": "NL",
"email_unsubscribed": false,
"converted_at": null,
"last_activity_at": "2026-09-14T10:15:00Z",
"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.
Convertir un prospect en client
/api/v1/customers/{customer}/convert
Convertit un prospect en client. S'il est déjà client, rien ne change et vous récupérez simplement le client.
- Scope
-
customers.write— Créer et modifier les clients et les prospects
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 |
|---|---|---|
customer obligatoire |
string (uuid) | L'id (UUID) du client. |
Exemple de requête
curl -X POST "https://app.klantly.com/api/v1/customers/9d3f6c1e-4b2a-4c8e-9f1a-2b3c4d5e6f70/convert" \
-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', 'customers/9d3f6c1e-4b2a-4c8e-9f1a-2b3c4d5e6f70/convert', [
'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/customers/9d3f6c1e-4b2a-4c8e-9f1a-2b3c4d5e6f70/convert', {
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/customers/9d3f6c1e-4b2a-4c8e-9f1a-2b3c4d5e6f70/convert",
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": "customer",
"id": "9d3f6c1e-4b2a-4c8e-9f1a-2b3c4d5e6f70",
"type": "business",
"status": "lead",
"name": "Jan de Vries",
"email": "jan@example.com",
"phone": "+31 6 12345678",
"company_name": "De Vries Bouw",
"vat_number": "NL123456789B01",
"coc_number": "12345678",
"address": "Dorpsstraat 1",
"postal_code": "3511 AB",
"city": "Utrecht",
"country": "NL",
"email_unsubscribed": false,
"converted_at": null,
"last_activity_at": "2026-09-14T10:15:00Z",
"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. -
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.
Historique d'un client
/api/v1/customers/{customer}/activities
L'historique d'un client, le plus récent en premier : devis, factures, rendez-vous, e-mails et plus encore. Les références aux enregistrements liés figurent sous related. Aujourd'hui, on y trouve les entrées système (création, facture/paiement, e-mail) ; un deal, une note ou un changement d'étape n'y apparaît pas — suivez-les via les événements deal.* et note.*.
- Scope
-
customers.read— Lire les clients et les prospects
Paramètres de chemin
| Nom | Type | Description |
|---|---|---|
customer obligatoire |
string (uuid) | L'id (UUID) du client. |
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. |
filter[type]
|
string | Uniquement les activités de ce type, par exemple quote_sent ou invoice_created. au maximum 40 caractères |
Exemple de requête
curl "https://app.klantly.com/api/v1/customers/9d3f6c1e-4b2a-4c8e-9f1a-2b3c4d5e6f70/activities" \
-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', 'customers/9d3f6c1e-4b2a-4c8e-9f1a-2b3c4d5e6f70/activities');
$data = json_decode((string) $response->getBody(), true)['data'];const response = await fetch('https://app.klantly.com/api/v1/customers/9d3f6c1e-4b2a-4c8e-9f1a-2b3c4d5e6f70/activities', {
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/customers/9d3f6c1e-4b2a-4c8e-9f1a-2b3c4d5e6f70/activities",
headers={
"Authorization": f"Bearer {os.environ['KLANTLY_API_KEY']}",
},
)
data = response.json()["data"]Réponse 200
La réponse est une liste avec pagination par curseur : data contient les objets, meta la pagination.
{
"data": [
{
"object": "customer_activity",
"id": "9d3f7c62-3e7a-4f9d-8c4b-5a6e7f8a9ba3",
"customer_id": "9d3f6c1e-4b2a-4c8e-9f1a-2b3c4d5e6f70",
"type": "quote_sent",
"title": null,
"description": null,
"related": {
"quote_id": null,
"invoice_id": null,
"appointment_id": null,
"work_order_id": null,
"task_id": null,
"deal_id": null,
"order_id": null,
"conversation_id": null
},
"happened_at": "2026-09-14T10:15:00Z",
"created_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. -
404
not_found— Introuvable. -
422
validation_failed— Les données saisies ne sont pas valides.
L'objet
Tous les champs sont toujours présents ; un champ sans valeur vaut null.
| Champ | Type | Description |
|---|---|---|
object |
string | Toujours « customer ». |
id |
string (uuid) | Id unique (UUID). |
type |
string | individual (particulier) ou business (entreprise). l'une des valeurs : individual, business |
status |
string | lead (prospect) ou customer (client). l'une des valeurs : lead, customer |
name |
string | Nom de la personne de contact. peut être vide (null) |
email |
string (email) | Adresse e-mail ; unique au sein de votre entreprise. |
phone |
string | Numéro de téléphone. peut être vide (null) |
company_name |
string | Nom de l'entreprise, pour un client professionnel. peut être vide (null) |
vat_number |
string | Numéro de TVA. peut être vide (null) |
coc_number |
string | Numéro d'immatriculation (registre du commerce). peut être vide (null) |
address |
string | Rue et numéro. peut être vide (null) |
postal_code |
string | Code postal. peut être vide (null) |
city |
string | Ville. peut être vide (null) |
country |
string | Pays. peut être vide (null) |
email_unsubscribed |
boolean | S'est désabonné des e-mails. |
converted_at |
string (date-time) | Date à laquelle le prospect est devenu client. peut être vide (null) |
last_activity_at |
string (date-time) | Dernière activité dans Klantly. peut être vide (null) |
created_at |
string (date-time) | Créé le (UTC). |
updated_at |
string (date-time) | Dernière modification le (UTC). |