Skip to content

Services

Services in BenchKey are labor / service catalog entries, the standardized list of repair types your shop performs (e.g. “Screen Replacement”, “Battery Swap”, “Diagnostic”). Each service has a default labor price and optional auto-match phrases that BenchKey uses to suggest the right category when a technician types a ticket description.

{
"object": "service",
"id": 7,
"name": "Screen Replacement",
"labor_price": {
"amount_cents": 4500,
"amount": "45.00",
"currency": "USD"
},
"match_phrases": ["screen", "lcd", "display", "cracked glass"],
"is_default": false,
"sort_order": 2,
"created_at": "2024-01-10T18:30:00.000Z",
"updated_at": "2025-09-04T11:15:22.000Z"
}
FieldTypeDescription
idintegerUnique service ID
namestringDisplay name of the service / labor category
labor_priceMoney|nullDefault labor charge (amount_cents, amount, currency)
match_phrasesarrayPhrases used to auto-match this service when creating tickets
is_defaultbooleanWhether this is the fallback service when no phrases match
sort_orderintegerDisplay order in the UI (ascending)
created_atstringISO-8601 timestamp
updated_atstringISO-8601 timestamp

GET /api/v1/services

Returns a cursor-paginated list of service catalog entries ordered by sort_order ascending, then id ascending.

Scope required: services.read

ParameterTypeDescription
qstringSearch by name (partial match), max 255 chars
is_defaultbooleanFilter by default status: true/1 returns only the default category, false/0 returns only non-default categories. Omit to return all. Any other value returns 400 invalid_query
limitintegerPage size, 1–100 (default: 20)
cursorstringOpaque cursor from a previous response’s next_cursor
Terminal window
curl "https://app.benchkey.com/api/v1/services?limit=20&q=screen" \
-H "Authorization: Bearer bk_live_01J8X4_kvWz9nP3mRqTs7uYeBfGhDjLa"
const res = await fetch(
"https://app.benchkey.com/api/v1/services?limit=20&q=screen",
{ headers: { Authorization: "Bearer bk_live_01J8X4_kvWz9nP3mRqTs7uYeBfGhDjLa" } }
);
const { data, has_more, next_cursor } = await res.json();
{
"object": "list",
"data": [
{
"object": "service",
"id": 7,
"name": "Screen Replacement",
"labor_price": { "amount_cents": 4500, "amount": "45.00", "currency": "USD" },
"match_phrases": ["screen", "lcd", "display", "cracked glass"],
"is_default": false,
"sort_order": 2,
"created_at": "2024-01-10T18:30:00.000Z",
"updated_at": "2025-09-04T11:15:22.000Z"
}
],
"has_more": false,
"next_cursor": null
}

See Pagination for how to page through results.


GET /api/v1/services/:id

Returns a single service catalog entry by its integer id.

Scope required: services.read

Terminal window
curl "https://app.benchkey.com/api/v1/services/7" \
-H "Authorization: Bearer bk_live_01J8X4_kvWz9nP3mRqTs7uYeBfGhDjLa"
const res = await fetch(
"https://app.benchkey.com/api/v1/services/7",
{ headers: { Authorization: "Bearer bk_live_01J8X4_kvWz9nP3mRqTs7uYeBfGhDjLa" } }
);
const service = await res.json();

Returns the service object. Returns 404 if no service with that ID exists.


POST /api/v1/services

Creates a new labor / service catalog entry.

Scope required: services.write

FieldRequiredDescription
nameyesService name, max 80 characters
labor_centsnoDefault labor charge in cents (integer, 0–10,000,000)
match_phrasesnoArray of strings to auto-match against ticket descriptions (max 50 items; each item max 200 characters, non-empty)
is_defaultnoSet true to mark as the fallback category
sort_ordernoInteger display order (lower = shown first)
Terminal window
curl -X POST https://app.benchkey.com/api/v1/services \
-H "Authorization: Bearer bk_live_01J8X4_kvWz9nP3mRqTs7uYeBfGhDjLa" \
-H "Content-Type: application/json" \
-d '{
"name": "Battery Replacement",
"labor_cents": 2500,
"match_phrases": ["battery", "won'\''t charge", "dead battery"],
"is_default": false,
"sort_order": 3
}'
const res = await fetch("https://app.benchkey.com/api/v1/services", {
method: "POST",
headers: {
Authorization: "Bearer bk_live_01J8X4_kvWz9nP3mRqTs7uYeBfGhDjLa",
"Content-Type": "application/json",
},
body: JSON.stringify({
name: "Battery Replacement",
labor_cents: 2500,
match_phrases: ["battery", "won't charge", "dead battery"],
is_default: false,
sort_order: 3,
}),
});
const service = await res.json(); // HTTP 201

Returns the created service object with HTTP 201.


PATCH /api/v1/services/:id

Updates one or more fields on an existing service. Only fields provided in the request body are changed; omitted fields keep their current values.

Scope required: services.write

At least one field must be included:

FieldDescription
nameNew service name (max 80 characters)
labor_centsNew default labor charge in cents (integer, 0–10,000,000)
match_phrasesReplacement array of auto-match phrases, replaces the full list (max 50 items; each item max 200 characters, non-empty)
is_defaulttrue to make this the default category
sort_orderNew display order integer
Terminal window
curl -X PATCH "https://app.benchkey.com/api/v1/services/7" \
-H "Authorization: Bearer bk_live_01J8X4_kvWz9nP3mRqTs7uYeBfGhDjLa" \
-H "Content-Type: application/json" \
-d '{ "labor_cents": 5000 }'
const res = await fetch("https://app.benchkey.com/api/v1/services/7", {
method: "PATCH",
headers: {
Authorization: "Bearer bk_live_01J8X4_kvWz9nP3mRqTs7uYeBfGhDjLa",
"Content-Type": "application/json",
},
body: JSON.stringify({ labor_cents: 5000 }),
});
const service = await res.json();

Returns the updated service object.


DELETE /api/v1/services/:id

Permanently deletes a service catalog entry. This cannot be undone. Existing tickets that referenced this service are not affected.

Scope required: services.write

Terminal window
curl -X DELETE "https://app.benchkey.com/api/v1/services/7" \
-H "Authorization: Bearer bk_live_01J8X4_kvWz9nP3mRqTs7uYeBfGhDjLa"
const res = await fetch("https://app.benchkey.com/api/v1/services/7", {
method: "DELETE",
headers: { Authorization: "Bearer bk_live_01J8X4_kvWz9nP3mRqTs7uYeBfGhDjLa" },
});
const result = await res.json();
// { "object": "service", "id": 7, "deleted": true }
{
"object": "service",
"id": 7,
"deleted": true
}

HTTP statusCodeMeaning
400invalid_queryA list filter parameter was supplied as an array or object instead of a single scalar value, or is_default is not true/false/1/0
400invalid_idThe :id is not a valid positive integer
400invalid_fieldname is absent, empty, over 80 characters, or has leading/trailing whitespace; labor_cents is not an integer in 0–10,000,000; is_default is not a boolean; sort_order is not a safe integer; q exceeds 255 characters; a match_phrases item is not a string, is empty, exceeds 200 characters, or has leading/trailing whitespace; match_phrases has more than 50 items; any writable field is explicitly null
400nothing_to_updatePATCH body contains none of the recognized updatable fields (name, labor_cents, match_phrases, is_default, sort_order)
422create_failedThe internal service could not be created
422update_failedThe internal service could not be updated
422delete_failedThe internal service could not be deleted
404not_foundNo service with that ID exists
403insufficient_scopeAPI key lacks services.read or services.write

See Errors for the full error envelope format.

System status