Klantly Developers

Référence de l'API

Bons d’intervention

Des bons d’intervention avec lignes et check-list : les créer depuis un ERP par exemple, les modifier, changer leur statut et récupérer ceux qui sont terminés.

Endpoints

Lister les bons d’intervention

GET /api/v1/work-orders

Une liste de bons d’intervention, du plus récent au plus ancien, avec lignes, check-list et photos. Filtrez par statut, client, utilisateur, rendez-vous ou date de modification. Avec filter[status]=completed et filter[updated_since], vous récupérez le travail terminé.

Scope
work_orders.read — Lire les bons d'intervention, avec le nom, l'adresse et les coordonnées du client
Fonctionnalité requise
work_orders

Paramètres de requête

NomTypeDescription
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 trie par ordre décroissant. l'une des valeurs : -created_at, created_at, -updated_at, updated_at · par défaut : -created_at
filter[status] string Uniquement les bons d’intervention de ce statut. l'une des valeurs : draft, planned, in_progress, completed, invoiced, cancelled
filter[customer_id] string (uuid) Uniquement ce qui appartient à ce client.
filter[assigned_user_id] string Uniquement ce qui est assigné à cet utilisateur (l’id de Lister les utilisateurs).
filter[appointment_id] string (uuid) Uniquement les bons d’intervention de ce rendez-vous.
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
curl "https://app.klantly.com/api/v1/work-orders?filter[status]=completed&sort=-updated_at" \
  -H "Authorization: Bearer $KLANTLY_API_KEY"
PHP
$client = new \GuzzleHttp\Client([
    'base_uri' => 'https://app.klantly.com/api/v1/',
    'headers' => ['Authorization' => 'Bearer ' . getenv('KLANTLY_API_KEY')],
]);

$response = $client->request('GET', 'work-orders', [
    'query' => [
        'filter[status]' => 'completed',
        'sort' => '-updated_at',
    ],
]);

$data = json_decode((string) $response->getBody(), true)['data'];
JavaScript
const response = await fetch('https://app.klantly.com/api/v1/work-orders?filter[status]=completed&sort=-updated_at', {
  headers: {
    Authorization: `Bearer ${process.env.KLANTLY_API_KEY}`,
  },
});

const { data } = await response.json();
Python
import os

import requests

