Skip to content

Locations

Locations represent physical shops, warehouses, or service branches in BenchKey. Every ticket, invoice, and inventory record is tied to a location. A tenant must have at least one active location; deleting the last one or the last active one is rejected.

{
"object": "location",
"id": 3,
"name": "Downtown Shop",
"address": {
"line1": "400 Congress Ave",
"line2": "Suite 200",
"city": "Austin",
"state": "TX",
"postal_code": "78701",
"country": "US"
},
"phone": "512-555-0100",
"email": "downtown@acmerepair.com",
"timezone": "America/Chicago",
"currency": "USD",
"is_warehouse": false,
"is_active": true,
"sort_order": 0,
"created_at": "2024-01-10T18:00:00.000Z"
}
FieldTypeDescription
idintegerUnique location ID
namestringDisplay name of the location
addressobjectMailing address fields (line1, line2, city, state, postal_code, country)
phonestring|nullLocation phone number
emailstring|nullLocation contact email
timezonestring|nullIANA timezone identifier (e.g. America/Chicago)
currencystring|nullISO 4217 currency code (e.g. USD)
is_warehousebooleanIf true, this location is a warehouse/storage-only location (no customer-facing counter)
is_activebooleanIf false, the location is disabled and hidden from most workflows
sort_orderintegerDisplay order among locations (lower = first)
created_atstringISO-8601 timestamp when the location was created

GET /api/v1/locations

Returns a cursor-paginated list of locations ordered by creation date descending.

Scope required: locations.read

ParameterTypeDescription
is_activebooleanFilter by active status: true or false. Omit to return all.
limitintegerPage size, 1–100 (default: 25)
cursorstringOpaque cursor from a previous response’s next_cursor
Terminal window
curl "https://app.benchkey.com/api/v1/locations?is_active=true" \
-H "Authorization: Bearer bk_live_01J8X4_kvWz9nP3mRqTs7uYeBfGhDjLa"
const res = await fetch(
"https://app.benchkey.com/api/v1/locations?is_active=true",
{ headers: { Authorization: "Bearer bk_live_01J8X4_kvWz9nP3mRqTs7uYeBfGhDjLa" } }
);
const { data, has_more, next_cursor } = await res.json();
{
"object": "list",
"data": [
{
"object": "location",
"id": 3,
"name": "Downtown Shop",
"address": {
"line1": "400 Congress Ave",
"line2": "Suite 200",
"city": "Austin",
"state": "TX",
"postal_code": "78701",
"country": "US"
},
"phone": "512-555-0100",
"email": "downtown@acmerepair.com",
"timezone": "America/Chicago",
"currency": "USD",
"is_warehouse": false,
"is_active": true,
"sort_order": 0,
"created_at": "2024-01-10T18:00:00.000Z"
}
],
"has_more": false,
"next_cursor": null
}

See Pagination for how to page through results.


GET /api/v1/locations/:id

Returns a single location by its integer ID.

Scope required: locations.read

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

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


POST /api/v1/locations

Creates a new location. Requires name. Adding locations may be gated on your billing plan, you will receive a 402 if a plan upgrade is required.

Scope required: locations.write

FieldRequiredDescription
nameyesDisplay name (max 160 characters)
addressnoAddress object: line1, line2, city, state, postal_code, country
phonenoLocation phone number
emailnoLocation contact email
timezonenoIANA timezone identifier (e.g. America/Chicago)
currencynoISO 4217 currency code (e.g. USD)
is_warehousenotrue to designate as a warehouse/storage location (default: false)
is_activenofalse to create the location in a disabled state (default: true)
sort_ordernoDisplay order; lower numbers appear first (default: 0)
Terminal window
curl -X POST https://app.benchkey.com/api/v1/locations \
-H "Authorization: Bearer bk_live_01J8X4_kvWz9nP3mRqTs7uYeBfGhDjLa" \
-H "Content-Type: application/json" \
-d '{
"name": "North Austin Branch",
"address": {
"line1": "9901 Burnet Rd",
"city": "Austin",
"state": "TX",
"postal_code": "78758",
"country": "US"
},
"phone": "512-555-0199",
"timezone": "America/Chicago",
"currency": "USD"
}'
const res = await fetch("https://app.benchkey.com/api/v1/locations", {
method: "POST",
headers: {
Authorization: "Bearer bk_live_01J8X4_kvWz9nP3mRqTs7uYeBfGhDjLa",
"Content-Type": "application/json",
},
body: JSON.stringify({
name: "North Austin Branch",
address: {
line1: "9901 Burnet Rd",
city: "Austin",
state: "TX",
postal_code: "78758",
country: "US",
},
phone: "512-555-0199",
timezone: "America/Chicago",
currency: "USD",
}),
});
const location = await res.json(); // HTTP 201

Returns the created location object with HTTP 201.


PATCH /api/v1/locations/:id

Updates one or more fields on an existing location. Only the fields included in the request body are changed.

Scope required: locations.write

At least one writable field must be provided:

FieldDescription
nameNew display name
addressNew address object (line1, line2, city, state, postal_code, country)
phoneNew phone number
emailNew contact email
timezoneNew IANA timezone identifier
currencyNew ISO 4217 currency code
is_warehouseToggle warehouse designation
is_activeEnable (true) or disable (false) the location
sort_orderNew display sort order
Terminal window
curl -X PATCH "https://app.benchkey.com/api/v1/locations/3" \
-H "Authorization: Bearer bk_live_01J8X4_kvWz9nP3mRqTs7uYeBfGhDjLa" \
-H "Content-Type: application/json" \
-d '{ "phone": "512-555-0111", "sort_order": 1 }'
const res = await fetch("https://app.benchkey.com/api/v1/locations/3", {
method: "PATCH",
headers: {
Authorization: "Bearer bk_live_01J8X4_kvWz9nP3mRqTs7uYeBfGhDjLa",
"Content-Type": "application/json",
},
body: JSON.stringify({ phone: "512-555-0111", sort_order: 1 }),
});
const location = await res.json();

Returns the updated location object.


DELETE /api/v1/locations/:id

Permanently deletes a location. This will fail if the location has inventory on hand, an open register session, or if it is the only remaining location for the tenant.

Scope required: locations.write

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

HTTP statusCodeMeaning
400invalid_idThe :id is not a valid positive integer
400invalid_cursorThe cursor value is malformed
400invalid_paramThe is_active filter is not true or false
400missing_fieldRequired field name is absent on create
400invalid_fieldA typed field has the wrong type, phone, email, timezone, currency must be strings; is_warehouse, is_active must be booleans; sort_order must be a non-negative integer; address must be an object (or null); each address subfield (line1, line2, city, state, postal_code, country) must be a string or null; unrecognized address subfield keys are rejected
400no_fieldsPATCH body is empty
400no_writable_fieldsPATCH body contains no recognized writable fields
400create_failedInternal validation rejected the create input (message includes details)
400update_failedInternal validation rejected the update (message includes details)
400delete_failedLocation could not be deleted, see message for details
404not_foundNo location with that ID exists
422billing_requiredYour plan does not allow adding another location
422conflictLocation has inventory or an open register session and cannot be deleted
403insufficient_scopeAPI key lacks locations.read or locations.write

See Errors for the full error envelope format.

System status