Klantly Developers

Journal des modifications

Toutes les modifications de l'API Klantly, les plus récentes d'abord.

Au sein de la version 1, des éléments sont uniquement ajoutés. Une modification susceptible de casser des intégrations existantes n'arrive que dans une nouvelle version et est annoncée longtemps à l'avance avec les en-têtes Deprecation et Sunset.

14 octobre 2026

Nouvel événement : message.not_delivered. WhatsApp n'a pas remis un message que toi ou l'entreprise avez envoyé. Meta le signale via son webhook de statut, parfois quelques minutes après l'envoi : message.sent seul ne signifie donc pas que le message est arrivé.

  • Scope messages.read, comme message.received et message.sent. La charge utile est le message lui-même.
  • Raisons les plus fréquentes : le numéro ne peut pas recevoir WhatsApp, ou le dernier message du client date de plus de 24 heures (seul un modèle approuvé passe alors).
  • Les endpoints abonnés avec ["*"] reçoivent l'événement automatiquement ; avec une liste fixe, ajoute message.not_delivered toi-même.

13 octobre 2026

Les rendez-vous de l'agenda Google. Une entreprise peut désormais faire fonctionner son agenda Google dans l'autre sens : les éléments des agendas Google choisis figurent alors comme rendez-vous dans Klantly.

  • Chaque rendez-vous porte source : klantly (le cas normal) ou google (récupéré de l'agenda Google de l'entreprise). Ce champ s'ajoute à toute réponse contenant un rendez-vous, donc l'ETag d'un rendez-vous change une fois — un If-Match avec une ancienne valeur renvoie alors 412 ; récupérez le rendez-vous à nouveau.
  • Un rendez-vous avec source: "google" est en lecture seule. PATCH, DELETE et les actions confirm, cancel, complete et notify renvoient 409 avec le code conflict : on y travaille dans Google, c'est donc là que la modification doit se faire. La lecture fonctionne normalement, et il compte pour l'occupation de l'agenda.
  • Ces rendez-vous ne produisent aucun événement webhook. L'agenda d'une entreprise peut contenir des centaines d'éléments ; les envoyer comme appointment.created saturerait votre endpoint avec du travail qui ne vient pas de Klantly.
  • GET /availability les prend en compte, car ce sont des rendez-vous ordinaires. Si la récupération était désactivée, rien ne change.
  • Disponibilité : un rendez-vous d'une journée entière bloque désormais toute la journée. GET /v1/availability lisait les heures de début et de fin brutes, et pour un rendez-vous d'une journée entière les deux sont à 00:00 du dernier jour — la plage était donc vide et la journée revenait comme entièrement libre. Il en va de même pour un rendez-vous qui passe minuit : il compte chaque jour qu'il touche. Votre agenda Google ne compte toujours pas ici ; cela reste l'exception délibérée.

27 septembre 2026

Demandes de service. Une nouvelle ressource : le SIGNALEMENT qui précède le travail — une panne, un cas de garantie, une réclamation ou une question d'un client. Le travail exécuté, avec ses heures et ses montants, reste le bon d'intervention ; une demande n'a pas de lignes et ne se retrouve jamais sur une facture.

  • GET|POST /v1/services, GET|PATCH|DELETE /v1/services/{id} et POST /v1/services/{id}/status (brouillon → planifiée → en cours → terminée, plus annulée).
  • Photos sous /v1/services/{id}/photos : GET, POST (multipart) et DELETE. Chaque photo porte un kind : issue (le signalement), progress, completion (le résultat) ou other. Les mêmes limites que les photos de bon d'intervention : 10 Mo par photo, 30 par demande, et un lien de téléchargement valable un quart d'heure.
  • Scopes services.read, services.write et services.delete ; ils relèvent de la fonctionnalité bons d'intervention, donc une clé qui y a droit peut les attribuer.
  • Événements service.created, service.updated, service.status_changed, service.completed, service.signed et service.deleted.
  • La signature, la planification du rendez-vous et la conversion en bon d'intervention ne passent délibérément pas par l'API : ce sont des gestes d'une personne sur place. Vous liez vous-même un rendez-vous avec appointment_id.

20 septembre 2026

Tri.

  • Pour les deals, les rendez-vous, les conversations et les avis, sort n'accepte plus que created_at et updated_at (avec ou sans signe moins). stage_changed_at, starts_at, last_message_at et reviewed_at sont supprimés : ces colonnes peuvent être vides, et le curseur sautait alors le reste de la liste — les lignes sans valeur étaient inaccessibles. Une valeur supprimée renvoie désormais 422.
  • Le tri par défaut des conversations et des avis est donc devenu -created_at (au lieu de -last_message_at et -reviewed_at respectivement).
  • Pour l'ordre de l'agenda, utilisez filter[starts_from] et filter[starts_until] et triez vous-même.