response = requests.get(
    "https://app.klantly.com/api/v1/work-orders",
    headers={
        "Authorization": f"Bearer {os.environ['KLANTLY_API_KEY']}",
    },
    params={
        "filter[status]": "completed",
        "sort": "-updated_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.

Exemple de réponse
{
  "data": [
    {
      "object": "work_order",
      "id": "9d3f8328-9ed0-4f5d-8cab-b0cedfe0f1a9",
      "number": "WB-2026-00042",
      "status": "planned",
      "title": "Onderhoud cv-ketel",
      "type": "onderhoud",
      "location": null,
      "description": null,
      "work_performed": null,
      "customer_notes": null,
      "customer_id": "9d3f6c1e-4b2a-4c8e-9f1a-2b3c4d5e6f70",
      "customer": {
        "type": "business",
        "name": "De Vries Bouw",
        "email": "jan@example.com",
        "phone": "+31 6 12345678",
        "address": "Dorpsstraat 1",
        "postal_code": "3511 AB",
        "city": "Utrecht",
        "country": "NL"
      },
      "deal_id": null,
      "appointment_id": null,
      "quote_id": null,
      "invoice_id": null,
      "assigned_user_id": "usr_0k3j9x21m4zq8p",
      "language": "nl",
      "currency": "EUR",
      "subtotal": "90.00",
      "tax_amount": "18.90",
      "total": "108.90",
      "scheduled_at": "2026-10-01T08:00:00Z",
      "started_at": null,
      "completed_at": null,
      "sent_at": null,
      "signature": {
        "is_signed": false,
        "signed_by_name": null,
        "signed_at": null
      },
      "items": [
        {
          "object": "work_order_item",
          "id": "9d3f856a-b0f2-4b7f-8ecd-d2e0f1a2b3cb",
          "type": "labor",
          "name": "Arbeid",
          "description": null,
          "sku": null,
          "quantity": "2.00",
          "unit": "uur",
          "unit_price": "45.00",
          "discount_percentage": "0.00",
          "discount_amount": "0.00",
          "line_total": "90.00",
          "is_taxable": true,
          "tax_rate": "21.00",
          "minutes": 120
        }
      ],
      "checklist": [
        {
          "object": "work_order_checklist_item",
          "id": "9d3f868b-c1a3-4c8a-9fde-e3f1a2b3c4dc",
          "label": "Druk gecontroleerd",
          "checked": false,
          "required": true,
          "note": null
        }
      ],
      "photos": [],
      "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

En outre, chaque endpoint peut renvoyer les erreurs générales, comme une clé invalide ou une limite atteinte. Voir tous les codes d'erreur.

Récupérer un bon d’intervention

GET /api/v1/work-orders/{work_order}

Un bon d’intervention par id, avec lignes, check-list, photos (données uniquement) et l’état de la signature.

Scope
work_orders.read — Lire les bons d'intervention, avec le nom, l'adresse et les coordonnées du client
Fonctionnalité requise
work_orders

Paramètres de chemin

NomTypeDescription
work_order obligatoire string (uuid) L’id (UUID) du bon d’intervention.

Exemple de requête

cURL
curl "https://app.klantly.com/api/v1/work-orders/9d3f6c1e-4b2a-4c8e-9f1a-2b3c4d5e6f70" \
  -H "Authorization: Bearer $KLANTLY_API_KEY"
PHP
$client = new \GuzzleHttp\Client([
    'base_uri' => 'https://app.klantly.com/api/v1/',
    'headers' => ['Authorization' => 'Bearer ' . getenv('KLANTLY_API_KEY')],
]);

$response = $client->request('GET', 'work-orders/9d3f6c1e-4b2a-4c8e-9f1a-2b3c4d5e6f70');

$data = json_decode((string) $response->getBody(), true)['data'];
JavaScript
const response = await fetch('https://app.klantly.com/api/v1/work-orders/9d3f6c1e-4b2a-4c8e-9f1a-2b3c4d5e6f70', {
  headers: {
    Authorization: `Bearer ${process.env.KLANTLY_API_KEY}`,
  },
});

const { data } = await response.json();
Python
import os

import requests

response = requests.get(
    "https://app.klantly.com/api/v1/work-orders/9d3f6c1e-4b2a-4c8e-9f1a-2b3c4d5e6f70",
    headers={
        "Authorization": f"Bearer {os.environ['KLANTLY_API_KEY']}",
    },
)
data = response.json()["data"]

Réponse 200

Exemple de réponse
{
  "data": {
    "object": "work_order",
    "id": "9d3f8328-9ed0-4f5d-8cab-b0cedfe0f1a9",
    "number": "WB-2026-00042",
    "status": "planned",
    "title": "Onderhoud cv-ketel",
    "type": "onderhoud",
    "location": null,
    "description": null,
    "work_performed": null,
    "customer_notes": null,
    "customer_id": "9d3f6c1e-4b2a-4c8e-9f1a-2b3c4d5e6f70",
    "customer": {
      "type": "business",
      "name": "De Vries Bouw",
      "email": "jan@example.com",
      "phone": "+31 6 12345678",
      "address": "Dorpsstraat 1",
      "postal_code": "3511 AB",
      "city": "Utrecht",
      "country": "NL"
    },
    "deal_id": null,
    "appointment_id": null,
    "quote_id": null,
    "invoice_id": null,
    "assigned_user_id": "usr_0k3j9x21m4zq8p",
    "language": "nl",
    "currency": "EUR",
    "subtotal": "90.00",
    "tax_amount": "18.90",
    "total": "108.90",
    "scheduled_at": "2026-10-01T08:00:00Z",
    "started_at": null,
    "completed_at": null,
    "sent_at": null,
    "signature": {
      "is_signed": false,
      "signed_by_name": null,
      "signed_at": null
    },
    "items": [
      {
        "object": "work_order_item",
        "id": "9d3f856a-b0f2-4b7f-8ecd-d2e0f1a2b3cb",
        "type": "labor",
        "name": "Arbeid",
        "description": null,
        "sku": null,
        "quantity": "2.00",
        "unit": "uur",
        "unit_price": "45.00",
        "discount_percentage": "0.00",
        "discount_amount": "0.00",
        "line_total": "90.00",
        "is_taxable": true,
        "tax_rate": "21.00",
        "minutes": 120
      }
    ],
    "checklist": [
      {
        "object": "work_order_checklist_item",
        "id": "9d3f868b-c1a3-4c8a-9fde-e3f1a2b3c4dc",
        "label": "Druk gecontroleerd",
        "checked": false,
        "required": true,
        "note": null
      }
    ],
    "photos": [],
    "created_at": "2026-09-14T10:15:00Z",
    "updated_at": "2026-09-14T10:15:00Z"
  }
}

Erreurs possibles

En outre, chaque endpoint peut renvoyer les erreurs générales, comme une clé invalide ou une limite atteinte. Voir tous les codes d'erreur.

Créer un bon d’intervention

POST /api/v1/work-orders

Crée un bon d’intervention pour un client, en brouillon ou planifié. Klantly lui attribue un numéro et calcule les totaux ; le nom, l’adresse et les coordonnées viennent du client.

Scope
work_orders.write — Créer et modifier des bons d'intervention, et changer leur statut (terminer peut envoyer une demande d'avis)
Fonctionnalité requise
work_orders

Envoyez une Idempotency-Key : une nouvelle tentative après un délai d'attente ne crée alors jamais de doublon.

Corps (JSON)

ChampTypeDescription
customer_id obligatoire string (uuid) Le client. Obligatoire à la création ; le nom, l’adresse et les coordonnées viennent du client.
status facultatif string draft (brouillon), planned (planifié), in_progress (en cours), completed (terminé), invoiced (facturé) ou cancelled (annulé). À la création : draft ou planned. l'une des valeurs : draft, planned
title facultatif string Titre. peut être vide (null) · au maximum 255 caractères
type facultatif string Type de travail, par exemple installation, réparation ou entretien. peut être vide (null) · au maximum 64 caractères
location facultatif string Lieu de l’intervention, s’il ne s’agit pas de l’adresse du client. peut être vide (null) · au maximum 255 caractères
description facultatif string Description du travail ou de la réclamation. peut être vide (null) · au maximum 20000 caractères
work_performed facultatif string Ce qui a été fait. peut être vide (null) · au maximum 20000 caractères
customer_notes facultatif string Remarques pour le client ; figurent sur le bon. peut être vide (null) · au maximum 20000 caractères
scheduled_at facultatif string (date-time) Date prévue de l’intervention (UTC). En entrée : ISO 8601 avec fuseau horaire. peut être vide (null)
assigned_user_id facultatif string Le technicien ou l’utilisateur qui réalise le travail, ou null. peut être vide (null)
appointment_id facultatif string (uuid) Le rendez-vous auquel le bon appartient, ou null. peut être vide (null)
quote_id facultatif string (uuid) Le devis dont provient le bon, ou null. peut être vide (null)
language facultatif string Langue du bon : nl, en, de ou fr. l'une des valeurs : nl, en, de, fr
items facultatif array Les lignes (200 au maximum). En entrée : une liste avec par ligne name (obligatoire) et en option type, description, sku, quantity, unit, unit_price, discount_percentage, discount_amount, tax_rate, is_taxable et minutes ; la liste remplace toutes les lignes.
checklist facultatif array La check-list (200 points au maximum). En entrée : par point label (obligatoire) et en option checked, required et note ; la liste remplace toute la check-list.

Exemple de requête

cURL
curl -X POST "https://app.klantly.com/api/v1/work-orders" \
  -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": "Onderhoud cv-ketel",
  "status": "planned",
  "scheduled_at": "2026-10-01T08:00:00Z",
  "items": [
    {
      "type": "labor",
      "name": "Arbeid",
      "quantity": 2,
      "unit_price": "45.00"
    }
  ]
}'
PHP
$client = new \GuzzleHttp\Client([
    'base_uri' => 'https://app.klantly.com/api/v1/',
    'headers' => ['Authorization' => 'Bearer ' . getenv('KLANTLY_API_KEY')],
]);

$response = $client->request('POST', 'work-orders', [
    'headers' => [
        'Idempotency-Key' => '6f1c2d3e-4a5b-4c6d-8e7f-9a0b1c2d3e4f',
    ],
    'json' => [
        'customer_id' => '9d3f6c1e-4b2a-4c8e-9f1a-2b3c4d5e6f70',
        'title' => 'Onderhoud cv-ketel',
        'status' => 'planned',
        'scheduled_at' => '2026-10-01T08:00:00Z',
        'items' => [
            0 => [
                'type' => 'labor',
                'name' => 'Arbeid',
                'quantity' => 2,
                'unit_price' => '45.00',
            ],
        ],
    ],
]);

$data = json_decode((string) $response->getBody(), true)['data'];
JavaScript
const response = await fetch('https://app.klantly.com/api/v1/work-orders', {
  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": "Onderhoud cv-ketel",
  "status": "planned",
  "scheduled_at": "2026-10-01T08:00:00Z",
  "items": [
    {
      "type": "labor",
      "name": "Arbeid",
      "quantity": 2,
      "unit_price": "45.00"
    }
  ]
}),
});

const { data } = await response.json();
Python
import os

import requests

response = requests.post(
    "https://app.klantly.com/api/v1/work-orders",
    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": "Onderhoud cv-ketel",
        "status": "planned",
        "scheduled_at": "2026-10-01T08:00:00Z",
        "items": [
            {
                "type": "labor",
                "name": "Arbeid",
                "quantity": 2,
                "unit_price": "45.00"
            }
        ]
    },
)
data = response.json()["data"]

