API reference
Service requests
Customer reports (malfunctions, warranty, complaints) with photos: create them from a customer portal for example, assign them and follow their status. The actual work with hours and invoicing is the work order. You link an appointment with appointment_id; signing, picking the moment itself and converting to a work order are done by a person in Klantly or in the app.
Endpoints
-
GET
/servicesList service requests -
GET
/services/{service}Get a service request -
POST
/servicesCreate a service request -
PATCH
/services/{service}Update a service request -
POST
/services/{service}/statusChange the status of a service request -
DELETE
/services/{service}Delete a service request
List service requests
/api/v1/services
A list of service requests, newest first, with photos. Filter by status, priority, customer, employee, quote or change date.
- Scope
-
services.read— Read service requests, with the customer's name, address and contact details - Required feature
work_orders
Query parameters
| Name | Type | Description |
|---|---|---|
limit
|
integer | Number of results per page. from 1 to 100 · default: 50 |
cursor
|
string | The next_cursor or prev_cursor from meta of the previous response. |
sort
|
string | The field to sort on; a minus sign in front means descending. Which fields you can choose and what the default is are listed with this parameter. one of: -created_at, created_at, -updated_at, updated_at · default: -created_at |
filter[status]
|
string | Only requests with this status. one of: draft, planned, in_progress, completed, cancelled |
filter[priority]
|
string | Only requests with this priority. one of: low, normal, high, urgent |
filter[customer_id]
|
string (uuid) | Only what belongs to this customer. |
filter[assigned_user_id]
|
string | Only what is assigned to this user (the id from List users). |
filter[quote_id]
|
string (uuid) | Only what belongs to this quote. |
filter[updated_since]
|
string (date-time) | Only what changed since this moment: ISO 8601 with a time zone, for example 2026-09-14T10:15:00Z. Useful for synchronising. Overlap your previous moment by a few minutes, because the clock of your system and that of Klantly do not run exactly in sync, and because a change made just after your previous moment would otherwise fall just outside it. The boundary is inclusive: something changed exactly at this moment is included. |
Example request
curl "https://app.klantly.com/api/v1/services?filter[status]=planned&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', 'services', [
'query' => [
'filter[status]' => 'planned',
'sort' => '-updated_at',
],
]);
$data = json_decode((string) $response->getBody(), true)['data'];const response = await fetch('https://app.klantly.com/api/v1/services?filter[status]=planned&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/services",
headers={
"Authorization": f"Bearer {os.environ['KLANTLY_API_KEY']}",
},
params={
"filter[status]": "planned",
"sort": "-updated_at"
},
)
data = response.json()["data"]Response 200
The response is a list with cursor pagination: data contains the objects, meta the pagination.
{
"data": [
{
"object": "service",
"id": "9d3f8339-9ed1-4f6e-8dbc-c1dfe0f1a2bb",
"number": "SV-2026-00042",
"status": "planned",
"priority": "high",
"category": "malfunction",
"title": "Lekkage bij de dakgoot",
"location": null,
"description": "Water loopt langs de gevel na regen.",
"resolution": 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"
},
"quote_id": null,
"appointment_id": null,
"work_order_id": null,
"assigned_user_id": "usr_0k3j9x21m4zq8p",
"language": "nl",
"reported_at": null,
"scheduled_at": "2026-10-01T08:00:00Z",
"started_at": null,
"completed_at": null,
"signature": {
"is_signed": false,
"signed_by_name": null,
"signed_at": 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
}
}Possible errors
-
403
insufficient_scope— This API key has no access to this action. -
422
validation_failed— The input is invalid.
Get a service request
/api/v1/services/{service}
One service request by id, with photos (including a download link) and the state of the signature.
- Scope
-
services.read— Read service requests, with the customer's name, address and contact details - Required feature
work_orders
Path parameters
| Name | Type | Description |
|---|---|---|
service required |
string (uuid) | The id (UUID) of the service request. |
Example request
curl "https://app.klantly.com/api/v1/services/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', 'services/9d3f6c1e-4b2a-4c8e-9f1a-2b3c4d5e6f70');
$data = json_decode((string) $response->getBody(), true)['data'];const response = await fetch('https://app.klantly.com/api/v1/services/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/services/9d3f6c1e-4b2a-4c8e-9f1a-2b3c4d5e6f70",
headers={
"Authorization": f"Bearer {os.environ['KLANTLY_API_KEY']}",
},
)
data = response.json()["data"]Response 200
{
"data": {
"object": "service",
"id": "9d3f8339-9ed1-4f6e-8dbc-c1dfe0f1a2bb",
"number": "SV-2026-00042",
"status": "planned",
"priority": "high",
"category": "malfunction",
"title": "Lekkage bij de dakgoot",
"location": null,
"description": "Water loopt langs de gevel na regen.",
"resolution": 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"
},
"quote_id": null,
"appointment_id": null,
"work_order_id": null,
"assigned_user_id": "usr_0k3j9x21m4zq8p",
"language": "nl",
"reported_at": null,
"scheduled_at": "2026-10-01T08:00:00Z",
"started_at": null,
"completed_at": null,
"signature": {
"is_signed": false,
"signed_by_name": null,
"signed_at": null
},
"photos": [],
"created_at": "2026-09-14T10:15:00Z",
"updated_at": "2026-09-14T10:15:00Z"
}
}Possible errors
-
403
insufficient_scope— This API key has no access to this action. -
404
not_found— Not found.
Create a service request
/api/v1/services
Creates a request for a customer, as a draft or scheduled. Klantly gives it a number from its own series (SV-year-sequence by default); name, address and contact details come from the customer. Without reported_at, that is the moment of creation.
- Scope
-
services.write— Create and change service requests, change their status and add photos - Required feature
work_orders
Send an Idempotency-Key and a retry after a timeout will never create a duplicate record.
Body (JSON)
| Field | Type | Description |
|---|---|---|
customer_id
required
|
string (uuid) | The customer. Required on create; name, address and contact details come from the customer. |
title
required
|
string | Subject of the request. Required on create. at most 255 characters |
status
optional
|
string | draft, planned (scheduled), in_progress, completed or cancelled. On create: draft or planned. one of: draft, planned |
category
optional
|
string | Type of request, for example malfunction, warranty, maintenance, complaint, question or other. Free text: a company may use its own types. can be empty (null) · at most 64 characters |
priority
optional
|
string | low, normal, high or urgent. Defaults to normal. one of: low, normal, high, urgent |
location
optional
|
string | Where the problem is, if that is not the customer’s address. can be empty (null) · at most 255 characters |
description
optional
|
string | The problem as the customer reports it. can be empty (null) · at most 20000 characters |
resolution
optional
|
string | What was done to solve it. can be empty (null) · at most 20000 characters |
customer_notes
optional
|
string | Remarks for the customer. can be empty (null) · at most 20000 characters |
reported_at
optional
|
string (date-time) | When the request came in (UTC). Empty on create means the moment of creation. On input: ISO 8601 with a time zone. can be empty (null) |
scheduled_at
optional
|
string (date-time) | When the service visit is scheduled (UTC). On input: ISO 8601 with a time zone. can be empty (null) |
assigned_user_id
optional
|
string | The employee handling the request, or null. can be empty (null) |
appointment_id
optional
|
string (uuid) | The appointment for the service visit, or null. can be empty (null) |
quote_id
optional
|
string (uuid) | The quote the request belongs to, or null. can be empty (null) |
language
optional
|
string | Language of the request: nl, en, de or fr. one of: nl, en, de, fr |
Example request
curl -X POST "https://app.klantly.com/api/v1/services" \
-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": "Lekkage bij de dakgoot",
"category": "malfunction",
"priority": "high",
"description": "Water loopt langs de gevel na regen."
}'$client = new \GuzzleHttp\Client([
'base_uri' => 'https://app.klantly.com/api/v1/',
'headers' => ['Authorization' => 'Bearer ' . getenv('KLANTLY_API_KEY')],
]);
$response = $client->request('POST', 'services', [
'headers' => [
'Idempotency-Key' => '6f1c2d3e-4a5b-4c6d-8e7f-9a0b1c2d3e4f',
],
'json' => [
'customer_id' => '9d3f6c1e-4b2a-4c8e-9f1a-2b3c4d5e6f70',
'title' => 'Lekkage bij de dakgoot',
'category' => 'malfunction',
'priority' => 'high',
'description' => 'Water loopt langs de gevel na regen.',
],
]);
$data = json_decode((string) $response->getBody(), true)['data'];const response = await fetch('https://app.klantly.com/api/v1/services', {
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": "Lekkage bij de dakgoot",
"category": "malfunction",
"priority": "high",
"description": "Water loopt langs de gevel na regen."
}),
});
const { data } = await response.json();import os
import requests
response = requests.post(
"https://app.klantly.com/api/v1/services",
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": "Lekkage bij de dakgoot",
"category": "malfunction",
"priority": "high",
"description": "Water loopt langs de gevel na regen."
},
)
data = response.json()["data"]Response 201
{
"data": {
"object": "service",
"id": "9d3f8339-9ed1-4f6e-8dbc-c1dfe0f1a2bb",
"number": "SV-2026-00042",
"status": "planned",
"priority": "high",
"category": "malfunction",
"title": "Lekkage bij de dakgoot",
"location": null,
"description": "Water loopt langs de gevel na regen.",
"resolution": 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"
},
"quote_id": null,
"appointment_id": null,
"work_order_id": null,
"assigned_user_id": "usr_0k3j9x21m4zq8p",
"language": "nl",
"reported_at": null,
"scheduled_at": "2026-10-01T08:00:00Z",
"started_at": null,
"completed_at": null,
"signature": {
"is_signed": false,
"signed_by_name": null,
"signed_at": null
},
"photos": [],
"created_at": "2026-09-14T10:15:00Z",
"updated_at": "2026-09-14T10:15:00Z"
}
}Possible errors
-
403
insufficient_scope— This API key has no access to this action. -
422
validation_failed— The input is invalid. -
422
unknown_field— The input contains an unknown field. -
415
unsupported_media_type— This format is not supported. -
413
payload_too_large— The request body is too large. -
422
idempotency_key_reused— This Idempotency-Key was already used for a different request. -
409
idempotency_in_progress— A request with this Idempotency-Key is still in progress.
Update a service request
/api/v1/services/{service}
Only changes the fields you send. You do not set the work-order link yourself: it appears when you convert the request in Klantly.
- Scope
-
services.write— Create and change service requests, change their status and add photos - Required feature
work_orders
Send the ETag in If-Match and you will never accidentally overwrite a newer version.
Path parameters
| Name | Type | Description |
|---|---|---|
service required |
string (uuid) | The id (UUID) of the service request. |
Body (JSON)
| Field | Type | Description |
|---|---|---|
title
optional
|
string | Subject of the request. Required on create. at most 255 characters |
category
optional
|
string | Type of request, for example malfunction, warranty, maintenance, complaint, question or other. Free text: a company may use its own types. can be empty (null) · at most 64 characters |
priority
optional
|
string | low, normal, high or urgent. Defaults to normal. one of: low, normal, high, urgent |
location
optional
|
string | Where the problem is, if that is not the customer’s address. can be empty (null) · at most 255 characters |
description
optional
|
string | The problem as the customer reports it. can be empty (null) · at most 20000 characters |
resolution
optional
|
string | What was done to solve it. can be empty (null) · at most 20000 characters |
customer_notes
optional
|
string | Remarks for the customer. can be empty (null) · at most 20000 characters |
reported_at
optional
|
string (date-time) | When the request came in (UTC). Empty on create means the moment of creation. On input: ISO 8601 with a time zone. can be empty (null) |
scheduled_at
optional
|
string (date-time) | When the service visit is scheduled (UTC). On input: ISO 8601 with a time zone. can be empty (null) |
assigned_user_id
optional
|
string | The employee handling the request, or null. can be empty (null) |
appointment_id
optional
|
string (uuid) | The appointment for the service visit, or null. can be empty (null) |
quote_id
optional
|
string (uuid) | The quote the request belongs to, or null. can be empty (null) |
language
optional
|
string | Language of the request: nl, en, de or fr. one of: nl, en, de, fr |
Example request
curl -X PATCH "https://app.klantly.com/api/v1/services/9d3f6c1e-4b2a-4c8e-9f1a-2b3c4d5e6f70" \
-H "Authorization: Bearer $KLANTLY_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"resolution": "Goot opnieuw afgekit en getest."
}'$client = new \GuzzleHttp\Client([
'base_uri' => 'https://app.klantly.com/api/v1/',
'headers' => ['Authorization' => 'Bearer ' . getenv('KLANTLY_API_KEY')],
]);
$response = $client->request('PATCH', 'services/9d3f6c1e-4b2a-4c8e-9f1a-2b3c4d5e6f70', [
'json' => [
'resolution' => 'Goot opnieuw afgekit en getest.',
],
]);
$data = json_decode((string) $response->getBody(), true)['data'];const response = await fetch('https://app.klantly.com/api/v1/services/9d3f6c1e-4b2a-4c8e-9f1a-2b3c4d5e6f70', {
method: 'PATCH',
headers: {
Authorization: `Bearer ${process.env.KLANTLY_API_KEY}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
"resolution": "Goot opnieuw afgekit en getest."
}),
});
const { data } = await response.json();import os
import requests
response = requests.patch(
"https://app.klantly.com/api/v1/services/9d3f6c1e-4b2a-4c8e-9f1a-2b3c4d5e6f70",
headers={
"Authorization": f"Bearer {os.environ['KLANTLY_API_KEY']}",
},
json={
"resolution": "Goot opnieuw afgekit en getest."
},
)
data = response.json()["data"]Response 200
{
"data": {
"object": "service",
"id": "9d3f8339-9ed1-4f6e-8dbc-c1dfe0f1a2bb",
"number": "SV-2026-00042",
"status": "planned",
"priority": "high",
"category": "malfunction",
"title": "Lekkage bij de dakgoot",
"location": null,
"description": "Water loopt langs de gevel na regen.",
"resolution": 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"
},
"quote_id": null,
"appointment_id": null,
"work_order_id": null,
"assigned_user_id": "usr_0k3j9x21m4zq8p",
"language": "nl",
"reported_at": null,
"scheduled_at": "2026-10-01T08:00:00Z",
"started_at": null,
"completed_at": null,
"signature": {
"is_signed": false,
"signed_by_name": null,
"signed_at": null
},
"photos": [],
"created_at": "2026-09-14T10:15:00Z",
"updated_at": "2026-09-14T10:15:00Z"
}
}Possible errors
-
403
insufficient_scope— This API key has no access to this action. -
422
validation_failed— The input is invalid. -
422
unknown_field— The input contains an unknown field. -
415
unsupported_media_type— This format is not supported. -
413
payload_too_large— The request body is too large. -
404
not_found— Not found. -
412
precondition_failed— The record has been changed in the meantime.
Change the status of a service request
/api/v1/services/{service}/status
Sets the request to draft, scheduled, in progress, completed or cancelled. For in progress and completed, started_at and completed_at are stamped. If "signature required for service" is on in the work-order settings, an unsigned request cannot be completed (invalid_state_transition).
- Scope
-
services.write— Create and change service requests, change their status and add photos - Required feature
work_orders
Send an Idempotency-Key and a retry after a timeout will never create a duplicate record.
Path parameters
| Name | Type | Description |
|---|---|---|
service required |
string (uuid) | The id (UUID) of the service request. |
Body (JSON)
| Field | Type | Description |
|---|---|---|
status
required
|
string | draft, planned (scheduled), in_progress, completed or cancelled. On create: draft or planned. one of: draft, planned, in_progress, completed, cancelled |
Example request
curl -X POST "https://app.klantly.com/api/v1/services/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', 'services/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/services/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/services/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"]Response 200
{
"data": {
"object": "service",
"id": "9d3f8339-9ed1-4f6e-8dbc-c1dfe0f1a2bb",
"number": "SV-2026-00042",
"status": "planned",
"priority": "high",
"category": "malfunction",
"title": "Lekkage bij de dakgoot",
"location": null,
"description": "Water loopt langs de gevel na regen.",
"resolution": 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"
},
"quote_id": null,
"appointment_id": null,
"work_order_id": null,
"assigned_user_id": "usr_0k3j9x21m4zq8p",
"language": "nl",
"reported_at": null,
"scheduled_at": "2026-10-01T08:00:00Z",
"started_at": null,
"completed_at": null,
"signature": {
"is_signed": false,
"signed_by_name": null,
"signed_at": null
},
"photos": [],
"created_at": "2026-09-14T10:15:00Z",
"updated_at": "2026-09-14T10:15:00Z"
}
}Possible errors
-
403
insufficient_scope— This API key has no access to this action. -
422
validation_failed— The input is invalid. -
422
unknown_field— The input contains an unknown field. -
415
unsupported_media_type— This format is not supported. -
413
payload_too_large— The request body is too large. -
404
not_found— Not found. -
409
invalid_state_transition— This action is not possible in the current status. -
422
idempotency_key_reused— This Idempotency-Key was already used for a different request. -
409
idempotency_in_progress— A request with this Idempotency-Key is still in progress.
Delete a service request
/api/v1/services/{service}
Deletes the request, including its photos.
- Scope
-
services.delete— Delete service requests - Required feature
work_orders
Path parameters
| Name | Type | Description |
|---|---|---|
service required |
string (uuid) | The id (UUID) of the service request. |
Example request
curl -X DELETE "https://app.klantly.com/api/v1/services/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', 'services/9d3f6c1e-4b2a-4c8e-9f1a-2b3c4d5e6f70');
$data = json_decode((string) $response->getBody(), true)['data'];const response = await fetch('https://app.klantly.com/api/v1/services/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/services/9d3f6c1e-4b2a-4c8e-9f1a-2b3c4d5e6f70",
headers={
"Authorization": f"Bearer {os.environ['KLANTLY_API_KEY']}",
},
)
data = response.json()["data"]Response 200
{
"data": {
"object": "note",
"id": "9d3f7b41-2d6f-4e8c-9b3a-4f5d6e7a8b92",
"deleted": true
}
}Possible errors
-
403
insufficient_scope— This API key has no access to this action. -
404
not_found— Not found.
The object
All fields are always present; a field without a value is null.
| Field | Type | Description |
|---|---|---|
object |
string | Always "service". |
id |
string (uuid) | Unique id (UUID). |
number |
string | Number of the request, for example SV-2026-00042; Klantly assigns it from its own series, separate from work orders. |
status |
string | draft, planned (scheduled), in_progress, completed or cancelled. On create: draft or planned. one of: draft, planned, in_progress, completed, cancelled |
priority |
string | low, normal, high or urgent. Defaults to normal. one of: low, normal, high, urgent |
category |
string | Type of request, for example malfunction, warranty, maintenance, complaint, question or other. Free text: a company may use its own types. can be empty (null) |
title |
string | Subject of the request. Required on create. |
location |
string | Where the problem is, if that is not the customer’s address. can be empty (null) |
description |
string | The problem as the customer reports it. can be empty (null) |
resolution |
string | What was done to solve it. can be empty (null) |
customer_notes |
string | Remarks for the customer. can be empty (null) |
customer_id |
string (uuid) | The customer. Required on create; name, address and contact details come from the customer. can be empty (null) |
customer |
object | The customer details on the request, as they were when it was created. |
customer.type |
string | individual or business. can be empty (null) |
customer.name |
string | Name; for a business, the company name. can be empty (null) |
customer.email |
string | Email address. can be empty (null) |
customer.phone |
string | Phone number. can be empty (null) |
customer.address |
string | Street and house number. can be empty (null) |
customer.postal_code |
string | Postal code. can be empty (null) |
customer.city |
string | City. can be empty (null) |
customer.country |
string | Country. can be empty (null) |
quote_id |
string (uuid) | The quote the request belongs to, or null. can be empty (null) |
appointment_id |
string (uuid) | The appointment for the service visit, or null. can be empty (null) |
work_order_id |
string (uuid) | The work order that came out of this request, or null. You do not set this yourself: it appears when the request is converted in Klantly. can be empty (null) |
assigned_user_id |
string | The employee handling the request, or null. can be empty (null) |
language |
string | Language of the request: nl, en, de or fr. one of: nl, en, de, fr |
reported_at |
string (date-time) | When the request came in (UTC). Empty on create means the moment of creation. On input: ISO 8601 with a time zone. can be empty (null) |
scheduled_at |
string (date-time) | When the service visit is scheduled (UTC). On input: ISO 8601 with a time zone. can be empty (null) |
started_at |
string (date-time) | When work on the request started. can be empty (null) |
completed_at |
string (date-time) | When the request was completed. can be empty (null) |
signature |
object | The customer’s signature on handover (details only, no image). |
signature.is_signed |
boolean | Whether the request has been signed. |
signature.signed_by_name |
string | Name of the signatory. can be empty (null) |
signature.signed_at |
string (date-time) | When it was signed. can be empty (null) |
photos |
array<object> | The photos on the request. Uploading goes through POST /services/{id}/photos. |
photos.object |
string | Always "service_photo". |
photos.id |
string (uuid) | Id of the photo. |
photos.kind |
string | issue (the report), progress, completion (the handover) or other. can be empty (null) · one of: issue, progress, completion, other |
photos.caption |
string | Caption of the photo. can be empty (null) |
photos.download_url |
string (uri) | A signed link to the photo, valid for fifteen minutes and openable without an API key. |
photos.created_at |
string (date-time) | When the photo was added (UTC). |
created_at |
string (date-time) | When the request was created (UTC). |
updated_at |
string (date-time) | When the request last changed (UTC). |