API-Referenz
Arbeitsaufträge
Arbeitsaufträge mit Positionen und Checkliste: zum Beispiel aus einem ERP erstellen, bearbeiten, den Status ändern und abgeschlossene Aufträge abrufen.
Endpunkte
-
GET
/work-ordersArbeitsaufträge auflisten -
GET
/work-orders/{work_order}Arbeitsauftrag abrufen -
POST
/work-ordersArbeitsauftrag erstellen -
PATCH
/work-orders/{work_order}Arbeitsauftrag bearbeiten -
POST
/work-orders/{work_order}/statusStatus eines Arbeitsauftrags ändern -
DELETE
/work-orders/{work_order}Arbeitsauftrag löschen
Arbeitsaufträge auflisten
/api/v1/work-orders
Eine Liste von Arbeitsaufträgen, neueste zuerst, mit Positionen, Checkliste und Fotos. Filtern Sie nach Status, Kunde, Benutzer, Termin oder Änderungsdatum. Mit filter[status]=completed und filter[updated_since] holen Sie abgeschlossene Arbeit ab.
- Scope
-
work_orders.read— Arbeitsaufträge lesen, mit Name, Adresse und Kontaktdaten des Kunden - Erforderliche Funktion
work_orders
Query-Parameter
| Name | Typ | Beschreibung |
|---|---|---|
limit
|
integer | Anzahl der Ergebnisse pro Seite. von 1 bis 100 · Standard: 50 |
cursor
|
string | Der next_cursor oder prev_cursor aus meta der vorherigen Antwort. |
sort
|
string | Sortierung nach created_at oder updated_at; ein Minuszeichen davor sortiert absteigend. einer von: -created_at, created_at, -updated_at, updated_at · Standard: -created_at |
filter[status]
|
string | Nur Arbeitsaufträge mit diesem Status. einer von: draft, planned, in_progress, completed, invoiced, cancelled |
filter[customer_id]
|
string (uuid) | Nur was zu diesem Kunden gehört. |
filter[assigned_user_id]
|
string | Nur was diesem Benutzer zugewiesen ist (die ID aus Benutzer auflisten). |
filter[appointment_id]
|
string (uuid) | Nur Arbeitsaufträge zu diesem Termin. |
filter[updated_since]
|
string (date-time) | Nur was seit diesem Zeitpunkt geändert wurde: ISO 8601 mit Zeitzone, zum Beispiel 2026-09-14T10:15:00Z. Praktisch zum Synchronisieren. |
Beispielanfrage
curl "https://app.klantly.com/api/v1/work-orders?filter[status]=completed&sort=-updated_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', 'work-orders', [
'query' => [
'filter[status]' => 'completed',
'sort' => '-updated_at',
],
]);
$data = json_decode((string) $response->getBody(), true)['data'];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();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"]Antwort 200
Die Antwort ist eine Liste mit Cursor-Paginierung: data enthält die Objekte, meta die Paginierung.
{
"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
}
}Mögliche Fehler
-
403
insufficient_scope— Dieser API-Schlüssel hat keinen Zugriff auf diese Aktion. -
422
validation_failed— Die Eingabe ist ungültig.
Arbeitsauftrag abrufen
/api/v1/work-orders/{work_order}
Ein Arbeitsauftrag nach ID, mit Positionen, Checkliste, Fotos (nur die Daten) und dem Stand der Unterschrift.
- Scope
-
work_orders.read— Arbeitsaufträge lesen, mit Name, Adresse und Kontaktdaten des Kunden - Erforderliche Funktion
work_orders
Pfadparameter
| Name | Typ | Beschreibung |
|---|---|---|
work_order erforderlich |
string (uuid) | Die ID (UUID) des Arbeitsauftrags. |
Beispielanfrage
curl "https://app.klantly.com/api/v1/work-orders/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', 'work-orders/9d3f6c1e-4b2a-4c8e-9f1a-2b3c4d5e6f70');
$data = json_decode((string) $response->getBody(), true)['data'];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();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"]Antwort 200
{
"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"
}
}Mögliche Fehler
-
403
insufficient_scope— Dieser API-Schlüssel hat keinen Zugriff auf diese Aktion. -
404
not_found— Nicht gefunden.
Arbeitsauftrag erstellen
/api/v1/work-orders
Erstellt einen Arbeitsauftrag für einen Kunden, als Entwurf oder geplant. Klantly vergibt eine Nummer und berechnet die Summen; Name, Adresse und Kontaktdaten kommen vom Kunden.
- Scope
-
work_orders.write— Arbeitsaufträge erstellen und bearbeiten sowie den Status ändern (Abschließen kann eine Bewertungsanfrage senden) - Erforderliche Funktion
work_orders
Senden Sie einen Idempotency-Key mit, dann erzeugt ein erneuter Versuch nach einem Timeout keinen doppelten Datensatz.
Body (JSON)
| Feld | Typ | Beschreibung |
|---|---|---|
customer_id
erforderlich
|
string (uuid) | Der Kunde. Beim Erstellen erforderlich; Name, Adresse und Kontaktdaten kommen vom Kunden. |
status
optional
|
string | draft (Entwurf), planned (geplant), in_progress (in Arbeit), completed (abgeschlossen), invoiced (abgerechnet) oder cancelled (storniert). Beim Erstellen draft oder planned. einer von: draft, planned |
title
optional
|
string | Titel. kann leer sein (null) · höchstens 255 Zeichen |
type
optional
|
string | Art der Arbeit, zum Beispiel Installation, Reparatur oder Wartung. kann leer sein (null) · höchstens 64 Zeichen |
location
optional
|
string | Wo die Arbeit stattfindet, wenn nicht an der Adresse des Kunden. kann leer sein (null) · höchstens 255 Zeichen |
description
optional
|
string | Beschreibung der Arbeit oder der Beschwerde. kann leer sein (null) · höchstens 20000 Zeichen |
work_performed
optional
|
string | Was erledigt wurde. kann leer sein (null) · höchstens 20000 Zeichen |
customer_notes
optional
|
string | Hinweise für den Kunden; stehen auf dem Arbeitsauftrag. kann leer sein (null) · höchstens 20000 Zeichen |
scheduled_at
optional
|
string (date-time) | Wann die Arbeit geplant ist (UTC). Bei der Eingabe: ISO 8601 mit Zeitzone. kann leer sein (null) |
assigned_user_id
optional
|
string | Der Techniker oder Benutzer, der die Arbeit erledigt, oder null. kann leer sein (null) |
appointment_id
optional
|
string (uuid) | Der Termin, zu dem der Arbeitsauftrag gehört, oder null. kann leer sein (null) |
quote_id
optional
|
string (uuid) | Das Angebot, aus dem der Arbeitsauftrag stammt, oder null. kann leer sein (null) |
language
optional
|
string | Sprache des Arbeitsauftrags: nl, en, de oder fr. einer von: nl, en, de, fr |
items
optional
|
array | Die Positionen (höchstens 200). Bei der Eingabe: eine Liste mit pro Position name (erforderlich) und optional type, description, sku, quantity, unit, unit_price, discount_percentage, discount_amount, tax_rate, is_taxable und minutes; die Liste ersetzt alle Positionen. |
checklist
optional
|
array | Die Checkliste (höchstens 200 Punkte). Bei der Eingabe: pro Punkt label (erforderlich) und optional checked, required und note; die Liste ersetzt die ganze Checkliste. |
Beispielanfrage
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"
}
]
}'$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'];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();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"]Antwort 201
{
"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"
}
}Mögliche Fehler
-
403
insufficient_scope— Dieser API-Schlüssel hat keinen Zugriff auf diese Aktion. -
422
validation_failed— Die Eingabe ist ungültig. -
422
unknown_field— Die Eingabe enthält ein unbekanntes Feld. -
415
unsupported_media_type— Dieses Format wird nicht unterstützt. -
413
payload_too_large— Der Body der Anfrage ist zu groß. -
422
idempotency_key_reused— Dieser Idempotency-Key wurde bereits für eine andere Anfrage verwendet. -
409
idempotency_in_progress— Eine Anfrage mit diesem Idempotency-Key wird noch verarbeitet.
Arbeitsauftrag bearbeiten
/api/v1/work-orders/{work_order}
Ändert nur die Felder, die Sie mitsenden. items und checklist ersetzen die Positionen und die Checkliste als Ganzes; die Positionen erhalten dabei neue IDs. Eine Position und die Summe dürfen 99.999.999,99 nicht übersteigen. Ein abgerechneter Arbeitsauftrag kann nicht mehr geändert werden.
- Scope
-
work_orders.write— Arbeitsaufträge erstellen und bearbeiten sowie den Status ändern (Abschließen kann eine Bewertungsanfrage senden) - Erforderliche Funktion
work_orders
Senden Sie das ETag in If-Match mit, dann überschreiben Sie nie versehentlich eine neuere Version.
Pfadparameter
| Name | Typ | Beschreibung |
|---|---|---|
work_order erforderlich |
string (uuid) | Die ID (UUID) des Arbeitsauftrags. |
Body (JSON)
| Feld | Typ | Beschreibung |
|---|---|---|
title
optional
|
string | Titel. kann leer sein (null) · höchstens 255 Zeichen |
type
optional
|
string | Art der Arbeit, zum Beispiel Installation, Reparatur oder Wartung. kann leer sein (null) · höchstens 64 Zeichen |
location
optional
|
string | Wo die Arbeit stattfindet, wenn nicht an der Adresse des Kunden. kann leer sein (null) · höchstens 255 Zeichen |
description
optional
|
string | Beschreibung der Arbeit oder der Beschwerde. kann leer sein (null) · höchstens 20000 Zeichen |
work_performed
optional
|
string | Was erledigt wurde. kann leer sein (null) · höchstens 20000 Zeichen |
customer_notes
optional
|
string | Hinweise für den Kunden; stehen auf dem Arbeitsauftrag. kann leer sein (null) · höchstens 20000 Zeichen |
scheduled_at
optional
|
string (date-time) | Wann die Arbeit geplant ist (UTC). Bei der Eingabe: ISO 8601 mit Zeitzone. kann leer sein (null) |
assigned_user_id
optional
|
string | Der Techniker oder Benutzer, der die Arbeit erledigt, oder null. kann leer sein (null) |
appointment_id
optional
|
string (uuid) | Der Termin, zu dem der Arbeitsauftrag gehört, oder null. kann leer sein (null) |
quote_id
optional
|
string (uuid) | Das Angebot, aus dem der Arbeitsauftrag stammt, oder null. kann leer sein (null) |
language
optional
|
string | Sprache des Arbeitsauftrags: nl, en, de oder fr. einer von: nl, en, de, fr |
items
optional
|
array | Die Positionen (höchstens 200). Bei der Eingabe: eine Liste mit pro Position name (erforderlich) und optional type, description, sku, quantity, unit, unit_price, discount_percentage, discount_amount, tax_rate, is_taxable und minutes; die Liste ersetzt alle Positionen. |
checklist
optional
|
array | Die Checkliste (höchstens 200 Punkte). Bei der Eingabe: pro Punkt label (erforderlich) und optional checked, required und note; die Liste ersetzt die ganze Checkliste. |
Beispielanfrage
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."
}'$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'];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();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"]Antwort 200
{
"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"
}
}Mögliche Fehler
-
403
insufficient_scope— Dieser API-Schlüssel hat keinen Zugriff auf diese Aktion. -
422
validation_failed— Die Eingabe ist ungültig. -
422
unknown_field— Die Eingabe enthält ein unbekanntes Feld. -
415
unsupported_media_type— Dieses Format wird nicht unterstützt. -
413
payload_too_large— Der Body der Anfrage ist zu groß. -
404
not_found— Nicht gefunden. -
412
precondition_failed— Der Datensatz wurde inzwischen geändert. -
409
invalid_state_transition— Diese Aktion ist im aktuellen Status nicht möglich.
Status eines Arbeitsauftrags ändern
/api/v1/work-orders/{work_order}/status
Setzt den Arbeitsauftrag auf Entwurf, geplant, in Arbeit, abgeschlossen oder storniert. Bei in Arbeit und abgeschlossen werden started_at und completed_at gesetzt. Wie in der App kann das Abschließen dem Kunden eine Bewertungsanfrage senden, wenn das Unternehmen das eingerichtet hat. Abgerechnet setzt nur Klantly selbst.
- Scope
-
work_orders.write— Arbeitsaufträge erstellen und bearbeiten sowie den Status ändern (Abschließen kann eine Bewertungsanfrage senden) - Erforderliche Funktion
work_orders
Senden Sie einen Idempotency-Key mit, dann erzeugt ein erneuter Versuch nach einem Timeout keinen doppelten Datensatz.
Pfadparameter
| Name | Typ | Beschreibung |
|---|---|---|
work_order erforderlich |
string (uuid) | Die ID (UUID) des Arbeitsauftrags. |
Body (JSON)
| Feld | Typ | Beschreibung |
|---|---|---|
status
erforderlich
|
string | draft (Entwurf), planned (geplant), in_progress (in Arbeit), completed (abgeschlossen), invoiced (abgerechnet) oder cancelled (storniert). Beim Erstellen draft oder planned. einer von: draft, planned, in_progress, completed, cancelled |
Beispielanfrage
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"
}'$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'];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();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"]Antwort 200
{
"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"
}
}Mögliche Fehler
-
403
insufficient_scope— Dieser API-Schlüssel hat keinen Zugriff auf diese Aktion. -
422
validation_failed— Die Eingabe ist ungültig. -
422
unknown_field— Die Eingabe enthält ein unbekanntes Feld. -
415
unsupported_media_type— Dieses Format wird nicht unterstützt. -
413
payload_too_large— Der Body der Anfrage ist zu groß. -
404
not_found— Nicht gefunden. -
409
invalid_state_transition— Diese Aktion ist im aktuellen Status nicht möglich. -
422
idempotency_key_reused— Dieser Idempotency-Key wurde bereits für eine andere Anfrage verwendet. -
409
idempotency_in_progress— Eine Anfrage mit diesem Idempotency-Key wird noch verarbeitet.
Arbeitsauftrag löschen
/api/v1/work-orders/{work_order}
Löscht den Arbeitsauftrag. Ein abgerechneter Arbeitsauftrag kann nicht gelöscht werden.
- Scope
-
work_orders.delete— Arbeitsaufträge löschen - Erforderliche Funktion
work_orders
Pfadparameter
| Name | Typ | Beschreibung |
|---|---|---|
work_order erforderlich |
string (uuid) | Die ID (UUID) des Arbeitsauftrags. |
Beispielanfrage
curl -X DELETE "https://app.klantly.com/api/v1/work-orders/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', 'work-orders/9d3f6c1e-4b2a-4c8e-9f1a-2b3c4d5e6f70');
$data = json_decode((string) $response->getBody(), true)['data'];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();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"]Antwort 200
{
"data": {
"object": "note",
"id": "9d3f7b41-2d6f-4e8c-9b3a-4f5d6e7a8b92",
"deleted": true
}
}Mögliche Fehler
-
403
insufficient_scope— Dieser API-Schlüssel hat keinen Zugriff auf diese Aktion. -
404
not_found— Nicht gefunden. -
409
invalid_state_transition— Diese Aktion ist im aktuellen Status nicht möglich.
Das Objekt
Alle Felder sind immer vorhanden; ein Feld ohne Wert ist null.
| Feld | Typ | Beschreibung |
|---|---|---|
object |
string | Immer „work_order“. |
id |
string (uuid) | Eindeutige ID (UUID). |
number |
string | Nummer des Arbeitsauftrags, zum Beispiel WB-2026-00042; vergibt Klantly selbst. |
status |
string | draft (Entwurf), planned (geplant), in_progress (in Arbeit), completed (abgeschlossen), invoiced (abgerechnet) oder cancelled (storniert). Beim Erstellen draft oder planned. einer von: draft, planned, in_progress, completed, invoiced, cancelled |
title |
string | Titel. kann leer sein (null) |
type |
string | Art der Arbeit, zum Beispiel Installation, Reparatur oder Wartung. kann leer sein (null) |
location |
string | Wo die Arbeit stattfindet, wenn nicht an der Adresse des Kunden. kann leer sein (null) |
description |
string | Beschreibung der Arbeit oder der Beschwerde. kann leer sein (null) |
work_performed |
string | Was erledigt wurde. kann leer sein (null) |
customer_notes |
string | Hinweise für den Kunden; stehen auf dem Arbeitsauftrag. kann leer sein (null) |
customer_id |
string (uuid) | Der Kunde. Beim Erstellen erforderlich; Name, Adresse und Kontaktdaten kommen vom Kunden. kann leer sein (null) |
customer |
object | Die Kundendaten auf dem Arbeitsauftrag, wie sie beim Erstellen waren. |
customer.type |
string | individual (Privatperson) oder business (Unternehmen). kann leer sein (null) |
customer.name |
string | Name; bei einem Unternehmen der Firmenname. kann leer sein (null) |
customer.email |
string | E-Mail-Adresse. kann leer sein (null) |
customer.phone |
string | Telefonnummer. kann leer sein (null) |
customer.address |
string | Straße und Hausnummer. kann leer sein (null) |
customer.postal_code |
string | Postleitzahl. kann leer sein (null) |
customer.city |
string | Ort. kann leer sein (null) |
customer.country |
string | Land. kann leer sein (null) |
deal_id |
string (uuid) | Der Deal auf dem Pipeline-Board, oder null. kann leer sein (null) |
appointment_id |
string (uuid) | Der Termin, zu dem der Arbeitsauftrag gehört, oder null. kann leer sein (null) |
quote_id |
string (uuid) | Das Angebot, aus dem der Arbeitsauftrag stammt, oder null. kann leer sein (null) |
invoice_id |
string (uuid) | Die Rechnung des Arbeitsauftrags, oder null. kann leer sein (null) |
assigned_user_id |
string | Der Techniker oder Benutzer, der die Arbeit erledigt, oder null. kann leer sein (null) |
language |
string | Sprache des Arbeitsauftrags: nl, en, de oder fr. einer von: nl, en, de, fr |
currency |
string | Immer „EUR“. |
subtotal |
string | Summe ohne Umsatzsteuer, als Text mit zwei Dezimalstellen. |
tax_amount |
string | Umsatzsteuerbetrag. |
total |
string | Summe inklusive Umsatzsteuer. |
scheduled_at |
string (date-time) | Wann die Arbeit geplant ist (UTC). Bei der Eingabe: ISO 8601 mit Zeitzone. kann leer sein (null) |
started_at |
string (date-time) | Wann die Arbeit begann. kann leer sein (null) |
completed_at |
string (date-time) | Wann die Arbeit fertig war. kann leer sein (null) |
sent_at |
string (date-time) | Wann der Arbeitsauftrag an den Kunden gesendet wurde. kann leer sein (null) |
signature |
object | Die Unterschrift des Kunden (nur die Daten, kein Bild). |
signature.is_signed |
boolean | Ob der Arbeitsauftrag unterschrieben ist. |
signature.signed_by_name |
string | Name der Person, die unterschrieben hat. kann leer sein (null) |
signature.signed_at |
string (date-time) | Wann unterschrieben wurde. kann leer sein (null) |
items |
array<object> | Die Positionen (höchstens 200). Bei der Eingabe: eine Liste mit pro Position name (erforderlich) und optional type, description, sku, quantity, unit, unit_price, discount_percentage, discount_amount, tax_rate, is_taxable und minutes; die Liste ersetzt alle Positionen. |
items.object |
string | Immer „work_order_item“. |
items.id |
string (uuid) | ID der Position. Ändert sich jedes Mal, wenn Sie items senden (die Positionen werden ersetzt). |
items.type |
string | labor (Arbeit), material (Material) oder other. einer von: labor, material, other |
items.name |
string | Bezeichnung auf dem Arbeitsauftrag. |
items.description |
string | Erläuterung. kann leer sein (null) |
items.sku |
string | Artikelnummer. kann leer sein (null) |
items.quantity |
string | Menge. |
items.unit |
string | Einheit, zum Beispiel Stunde oder Stück. kann leer sein (null) |
items.unit_price |
string | Preis pro Einheit ohne Umsatzsteuer. |
items.discount_percentage |
string | Rabatt in Prozent. |
items.discount_amount |
string | Fester Rabatt auf die Position ohne Umsatzsteuer; zählt nur, wenn discount_percentage 0 ist. |
items.line_total |
string | Positionssumme ohne Umsatzsteuer; berechnet Klantly. |
items.is_taxable |
boolean | Ob die Position der Umsatzsteuer unterliegt. |
items.tax_rate |
string | Steuersatz in Prozent (Standard 21, auch wenn das Unternehmen einen anderen Satz verwendet: senden Sie ihn dann mit). |
items.minutes |
integer | Gearbeitete Minuten, bei Arbeit. kann leer sein (null) |
checklist |
array<object> | Die Checkliste (höchstens 200 Punkte). Bei der Eingabe: pro Punkt label (erforderlich) und optional checked, required und note; die Liste ersetzt die ganze Checkliste. |
checklist.object |
string | Immer „work_order_checklist_item“. |
checklist.id |
string (uuid) | ID des Punkts. |
checklist.label |
string | Der Punkt, zum Beispiel „Druck geprüft“. |
checklist.checked |
boolean | Abgehakt. |
checklist.required |
boolean | Muss abgehakt werden. |
checklist.note |
string | Anmerkung zum Punkt. kann leer sein (null) |
photos |
array<object> | Die Fotos zum Arbeitsauftrag (nur die Daten; die Dateien sind noch nicht in der API). |
photos.object |
string | Immer „work_order_photo“. |
photos.id |
string (uuid) | ID des Fotos. |
photos.kind |
string | before (vorher), after (nachher) oder other. kann leer sein (null) · einer von: before, after, other |
photos.caption |
string | Bildunterschrift. kann leer sein (null) |
photos.created_at |
string (date-time) | Hochgeladen am (UTC). |
created_at |
string (date-time) | Erstellt am (UTC). |
updated_at |
string (date-time) | Zuletzt geändert am (UTC). |