Réponse 201

Exemple de réponse
{
  "data": {
    "object": "work_order",
    "id": "9d3f8328-9ed0-4f5d-8cab-b0cedfe0f1a9",
    "number": "WB-2026-00042",
    "status": "planned",
    "title": "Onderhoud cv-ketel",
    "type": "onderhoud",
    "location": null,
    "description": null,
    "work_performed": null,
    "customer_notes": null,
    "customer_id": "9d3f6c1e-4b2a-4c8e-9f1a-2b3c4d5e6f70",
    "customer": {
      "type": "business",
      "name": "De Vries Bouw",
      "email": "jan@example.com",
      "phone": "+31 6 12345678",
      "address": "Dorpsstraat 1",
      "postal_code": "3511 AB",
      "city": "Utrecht",
      "country": "NL"
    },
    "deal_id": null,
    "appointment_id": null,
    "quote_id": null,
    "invoice_id": null,
    "assigned_user_id": "usr_0k3j9x21m4zq8p",
    "language": "nl",
    "currency": "EUR",
    "subtotal": "90.00",
    "tax_amount": "18.90",
    "total": "108.90",
    "scheduled_at": "2026-10-01T08:00:00Z",
    "started_at": null,
    "completed_at": null,
    "sent_at": null,
    "signature": {
      "is_signed": false,
      "signed_by_name": null,
      "signed_at": null
    },
    "items": [
      {
        "object": "work_order_item",
        "id": "9d3f856a-b0f2-4b7f-8ecd-d2e0f1a2b3cb",
        "type": "labor",
        "name": "Arbeid",
        "description": null,
        "sku": null,
        "quantity": "2.00",
        "unit": "uur",
        "unit_price": "45.00",
        "discount_percentage": "0.00",
        "discount_amount": "0.00",
        "line_total": "90.00",
        "is_taxable": true,
        "tax_rate": "21.00",
        "minutes": 120
      }
    ],
    "checklist": [
      {
        "object": "work_order_checklist_item",
        "id": "9d3f868b-c1a3-4c8a-9fde-e3f1a2b3c4dc",
        "label": "Druk gecontroleerd",
        "checked": false,
        "required": true,
        "note": null
      }
    ],
    "photos": [],
    "created_at": "2026-09-14T10:15:00Z",
    "updated_at": "2026-09-14T10:15:00Z"
  }
}

