Skip to content

Assets

An asset is a physical device (phone, laptop, console, etc.) tracked across repair visits. Assets are keyed by serial number within a tenant. Each asset optionally links to a customer and exposes a small customer summary so you can render a device without a second call. Archived assets are excluded from list results by default.

{
"object": "asset",
"id": "4821",
"serial_number": "C02XG2JHJGH5",
"imei": null,
"asset_tag": "R-0042",
"make": "Apple",
"model": "MacBook Pro 14\"",
"device_type": "Laptop",
"notes": "Customer reported random shutdowns",
"status": "active",
"customer_id": "109",
"customer_email": "jane@example.com",
"customer": {
"object": "asset_customer",
"id": "109",
"name": "Jane Smith",
"email": "jane@example.com"
},
"first_seen_at": "2024-03-10T14:22:00Z",
"last_seen_at": "2025-01-08T09:45:00Z",
"archived_at": null,
"created_at": "2024-03-10T14:22:00Z",
"updated_at": "2025-01-08T09:45:00Z"
}
FieldTypeDescription
idstringUnique asset id
serial_numberstring|nullDevice serial number (unique per tenant)
imeistring|nullDevice IMEI. Device identity internally is serial or IMEI, so both are readable here. Read-only via the API, captured at ticket intake
asset_tagstring|nullInternal shop tag (e.g. a barcode label)
makestring|nullManufacturer (e.g. Apple, Samsung)
modelstring|nullModel name
device_typestring|nullCategory (e.g. Phone, Laptop, Game Console)
notesstring|nullFree-text notes about the device
statusstring|nullactive, archived, or written_off
customer_idstring|nullLinked customer id
customer_emailstring|nullCustomer email address stored on the asset row (used to match a customer at create time)
customerobject|nullSmall customer summary (id, name, email) or null (present only when the linked customer record loads)
first_seen_atstring|nullISO-8601 timestamp of the first repair intake
last_seen_atstring|nullISO-8601 timestamp of the most recent repair intake
archived_atstring|nullISO-8601 timestamp when the asset was archived, or null
created_atstring|nullISO-8601 creation timestamp
updated_atstring|nullISO-8601 last-update timestamp

GET /api/v1/assets

Returns a cursor-paginated list of assets, newest first. Archived assets are hidden by default.

Scope required: assets.read

ParameterTypeDescription
customer_idstringFilter to a single customer’s devices
statusstringFilter by status (active, archived, written_off)
device_typestringFilter by device type
qstringFull-text search across serial number, IMEI, asset tag, make, and model
updated_sincestringOnly assets updated at or after this time (ISO-8601 or Unix timestamp in seconds/milliseconds)
include_archivedbooleanSet to true to include archived assets (default false). Accepted values: true/false/1/0/yes/no. Any other value returns 400 invalid_filter
limitintegerPage size, 1–100 (default 25)
cursorstringOpaque cursor from a previous response
Terminal window
curl "https://app.benchkey.com/api/v1/assets?limit=10&q=macbook" \
-H "Authorization: Bearer bk_live_<tenantId>_<secret>"
const res = await fetch(
"https://app.benchkey.com/api/v1/assets?limit=10&q=macbook",
{ headers: { Authorization: "Bearer bk_live_<tenantId>_<secret>" } }
);
const { data, has_more, next_cursor } = await res.json();
console.log(`Got ${data.length} assets, has_more=${has_more}`);
{
"object": "list",
"data": [
{
"object": "asset",
"id": "4821",
"serial_number": "C02XG2JHJGH5",
"make": "Apple",
"model": "MacBook Pro 14\"",
"status": "active",
"customer_id": "109",
"customer": { "object": "asset_customer", "id": "109", "name": "Jane Smith", "email": "jane@example.com" },
"created_at": "2024-03-10T14:22:00Z",
"updated_at": "2025-01-08T09:45:00Z"
}
],
"has_more": false,
"next_cursor": null
}

GET /api/v1/assets/:id

Fetch a single asset by its numeric id.

Scope required: assets.read

Terminal window
curl https://app.benchkey.com/api/v1/assets/4821 \
-H "Authorization: Bearer bk_live_<tenantId>_<secret>"
const res = await fetch("https://app.benchkey.com/api/v1/assets/4821", {
headers: { Authorization: "Bearer bk_live_<tenantId>_<secret>" },
});
const asset = await res.json();
console.log(asset.serial_number); // "C02XG2JHJGH5"