Idempotence.

  • Une Idempotency-Key vaut désormais par entreprise et non plus par clé. Ainsi, une nouvelle tentative conserve sa garantie si votre intégration bascule sur le nouveau jeton pendant le renouvellement d'une clé. Si deux intégrations de la même entreprise utilisent la même valeur pour une requête différente, la seconde reçoit 422 idempotency_key_reused ; donnez à chaque intégration son propre préfixe.
  • Une 404 ou une 422 n'est plus conservée 24 heures : la même clé avec un corps corrigé exécute simplement la requête.

18 septembre 2026

Sécurité.

  • Un endpoint de webhook ne peut plus pointer vers une adresse interne emballée en IPv4-dans-IPv6 (comme [::ffff:7f00:1] pour 127.0.0.1). De telles adresses sont désormais refusées au même titre que leur forme habituelle.

Avoirs.

  • Créditer une facture envoyée ou payée avec POST /invoices/{id}/credit : entièrement, une quantité par ligne, ou un montant libre TTC. La réponse est l'avoir.
  • Les avoirs figurent dans GET /invoices à côté des factures, avec le nouveau champ type (invoice ou credit_note) et des montants négatifs. Sans filtre, vous obtenez les deux ; avec filter[type], vous en choisissez un.
  • Nouveaux champs sur une facture : type, credited_amount, credit_note_ids, credited_invoice_id, credited_invoice_number, credit_reason, refund_amount, refunded_at et credit_note_state ; sur une ligne credited_item_id. Nouveau statut credited (entièrement créditée).
  • Enregistrer le remboursement d'un avoir avec POST /invoices/{id}/refunded.
  • Rembourser via Mollie avec via: mollie sur POST /invoices/{id}/refunded, lorsque la facture a été payée via Mollie.
  • Nouvel événement invoice.credited. L'avoir lui-même arrive comme invoice.created avec type credit_note.
  • Une facture (partiellement) créditée ne peut plus être annulée, et vous ne pouvez pas enregistrer de paiement sur un avoir (409). L'envoi ne modifie pas le statut d'un avoir ou d'une facture créditée.
  • Le guide Factures vers votre comptabilité explique comment comptabiliser les avoirs.

17 septembre 2026

Boîte de réception, avis et pièces jointes.

  • Boîte de réception : lire les conversations et les messages, répondre au nom de l'entreprise via le widget de chat, WhatsApp ou e-mail, et clôturer une conversation. Répondre exige la fonction du canal de cette conversation.
  • Avis : consulter les avis et les demandes d'avis, et demander un avis à un client avec POST /review-requests. Créer soi-même un avis n'est volontairement pas possible — il doit venir du client.
  • Pièces jointes d'un devis et photos d'un bon d'intervention : consulter, téléverser et supprimer. Le téléversement se fait en multipart/form-data dans le champ file ; le téléchargement via un lien signé valable un quart d'heure et sans clé API.
  • Nouveaux scopes : messages.read, messages.send, reviews.read et reviews.write.
  • Nouveaux events pour la boîte de réception et les avis, comme message.received, conversation.closed et review.received.

Ventes et finances.

  • Devis : lister, créer, modifier (brouillons uniquement), envoyer, accepter, refuser et supprimer, et récupérer le PDF avec GET /quotes/{id}/pdf.
  • Factures : lister, créer, modifier (brouillons uniquement), envoyer, annuler, enregistrer des paiements et supprimer, et récupérer le PDF avec GET /invoices/{id}/pdf.
  • Obtenir la page de paiement du client avec GET /invoices/{id}/payment-link (scope invoices.send, fonctionnalité Paiements en ligne).
  • Transformer un devis accepté en brouillon de facture avec POST /quotes/{id}/invoice. Un devis a au plus une facture : une deuxième requête, y compris via POST /invoices avec quote_id, renvoie 409 conflict avec l'id de la facture existante dans invoice_id.
  • Les lignes de devis et de facture acceptent unit_price_incl : un prix TTC exact au centime.
  • Commandes de la boutique en ligne : les lister, changer le statut, transmettre le suivi et ajouter des notes.
  • Événements pour les devis, factures et commandes, comme quote.accepted, invoice.paid et order.status_changed.
  • Nouveaux scopes : quotes.read, quotes.write, quotes.delete, quotes.send, invoices.read, invoices.write, invoices.delete, invoices.send, orders.read et orders.write.
  • Nouveau guide : Factures vers votre comptabilité.

15 septembre 2026