Erreurs possibles

En outre, chaque endpoint peut renvoyer les erreurs générales, comme une clé invalide ou une limite atteinte. Voir tous les codes d'erreur.

Modifier un bon d’intervention

PATCH /api/v1/work-orders/{work_order}

Ne modifie que les champs envoyés. items et checklist remplacent l’ensemble des lignes et de la check-list ; les lignes reçoivent de nouveaux id. Une ligne et le total ne peuvent pas dépasser 99 999 999,99. Un bon d’intervention facturé ne peut plus être modifié.

Scope
work_orders.write — Créer et modifier des bons d'intervention, et changer leur statut (terminer peut envoyer une demande d'avis)
Fonctionnalité requise
work_orders

Envoyez l'ETag dans If-Match : vous n'écraserez jamais par erreur une version plus récente.

Paramètres de chemin

NomTypeDescription
work_order obligatoire string (uuid) L’id (UUID) du bon d’intervention.

Corps (JSON)

ChampTypeDescription
title facultatif string Titre. peut être vide (null) · au maximum 255 caractères
type facultatif string Type de travail, par exemple installation, réparation ou entretien. peut être vide (null) · au maximum 64 caractères
location facultatif string Lieu de l’intervention, s’il ne s’agit pas de l’adresse du client. peut être vide (null) · au maximum 255 caractères
description facultatif string Description du travail ou de la réclamation. peut être vide (null) · au maximum 20000 caractères
work_performed facultatif string Ce qui a été fait. peut être vide (null) · au maximum 20000 caractères
customer_notes facultatif string Remarques pour le client ; figurent sur le bon. peut être vide (null) · au maximum 20000 caractères
scheduled_at facultatif string (date-time) Date prévue de l’intervention (UTC). En entrée : ISO 8601 avec fuseau horaire. peut être vide (null)
assigned_user_id facultatif string Le technicien ou l’utilisateur qui réalise le travail, ou null. peut être vide (null)
appointment_id facultatif string (uuid) Le rendez-vous auquel le bon appartient, ou null. peut être vide (null)
quote_id facultatif string (uuid) Le devis dont provient le bon, ou null. peut être vide (null)
language facultatif string Langue du bon : nl, en, de ou fr. l'une des valeurs : nl, en, de, fr
items facultatif array Les lignes (200 au maximum). En entrée : une liste avec par ligne name (obligatoire) et en option type, description, sku, quantity, unit, unit_price, discount_percentage, discount_amount, tax_rate, is_taxable et minutes ; la liste remplace toutes les lignes.
checklist facultatif array La check-list (200 points au maximum). En entrée : par point label (obligatoire) et en option checked, required et note ; la liste remplace toute la check-list.