Returns a single asset object. Returns 404 if no asset with that id exists.

Archived assets return 404 by default. GET /:id applies the same visibility filter as the list: archived assets are hidden unless you pass ?include_archived=true. Pass a typo’d value (e.g. include_archived=ture) and the endpoint returns 400 invalid_filter rather than silently using the default.


POST /api/v1/assets

Creates a new asset and links it to a customer. You must supply at least one of customer_id or customer_email to identify the owning customer, plus serial_number. Returns 409 if the serial number is already registered for the tenant.

Scope required: assets.write

FieldTypeRequiredDescription
serial_numberstringYesDevice serial number, must be unique per tenant
customer_idstringOne of customer_id/customer_emailLink to an existing customer by id, must be a positive integer and the customer must exist; an unknown id returns 400 invalid_field
customer_emailstringOne of customer_id/customer_emailMatch a customer by email if customer_id is not known, must be a valid email address (user@domain.tld); malformed values return 400 invalid_field
asset_tagstringNoInternal barcode/label
makestringNoManufacturer
modelstringNoModel name
device_typestringNoDevice category
notesstringNoFree-text notes
Terminal window
curl -X POST https://app.benchkey.com/api/v1/assets \
-H "Authorization: Bearer bk_live_<tenantId>_<secret>" \
-H "Content-Type: application/json" \
-d '{
"customer_id": "109",
"serial_number": "C02XG2JHJGH5",
"make": "Apple",
"model": "MacBook Pro 14\"",
"device_type": "Laptop"
}'
const res = await fetch("https://app.benchkey.com/api/v1/assets", {
method: "POST",
headers: {
Authorization: "Bearer bk_live_<tenantId>_<secret>",
"Content-Type": "application/json",
},
body: JSON.stringify({
customer_id: "109",
serial_number: "C02XG2JHJGH5",
make: "Apple",
model: 'MacBook Pro 14"',
device_type: "Laptop",
}),
});
const asset = await res.json();
console.log(asset.id); // "4821"

201 Created with the new asset object. The Location header points to the created resource.


PATCH /api/v1/assets/:id

Updates one or more mutable fields on an asset. At least one field must be supplied. Returns the re-read asset object.

Transitioning status to archived or written_off automatically stamps archived_at; transitioning back to active clears it.

Scope required: assets.write

FieldTypeNotes
asset_tagstringInternal label
makestringManufacturer
modelstringModel name
device_typestringDevice category
serial_numberstringMust remain unique per tenant
notesstringFree-text notes
statusstringactive, archived, or written_off
Terminal window
curl -X PATCH https://app.benchkey.com/api/v1/assets/4821 \
-H "Authorization: Bearer bk_live_<tenantId>_<secret>" \
-H "Content-Type: application/json" \
-d '{"status": "archived", "notes": "Beyond economic repair"}'
const res = await fetch("https://app.benchkey.com/api/v1/assets/4821", {
method: "PATCH",
headers: {
Authorization: "Bearer bk_live_<tenantId>_<secret>",
"Content-Type": "application/json",
},
body: JSON.stringify({ status: "archived", notes: "Beyond economic repair" }),
});
const asset = await res.json();
console.log(asset.archived_at); // "2025-06-14T12:00:00Z"

Returns the updated asset object.


HTTP statusCodeMeaning
400invalid_idThe :id path segment is not a valid integer
400missing_customerNeither customer_id nor customer_email was supplied (a blank or whitespace-only customer_id also counts as absent)
400missing_fieldserial_number is required but was not provided
400invalid_fieldA field value is the wrong type, serial_number is blank, customer_email is not a valid email address, or customer_id does not match any customer in this tenant
400invalid_queryA list filter parameter (including updated_since) was supplied as an array or object instead of a single scalar string
400invalid_filterupdated_since is not a parseable date/timestamp, or include_archived is not a recognized boolean (true/false/1/0/yes/no)
400no_fieldsPATCH body contained no writable fields
400invalid_requestThe backend rejected the request (invalid input from the internal route)
401unauthorizedMissing or invalid API key
403insufficient_scopeAPI key lacks assets.read or assets.write scope
404not_foundNo asset with that id in this tenant
409serial_conflictThat serial number is already registered for this tenant
422create_failedThe asset could not be created
422unprocessableThe write operation could not be processed (fallback)
422write_failedThe asset operation could not be completed (update or delete)
System status