Sécurité.

  • Modifier, désactiver, supprimer ou renouveler le secret d'un endpoint de webhook nécessite une clé qui peut lire tout ce que l'endpoint reçoit (sinon 403 insufficient_scope).
  • Les webhooks ne peuvent plus pointer vers Klantly lui-même, ni via une adresse IP ni via votre propre nom de domaine, ni vers des formes IPv6 d'adresses internes.
  • Un corps qui n'est pas un objet JSON valide donne 400 bad_request (il était lu comme un corps vide).
  • Les heures hors de 1970–2100 et les dates qui n'existent pas, comme le 31 février, donnent 422.
  • POST /webhook-endpoints/{id}/test et POST /appointments/{id}/notify relèvent de la limite des actions lourdes.
  • Les réponses de l'API ont Cache-Control: no-store.
  • Les administrateurs reçoivent un e-mail de sécurité lorsqu'une clé API est révoquée, obtient des droits supplémentaires ou une autre restriction IP, et lorsqu'un endpoint de webhook est créé, change d'adresse ou reçoit un nouveau secret.
  • Une restriction IP doit être d'au moins /8 (IPv4) ou /32 (IPv6).

Améliorations après une revue.

  • Un endpoint de webhook configuré via l'API suit la clé qui l'a configuré : si vous la révoquez ou lui retirez un scope de lecture, l'endpoint ne reçoit plus ces événements. Une autre URL ou un nouveau secret nécessite une clé qui peut lire tout ce que l'endpoint reçoit (sinon 403 insufficient_scope).
  • Une livraison répétée ou renvoyée vérifie à nouveau si l'événement est toujours autorisé.
  • Une URL de webhook avec un point final ou des caractères hors ASCII est refusée ; utilisez la forme xn--.
  • Les curseurs sont chiffrés : utilisez-les tels que vous les recevez.
  • Une réponse rejouée (même Idempotency-Key) lors de la création ou du renouvellement d'un endpoint de webhook ne contient plus le secret.
  • Les lignes des bons d'intervention ont le champ discount_amount (une remise fixe) ; un montant trop élevé donne 422 au lieu d'une erreur serveur. PATCH /work-orders/{id} avec seulement items donne désormais aussi work_order.updated.
  • PATCH /tasks/{id} avec links conserve les liens que l'API n'affiche pas, et une modification apparaît dans l'historique de la tâche.
  • POST /appointments/{id}/notify donne 409 si l'entreprise a désactivé le modèle. Un rendez-vous créé comme confirmé a confirmed_at.

Rendez-vous, tâches et bons d'intervention.

  • Rendez-vous : lister, récupérer, planifier, modifier, confirmer, annuler, terminer et supprimer, et envoyer au client une confirmation, un déplacement, une annulation ou un rappel par e-mail.
  • Avec POST /appointments, title n'est plus obligatoire si vous transmettez un appointment_type_id : le titre devient alors le nom du type de rendez-vous. Sans l'un ni l'autre, vous obtenez 422.
  • Lister les types de rendez-vous et les créneaux libres.
  • Tâches : lister, récupérer, créer, lier à des clients et à d'autres enregistrements, déplacer, terminer, rouvrir, annuler et supprimer, ainsi que les commentaires et les tableaux de tâches.
  • Bons d'intervention : lister, récupérer, créer avec lignes et check-list, modifier, changer le statut et supprimer.
  • Événements pour les rendez-vous, les tâches et les bons d'intervention, comme appointment.created, task.moved et work_order.completed.
  • Nouveaux scopes : appointments.read, appointments.write, appointments.delete, appointments.send, tasks.read, tasks.write, tasks.delete, work_orders.read, work_orders.write et work_orders.delete.
  • Nouveaux guides : Rendez-vous depuis votre propre planning et Bons d'intervention depuis votre ERP.

Webhooks, deals et plus encore.

  • Webhooks selon Standard Webhooks : gérez les endpoints dans Klantly et via l'API, avec signature, nouvelles tentatives, journal de livraison et message de test. Lisez le guide Webhooks.
  • Événements : GET /events pour rattraper les webhooks manqués.
  • Deals : lister, récupérer, créer, modifier, déplacer, gagner, perdre et archiver, et lister les étapes du pipeline.
  • Notes sur les clients et les deals.
  • L'historique d'un client.
  • Récupérer les utilisateurs et les données de l'entreprise.
  • Nouveaux scopes : deals.read, deals.write, users.read, company.read, webhooks.manage et events.read.
  • Nouveaux guides : Du formulaire web au prospect et Make et n8n.

14 septembre 2026

Première version de l'API Klantly.

  • Authentification par clés API, avec scopes, date d'expiration, liste d'adresses IP autorisées et renouvellement.
  • GET /me pour tester votre connexion.
  • Clients : lister, récupérer, créer, modifier et convertir un prospect en client.
  • Pagination par curseur, filtres, Idempotency-Key et If-Match.
  • Messages d'erreur selon la RFC 9457, en quatre langues.
  • Spécification OpenAPI 3.1 en quatre langues.

Dernière mise à jour le 14 octobre 2026