Exemple de requête

cURL
curl -X PATCH "https://app.klantly.com/api/v1/work-orders/9d3f6c1e-4b2a-4c8e-9f1a-2b3c4d5e6f70" \
  -H "Authorization: Bearer $KLANTLY_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "work_performed": "Filter vervangen en de ketel ontlucht."
}'
PHP
$client = new \GuzzleHttp\Client([
    'base_uri' => 'https://app.klantly.com/api/v1/',
    'headers' => ['Authorization' => 'Bearer ' . getenv('KLANTLY_API_KEY')],
]);

$response = $client->request('PATCH', 'work-orders/9d3f6c1e-4b2a-4c8e-9f1a-2b3c4d5e6f70', [
    'json' => [
        'work_performed' => 'Filter vervangen en de ketel ontlucht.',
    ],
]);

$data = json_decode((string) $response->getBody(), true)['data'];
JavaScript
const response = await fetch('https://app.klantly.com/api/v1/work-orders/9d3f6c1e-4b2a-4c8e-9f1a-2b3c4d5e6f70', {
  method: 'PATCH',
  headers: {
    Authorization: `Bearer ${process.env.KLANTLY_API_KEY}`,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
  "work_performed": "Filter vervangen en de ketel ontlucht."
}),
});

const { data } = await response.json();
Python
import os

import requests

response = requests.patch(
    "https://app.klantly.com/api/v1/work-orders/9d3f6c1e-4b2a-4c8e-9f1a-2b3c4d5e6f70",
    headers={
        "Authorization": f"Bearer {os.environ['KLANTLY_API_KEY']}",
    },
    json={
        "work_performed": "Filter vervangen en de ketel ontlucht."
    },
)
data = response.json()["data"]

Réponse 200

Exemple de réponse
{
  "data": {
    "object": "work_order",
    "id": "9d3f8328-9ed0-4f5d-8cab-b0cedfe0f1a9",
    "number": "WB-2026-00042",
    "status": "planned",
    "title": "Onderhoud cv-ketel",
    "type": "onderhoud",
    "location": null,
    "description": null,
    "work_performed": null,
    "customer_notes": null,
    "customer_id": "9d3f6c1e-4b2a-4c8e-9f1a-2b3c4d5e6f70",
    "customer": {
      "type": "business",
      "name": "De Vries Bouw",
      "email": "jan@example.com",
      "phone": "+31 6 12345678",
      "address": "Dorpsstraat 1",
      "postal_code": "3511 AB",
      "city": "Utrecht",
      "country": "NL"
    },
    "deal_id": null,
    "appointment_id": null,
    "quote_id": null,
    "invoice_id": null,
    "assigned_user_id": "usr_0k3j9x21m4zq8p",
    "language": "nl",
    "currency": "EUR",
    "subtotal": "90.00",
    "tax_amount": "18.90",
    "total": "108.90",
    "scheduled_at": "2026-10-01T08:00:00Z",
    "started_at": null,
    "completed_at": null,
    "sent_at": null,
    "signature": {
      "is_signed": false,
      "signed_by_name": null,
      "signed_at": null
    },
    "items": [
      {
        "object": "work_order_item",
        "id": "9d3f856a-b0f2-4b7f-8ecd-d2e0f1a2b3cb",
        "type": "labor",
        "name": "Arbeid",
        "description": null,
        "sku": null,
        "quantity": "2.00",
        "unit": "uur",
        "unit_price": "45.00",
        "discount_percentage": "0.00",
        "discount_amount": "0.00",
        "line_total": "90.00",
        "is_taxable": true,
        "tax_rate": "21.00",
        "minutes": 120
      }
    ],
    "checklist": [
      {
        "object": "work_order_checklist_item",
        "id": "9d3f868b-c1a3-4c8a-9fde-e3f1a2b3c4dc",
        "label": "Druk gecontroleerd",
        "checked": false,
        "required": true,
        "note": null
      }
    ],
    "photos": [],
    "created_at": "2026-09-14T10:15:00Z",
    "updated_at": "2026-09-14T10:15:00Z"
  }
}

Erreurs possibles

En outre, chaque endpoint peut renvoyer les erreurs générales, comme une clé invalide ou une limite atteinte. Voir tous les codes d'erreur.

Changer le statut d’un bon d’intervention

POST /api/v1/work-orders/{work_order}/status

Passe le bon d’intervention en brouillon, planifié, en cours, terminé ou annulé. Pour en cours et terminé, started_at et completed_at sont renseignés. Comme dans l’application, terminer peut envoyer une demande d’avis au client si l’entreprise l’a configuré. Seul Klantly passe un bon au statut facturé.

Scope
work_orders.write — Créer et modifier des bons d'intervention, et changer leur statut (terminer peut envoyer une demande d'avis)
Fonctionnalité requise
work_orders

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

NomTypeDescription
work_order obligatoire string (uuid) L’id (UUID) du bon d’intervention.

Corps (JSON)

ChampTypeDescription
status obligatoire string draft (brouillon), planned (planifié), in_progress (en cours), completed (terminé), invoiced (facturé) ou cancelled (annulé). À la création : draft ou planned. l'une des valeurs : draft, planned, in_progress, completed, cancelled

Exemple de requête

cURL
curl -X POST "https://app.klantly.com/api/v1/work-orders/9d3f6c1e-4b2a-4c8e-9f1a-2b3c4d5e6f70/status" \
  -H "Authorization: Bearer $KLANTLY_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: 6f1c2d3e-4a5b-4c6d-8e7f-9a0b1c2d3e4f" \
  -d '{
  "status": "completed"
}'
PHP
$client = new \GuzzleHttp\Client([
    'base_uri' => 'https://app.klantly.com/api/v1/',
    'headers' => ['Authorization' => 'Bearer ' . getenv('KLANTLY_API_KEY')],
]);

$response = $client->request('POST', 'work-orders/9d3f6c1e-4b2a-4c8e-9f1a-2b3c4d5e6f70/status', [
    'headers' => [
        'Idempotency-Key' => '6f1c2d3e-4a5b-4c6d-8e7f-9a0b1c2d3e4f',
    ],
    'json' => [
        'status' => 'completed',
    ],
]);

$data = json_decode((string) $response->getBody(), true)['data'];
JavaScript
const response = await fetch('https://app.klantly.com/api/v1/work-orders/9d3f6c1e-4b2a-4c8e-9f1a-2b3c4d5e6f70/status', {
  method: 'POST',
  headers: {
    Authorization: `Bearer ${process.env.KLANTLY_API_KEY}`,
    'Content-Type': 'application/json',
    'Idempotency-Key': '6f1c2d3e-4a5b-4c6d-8e7f-9a0b1c2d3e4f',
  },
  body: JSON.stringify({
  "status": "completed"
}),
});

const { data } = await response.json();
Python
import os

import requests

response = requests.post(
    "https://app.klantly.com/api/v1/work-orders/9d3f6c1e-4b2a-4c8e-9f1a-2b3c4d5e6f70/status",
    headers={
        "Authorization": f"Bearer {os.environ['KLANTLY_API_KEY']}",
        "Idempotency-Key": "6f1c2d3e-4a5b-4c6d-8e7f-9a0b1c2d3e4f",
    },
    json={
        "status": "completed"
    },
)
data = response.json()["data"]

Réponse 200

Exemple de réponse
{
  "data": {
    "object": "work_order",
    "id": "9d3f8328-9ed0-4f5d-8cab-b0cedfe0f1a9",
    "number": "WB-2026-00042",
    "status": "planned",
    "title": "Onderhoud cv-ketel",
    "type": "onderhoud",
    "location": null,
    "description": null,
    "work_performed": null,
    "customer_notes": null,
    "customer_id": "9d3f6c1e-4b2a-4c8e-9f1a-2b3c4d5e6f70",
    "customer": {
      "type": "business",
      "name": "De Vries Bouw",
      "email": "jan@example.com",
      "phone": "+31 6 12345678",
      "address": "Dorpsstraat 1",
      "postal_code": "3511 AB",
      "city": "Utrecht",
      "country": "NL"
    },
    "deal_id": null,
    "appointment_id": null,
    "quote_id": null,
    "invoice_id": null,
    "assigned_user_id": "usr_0k3j9x21m4zq8p",
    "language": "nl",
    "currency": "EUR",
    "subtotal": "90.00",
    "tax_amount": "18.90",
    "total": "108.90",
    "scheduled_at": "2026-10-01T08:00:00Z",
    "started_at": null,
    "completed_at": null,
    "sent_at": null,
    "signature": {
      "is_signed": false,
      "signed_by_name": null,
      "signed_at": null
    },
    "items": [
      {
        "object": "work_order_item",
        "id": "9d3f856a-b0f2-4b7f-8ecd-d2e0f1a2b3cb",
        "type": "labor",
        "name": "Arbeid",
        "description": null,
        "sku": null,
        "quantity": "2.00",
        "unit": "uur",
        "unit_price": "45.00",
        "discount_percentage": "0.00",
        "discount_amount": "0.00",
        "line_total": "90.00",
        "is_taxable": true,
        "tax_rate": "21.00",
        "minutes": 120
      }
    ],
    "checklist": [
      {
        "object": "work_order_checklist_item",
        "id": "9d3f868b-c1a3-4c8a-9fde-e3f1a2b3c4dc",
        "label": "Druk gecontroleerd",
        "checked": false,
        "required": true,
        "note": null
      }
    ],
    "photos": [],
    "created_at": "2026-09-14T10:15:00Z",
    "updated_at": "2026-09-14T10:15:00Z"
  }
}

Erreurs possibles

En outre, chaque endpoint peut renvoyer les erreurs générales, comme une clé invalide ou une limite atteinte. Voir tous les codes d'erreur.

Supprimer un bon d’intervention

DELETE /api/v1/work-orders/{work_order}

Supprime le bon d’intervention. Un bon d’intervention facturé ne peut pas être supprimé.

Scope
work_orders.delete — Supprimer des bons d'intervention
Fonctionnalité requise
work_orders

Paramètres de chemin

NomTypeDescription
work_order obligatoire string (uuid) L’id (UUID) du bon d’intervention.

Exemple de requête

cURL
curl -X DELETE "https://app.klantly.com/api/v1/work-orders/9d3f6c1e-4b2a-4c8e-9f1a-2b3c4d5e6f70" \
  -H "Authorization: Bearer $KLANTLY_API_KEY"
PHP
$client = new \GuzzleHttp\Client([
    'base_uri' => 'https://app.klantly.com/api/v1/',
    'headers' => ['Authorization' => 'Bearer ' . getenv('KLANTLY_API_KEY')],
]);

$response = $client->request('DELETE', 'work-orders/9d3f6c1e-4b2a-4c8e-9f1a-2b3c4d5e6f70');

$data = json_decode((string) $response->getBody(), true)['data'];
JavaScript
const response = await fetch('https://app.klantly.com/api/v1/work-orders/9d3f6c1e-4b2a-4c8e-9f1a-2b3c4d5e6f70', {
  method: 'DELETE',
  headers: {
    Authorization: `Bearer ${process.env.KLANTLY_API_KEY}`,
  },
});

const { data } = await response.json();
Python
import os

import requests

response = requests.delete(
    "https://app.klantly.com/api/v1/work-orders/9d3f6c1e-4b2a-4c8e-9f1a-2b3c4d5e6f70",
    headers={
        "Authorization": f"Bearer {os.environ['KLANTLY_API_KEY']}",
    },
)
data = response.json()["data"]

Réponse 200

Exemple de réponse
{
  "data": {
    "object": "note",
    "id": "9d3f7b41-2d6f-4e8c-9b3a-4f5d6e7a8b92",
    "deleted": true
  }
}

Erreurs possibles

En outre, chaque endpoint peut renvoyer les erreurs générales, comme une clé invalide ou une limite atteinte. Voir tous les codes d'erreur.

L'objet

Tous les champs sont toujours présents ; un champ sans valeur vaut null.

ChampTypeDescription
object string Toujours « work_order ».
id string (uuid) Id unique (UUID).
number string Numéro du bon, par exemple WB-2026-00042 ; attribué par Klantly.
status string draft (brouillon), planned (planifié), in_progress (en cours), completed (terminé), invoiced (facturé) ou cancelled (annulé). À la création : draft ou planned. l'une des valeurs : draft, planned, in_progress, completed, invoiced, cancelled
title string Titre. peut être vide (null)
type string Type de travail, par exemple installation, réparation ou entretien. peut être vide (null)
location string Lieu de l’intervention, s’il ne s’agit pas de l’adresse du client. peut être vide (null)
description string Description du travail ou de la réclamation. peut être vide (null)
work_performed string Ce qui a été fait. peut être vide (null)
customer_notes string Remarques pour le client ; figurent sur le bon. peut être vide (null)
customer_id string (uuid) Le client. Obligatoire à la création ; le nom, l’adresse et les coordonnées viennent du client. peut être vide (null)
customer object Les données du client sur le bon, telles qu’elles étaient à la création.
customer.type string individual (particulier) ou business (entreprise). peut être vide (null)
customer.name string Nom ; pour une entreprise, la raison sociale. peut être vide (null)
customer.email string Adresse e-mail. peut être vide (null)
customer.phone string Numéro de téléphone. peut être vide (null)
customer.address string Rue et numéro. peut être vide (null)
customer.postal_code string Code postal. peut être vide (null)
customer.city string Ville. peut être vide (null)
customer.country string Pays. peut être vide (null)
deal_id string (uuid) Le deal du tableau pipeline, ou null. peut être vide (null)
appointment_id string (uuid) Le rendez-vous auquel le bon appartient, ou null. peut être vide (null)
quote_id string (uuid) Le devis dont provient le bon, ou null. peut être vide (null)
invoice_id string (uuid) La facture du bon, ou null. peut être vide (null)
assigned_user_id string Le technicien ou l’utilisateur qui réalise le travail, ou null. peut être vide (null)
language string Langue du bon : nl, en, de ou fr. l'une des valeurs : nl, en, de, fr
currency string Toujours « EUR ».
subtotal string Total hors TVA, sous forme de texte avec deux décimales.
tax_amount string Montant de la TVA.
total string Total TVA comprise.
scheduled_at string (date-time) Date prévue de l’intervention (UTC). En entrée : ISO 8601 avec fuseau horaire. peut être vide (null)
started_at string (date-time) Début de l’intervention. peut être vide (null)
completed_at string (date-time) Fin de l’intervention. peut être vide (null)
sent_at string (date-time) Date d’envoi du bon au client. peut être vide (null)
signature object La signature du client (données uniquement, pas d’image).
signature.is_signed boolean Indique si le bon est signé.
signature.signed_by_name string Nom du signataire. peut être vide (null)
signature.signed_at string (date-time) Date de la signature. peut être vide (null)
items array<object> Les lignes (200 au maximum). En entrée : une liste avec par ligne name (obligatoire) et en option type, description, sku, quantity, unit, unit_price, discount_percentage, discount_amount, tax_rate, is_taxable et minutes ; la liste remplace toutes les lignes.
items.object string Toujours « work_order_item ».
items.id string (uuid) Id de la ligne. Change à chaque envoi de items (les lignes sont remplacées).
items.type string labor (main-d’œuvre), material (matériel) ou other. l'une des valeurs : labor, material, other
items.name string Libellé sur le bon.
items.description string Précision. peut être vide (null)
items.sku string Référence article. peut être vide (null)
items.quantity string Quantité.
items.unit string Unité, par exemple heure ou pièce. peut être vide (null)
items.unit_price string Prix unitaire hors TVA.
items.discount_percentage string Remise en pourcentage.
items.discount_amount string Remise fixe sur la ligne hors TVA ; ne compte que si discount_percentage vaut 0.
items.line_total string Total de la ligne hors TVA ; calculé par Klantly.
items.is_taxable boolean Indique si la ligne est soumise à la TVA.
items.tax_rate string Taux de TVA en pourcentage (21 par défaut, même si l’entreprise applique un autre taux : envoyez-le alors).
items.minutes integer Minutes travaillées, pour la main-d’œuvre. peut être vide (null)
checklist array<object> La check-list (200 points au maximum). En entrée : par point label (obligatoire) et en option checked, required et note ; la liste remplace toute la check-list.
checklist.object string Toujours « work_order_checklist_item ».
checklist.id string (uuid) Id du point.
checklist.label string Le point, par exemple « Pression contrôlée ».
checklist.checked boolean Coché.
checklist.required boolean Doit obligatoirement être coché.
checklist.note string Remarque sur le point. peut être vide (null)
photos array<object> Les photos du bon (données uniquement ; les fichiers ne sont pas encore dans l’API).
photos.object string Toujours « work_order_photo ».
photos.id string (uuid) Id de la photo.
photos.kind string before (avant), after (après) ou other. peut être vide (null) · l'une des valeurs : before, after, other
photos.caption string Légende. peut être vide (null)
photos.created_at string (date-time) Téléversée le (UTC).
created_at string (date-time) Créé le (UTC).
updated_at string (date-time) Dernière modification (UTC).