Skip to documentation
Openshelf

Openshelf Integration Relay

v1.0.0

Last updated UTC · OpenAPI JSON

Cloud API for integrating inventory and asynchronous store/retrieve operations with provisioned Openshelf devices. Device IDs and API keys are supplied during onboarding; this API does not expose device administration or low-level hardware controls.

Base URL: https://api.opshelf.com. Append the documented /v1/... path (or /healthz for the service health check).

First integration

  1. Exchange your provisioned X-API-Key at POST /v1/auth/token.
  2. Send Authorization: Bearer <access_token> on subsequent /v1 requests.
  3. Check your device, create/read its inventory item, then submit a command with a stable request_id.
  4. Save the accepted command_id and poll its result, or register a webhook before submission.

Inventory records and physical storage are distinct: creating a record does not move an item. Successful submission means acceptance, not completion. Bin-managed items are visible but cannot be retrieved through the direct command API.

Errors and limits

Errors contain code, message, and correlation_id. Preserve the response X-Correlation-ID for support; you may supply a 1–128 character ID using letters, digits, dot, underscore, or hyphen. Unknown and unauthorized devices both return 404.

Authenticated routes share a per-key limit of five requests/second with a burst of 20. Token exchange allows a burst of five per source IP, replenishing at five/minute. Mutation bodies are limited to 64 KiB. On 429, honor Retry-After when present; otherwise back off. Retry uncertain commands with the same request ID and payload. Resolve 409/423 state conflicts before retrying; do not blindly replay physical work.

Dimensions are millimeters, weight is grams, and location indices are zero-based. The local engineering API is documented separately at Local API. Schemas here describe the cloud contract; not every local field or command is exposed.

Authentication

  • HTTPBearer — http bearer
  • PartnerApiKey — apiKey in header (X-API-Key)

    Provisioned partner key, used only for token exchange.

authentication

Exchange a provisioned API key for a short-lived bearer token.

post /v1/auth/token

Exchange an API key for an access token

Send the provisioned key in X-API-Key; no request body is required. Use the returned token as Authorization: Bearer <access_token> on /v1 requests. expires_in is seconds from issuance. Obtain another token when it expires; there is no refresh-token endpoint. Token exchange is limited to a burst of five requests per source IP, replenishing at five per minute.

Requires PartnerApiKey authentication.

Parameters

Name Type Description
X-API-Key
header
string | null

Provisioned partner API key; exchange it for a bearer token.

Responses

200 Successful Response

application/json · TokenResponse

Name Type Description
access_token required
string —
expires_in required
integer

Access-token lifetime in seconds from issuance

token_type
"bearer" —

default "bearer"

devices

Check availability of a device assigned to your API key.

get /v1/devices/{device_id}/health

Check device availability

Checks the authorized device through its backend. Returns 503 when it cannot serve requests and 404 for unknown or unauthorized device IDs. A successful check is not a reservation or a guarantee that a subsequent command can run.

Requires HTTPBearer authentication.

Parameters

Name Type Description
device_id required
path
string

Device identifier supplied during onboarding.

Responses

200 Successful Response

application/json · HealthResponse

Name Type Description
status
"ok" —

default "ok"

items

Inventory records, actionable locations, and barcode printing. Inventory edits do not move hardware.

get /v1/devices/{device_id}/items

List device inventory

Returns an offset-based page and the total inventory count. Dimensions are millimeters and weight is grams. Inventory records may exist without a storage location. For bin-managed items, locations is empty and direct retrieval is unavailable. Pagination is not a snapshot: concurrent inventory changes can affect subsequent pages.

Requires HTTPBearer authentication.

Parameters

Name Type Description
device_id required
path
string

Device identifier supplied during onboarding.

skip
query
integer

Number of inventory records to skip

limit
query
integer

Maximum records in this page

Responses

200 Successful Response

application/json · ItemListResponse

Name Type Description
items required
array<ItemResponse> —
barcode required
string —
created_at
string | null —
dimensions required
ItemDimensionsResponse —
height required
number —
length required
number —
width required
number —
full_net_weight
number | null —
id required
integer —
locations
array<ItemLocationResponse>

Directly actionable storage locations; always empty for bin-managed items.

cell_idx required
integer —
shelf_idx required
integer —
side required
string —

one of "front_module", "back_module"

metadata
object —
name required
string —
net_weight
number | null —
storage_mode required
string

How the item is stored. Bin-managed items cannot be retrieved directly.

one of "direct", "bin"

tare_weight
number | null —
updated_at
string | null —
weight
number | null —
limit required
integer —
skip required
integer —
total required
integer —
post /v1/devices/{device_id}/items

Create or replace an inventory record

Creates an item or updates the record with the same barcode on the device. This changes inventory only; submit a store_item command to move the item physically. Supply positive dimensions in millimeters. For an existing record, prefer the item update endpoint for partial edits. Reserved bin barcodes and forbidden changes to bin-managed items return 409.

Requires HTTPBearer authentication.

Parameters

Name Type Description
device_id required
path
string

Device identifier supplied during onboarding.

Request body required application/json

Name Type Description
barcode required
string

Inventory barcode identifier; customer formats are accepted. Print a label separately through the device print endpoint.

min length 1 · max length 255

dimensions required
Dimensions —
height required
number

Height in millimeters

> 0

length required
number

Length in millimeters

> 0

width required
number

Width in millimeters

> 0

full_net_weight
number | null

Full contents mass in grams

metadata
object —
name required
string —

min length 1 · max length 255

net_weight
number | null

Current contents mass in grams

tare_weight
number | null

Empty container mass in grams

weight
number | null

Gross item mass in grams; null is not forwarded on writes.

Responses

200 Successful Response

application/json · ItemResponse

Name Type Description
barcode required
string —
created_at
string | null —
dimensions required
ItemDimensionsResponse —
height required
number —
length required
number —
width required
number —
full_net_weight
number | null —
id required
integer —
locations
array<ItemLocationResponse>

Directly actionable storage locations; always empty for bin-managed items.

cell_idx required
integer —
shelf_idx required
integer —
side required
string —

one of "front_module", "back_module"

metadata
object —
name required
string —
net_weight
number | null —
storage_mode required
string

How the item is stored. Bin-managed items cannot be retrieved directly.

one of "direct", "bin"

tare_weight
number | null —
updated_at
string | null —
weight
number | null —
post /v1/devices/{device_id}/items/delete

Delete an unstored inventory record

Retrieve the item before deleting its record. Returns 409 with item_still_stored for occupied locations or item_in_bin for bin membership. Deletion does not issue a robot command.

Requires HTTPBearer authentication.

Parameters

Name Type Description
device_id required
path
string

Device identifier supplied during onboarding.

Request body required application/json

Name Type Description
barcode required
string

Inventory barcode of the record to delete; customer formats are accepted.

min length 1 · max length 255

Responses

200 Successful Response

application/json · DeleteItemResponse

Name Type Description
message required
"Item deleted successfully" —
post /v1/devices/{device_id}/items/lookup

Read an inventory item

Read this before retrieval to obtain a current actionable location. An empty location list may mean the item is not stored or is bin-managed; inspect storage_mode. Returns 404 when the item is absent.

Requires HTTPBearer authentication.

Parameters

Name Type Description
device_id required
path
string

Device identifier supplied during onboarding.

Request body required application/json

Name Type Description
barcode required
string

Inventory barcode identifier; customer formats are accepted.

min length 1 · max length 255

Responses

200 Successful Response

application/json · ItemResponse

Name Type Description
barcode required
string —
created_at
string | null —
dimensions required
ItemDimensionsResponse —
height required
number —
length required
number —
width required
number —
full_net_weight
number | null —
id required
integer —
locations
array<ItemLocationResponse>

Directly actionable storage locations; always empty for bin-managed items.

cell_idx required
integer —
shelf_idx required
integer —
side required
string —

one of "front_module", "back_module"

metadata
object —
name required
string —
net_weight
number | null —
storage_mode required
string

How the item is stored. Bin-managed items cannot be retrieved directly.

one of "direct", "bin"

tare_weight
number | null —
updated_at
string | null —
weight
number | null —
post /v1/devices/{device_id}/items/update

Update an inventory record

Updates the supplied non-null fields; omitted and null fields are not forwarded and leave their values unchanged. Metadata, when supplied, replaces the metadata object. Does not move the item. Changing a bin-managed item's dimensions is blocked until it is retrieved.

Requires HTTPBearer authentication.

Parameters

Name Type Description
device_id required
path
string

Device identifier supplied during onboarding.

Request body required application/json

Name Type Description
barcode required
string

Inventory barcode identifier; customer formats are accepted.

min length 1 · max length 255

dimensions
Dimensions | null —
height required
number

Height in millimeters

> 0

length required
number

Length in millimeters

> 0

width required
number

Width in millimeters

> 0

full_net_weight
number | null

Full contents mass in grams

metadata
object | null —
name
string | null —
net_weight
number | null

Current contents mass in grams

tare_weight
number | null

Empty container mass in grams

weight
number | null

Gross item mass in grams; null is not forwarded on writes.

Responses

200 Successful Response

application/json · ItemResponse

Name Type Description
barcode required
string —
created_at
string | null —
dimensions required
ItemDimensionsResponse —
height required
number —
length required
number —
width required
number —
full_net_weight
number | null —
id required
integer —
locations
array<ItemLocationResponse>

Directly actionable storage locations; always empty for bin-managed items.

cell_idx required
integer —
shelf_idx required
integer —
side required
string —

one of "front_module", "back_module"

metadata
object —
name required
string —
net_weight
number | null —
storage_mode required
string

How the item is stored. Bin-managed items cannot be retrieved directly.

one of "direct", "bin"

tare_weight
number | null —
updated_at
string | null —
weight
number | null —
post /v1/devices/{device_id}/print

Print an item barcode

Prints a barcode label through the device, which renders the supplied value as a Code 128 label; any non-empty barcode is accepted. This request does not create an inventory record and has no command idempotency key; retrying can print another label. A mock device accepts the request without producing a physical label.

Requires HTTPBearer authentication.

Parameters

Name Type Description
device_id required
path
string

Device identifier supplied during onboarding.

Request body required application/json

Name Type Description
barcode required
string

Inventory barcode identifier; customer formats are accepted.

min length 1 · max length 255

Responses

200 Successful Response

application/json · PrintLabelResponse

Name Type Description
barcode required
string —
message required
"success" —
printed required
boolean —

commands

Asynchronous store/retrieve admission, durable results, and current activity.

post /v1/devices/{device_id}/commands

Queue a store or retrieve command

Acceptance is not completion. Save command_id, then poll the command endpoint or consume a registered webhook for its terminal result. Only store_item and retrieve_item are exposed.

Supply a stable request_id for each logical operation. Retry an uncertain submission with the same ID and payload: the device returns the original command, including its current state. Reusing an ID with different content returns 409; use a new ID for a new attempt after a terminal failure. Device records are retained for seven days.

For storage, create the inventory record first or supply the new item's name and dimensions. For retrieval, use a current direct location from the item endpoint. Bin-managed items require an on-device tray workflow: a direct store or retrieve of a tray member returns 409. 423 comes from device firmware that still locks the device while a workflow owns it; 429 means rate or queue capacity was exceeded. Only retry after addressing the reported condition.

Requires HTTPBearer authentication.

Parameters

Name Type Description
device_id required
path
string

Device identifier supplied during onboarding.

Request body required application/json

Name Type Description
command required
"store_item" —
item required
StoreItemPayload —
barcode required
string

Inventory barcode identifier; customer formats are accepted. Print a label separately through the device print endpoint.

min length 1 · max length 255

dimensions
Dimensions | null —
height required
number

Height in millimeters

> 0

length required
number

Length in millimeters

> 0

width required
number

Width in millimeters

> 0

full_net_weight
number | null

Full contents mass in grams

metadata
object | null —
name
string | null —
net_weight
number | null

Current contents mass in grams

tare_weight
number | null

Empty container mass in grams

weight
number | null

Gross item mass in grams; null is not forwarded on writes.

request_id required
string

Stable ID for one logical command. Reuse with identical content for retry; a different payload conflicts.

min length 1 · max length 255

barcode
string | null —
command required
"retrieve_item" —
location required
Location —
cell_idx required
integer

Zero-based cell index

min 0

shelf_idx required
integer

Zero-based shelf index

min 0

side required
string —

one of "front_module", "back_module"

request_id required
string

Stable ID for one logical command. Reuse with identical content for retry; a different payload conflicts.

min length 1 · max length 255

Responses

200 Successful Response

application/json · CommandAcceptedResponse

Name Type Description
command_id required
string —
message required
"success" —
status required
string —

one of "queued", "running", "succeeded", "failed"

get /v1/devices/{device_id}/commands/{command_id}

Read a command and its result

Poll the ID returned by submission. queued and running are nonterminal; succeeded and failed are terminal. result can be null before completion. This durable record is the recovery path if a webhook is missed. An unknown or expired command returns 404. A backend result that does not match the cloud contract returns 502.

Requires HTTPBearer authentication.

Parameters

Name Type Description
device_id required
path
string

Device identifier supplied during onboarding.

command_id required
path
string

Command identifier returned when the command was accepted.

Responses

200 Successful Response

application/json · CommandStatusResponse

Name Type Description
command required
string —

one of "store_item", "retrieve_item"

command_id required
string —
completed_at required
string(date-time) | null —
created_at required
string(date-time) —
request_id required
string | null —
result required
StoreCommandResult | RetrieveCommandResult | FailedCommandResult | null

Terminal outcome, or null before one is available

barcode required
string —
command required
"store_item" —
command_id required
string —
location required
Location —
cell_idx required
integer

Zero-based cell index

min 0

shelf_idx required
integer

Zero-based shelf index

min 0

side required
string —

one of "front_module", "back_module"

message required
"success" —
weight
number | null

Measured item weight in grams; 0 or null when the scale measured nothing, for example a broken scale or a store without a physical item

barcode required
string —
command required
"retrieve_item" —
command_id required
string —
location required
Location —
cell_idx required
integer

Zero-based cell index

min 0

shelf_idx required
integer

Zero-based shelf index

min 0

side required
string —

one of "front_module", "back_module"

message required
"success" —
weight
number | null

Measured item weight in grams; 0 or null when the scale measured nothing, for example a broken scale or a store without a physical item

code required
string —
command
string | null —
command_id
string | null —
error required
string —
message required
"failed" —
started_at required
string(date-time) | null —
status required
string —

one of "queued", "running", "succeeded", "failed"

get /v1/devices/{device_id}/status

Read current device activity

Returns the device's current activity, not a command receipt or terminal result. queue_length counts waiting commands. Use command polling to determine a particular operation's outcome. Returns 503 when no current live status is available.

Requires HTTPBearer authentication.

Parameters

Name Type Description
device_id required
path
string

Device identifier supplied during onboarding.

Responses

200 Successful Response

application/json · ReducedStatus

Name Type Description
current_command required
StoreCommand | RetrieveCommand | null —
command required
"store_item" —
item required
StoreItemPayload —
barcode required
string

Inventory barcode identifier; customer formats are accepted. Print a label separately through the device print endpoint.

min length 1 · max length 255

dimensions
Dimensions | null —
height required
number

Height in millimeters

> 0

length required
number

Length in millimeters

> 0

width required
number

Width in millimeters

> 0

full_net_weight
number | null

Full contents mass in grams

metadata
object | null —
name
string | null —
net_weight
number | null

Current contents mass in grams

tare_weight
number | null

Empty container mass in grams

weight
number | null

Gross item mass in grams; null is not forwarded on writes.

request_id required
string

Stable ID for one logical command. Reuse with identical content for retry; a different payload conflicts.

min length 1 · max length 255

barcode
string | null —
command required
"retrieve_item" —
location required
Location —
cell_idx required
integer

Zero-based cell index

min 0

shelf_idx required
integer

Zero-based shelf index

min 0

side required
string —

one of "front_module", "back_module"

request_id required
string

Stable ID for one logical command. Reuse with identical content for retry; a different payload conflicts.

min length 1 · max length 255

queue_length required
integer

Waiting commands, excluding the currently executing command

min 0

webhooks

Signed terminal command results delivered to your HTTPS receiver. Use polling to recover missed outcomes.

get /v1/webhooks

List accessible webhook registrations

Lists registrations belonging to your partner whose entire device set is accessible to the current API key. Signing secrets are never included. Use the registration ID to delete a receiver.

Requires HTTPBearer authentication.

Responses

200 Successful Response

application/json · array<WebhookResponse>

Name Type Description
created_at required
string(date-time) —
device_ids required
array<string> —

pattern ^[0-9a-f]{8}$

events required
array<string> —

one of "command.succeeded", "command.failed"

id required
string —
url required
string —
post /v1/webhooks

Register a command-result webhook

Registers an HTTPS receiver for the selected authorized devices and events. Save the returned secret immediately; it is only returned at creation. The URL must use a hostname resolving exclusively to public addresses, without credentials or fragments. IP-literal URLs and redirects are not supported.

The callback below describes outbound requests to your receiver. Verify its signature over the original body bytes, deduplicate by event_id, and acknowledge with any 2xx after accepting the event. Delivery is retried up to 12 total attempts: the first retry is immediate, then exponential delays from one second, capped at 300 seconds. Delivery is ordered per registration/device; no global ordering is promised.

Retries preserve the event body and timestamp. Avoid a narrow timestamp window that rejects legitimate retries. Event capture depends on a live device stream and is not replayable through this API; use command polling to recover missed outcomes. Registrations apply to future captured events.

Requires HTTPBearer authentication.

Request body required application/json

Name Type Description
device_ids required
array<string> —

pattern ^[0-9a-f]{8}$ · min items 1

events
array<string> —

one of "command.succeeded", "command.failed"

url required
string

Public HTTPS hostname URL without credentials or fragments. Redirects and IP literals are not supported.

min length 1 · max length 2048

Responses

200 Successful Response

application/json · WebhookCreatedResponse

Name Type Description
created_at required
string(date-time) —
device_ids required
array<string> —

pattern ^[0-9a-f]{8}$

events required
array<string> —

one of "command.succeeded", "command.failed"

id required
string —
secret required
string

Webhook HMAC signing key, returned only once at registration creation

url required
string —
delete /v1/webhooks/{webhook_id}

Delete a webhook registration

Removes the accessible registration and its pending deliveries. An in-flight HTTP delivery may already have reached the receiver. Returns an empty 204 response; an unknown or inaccessible registration returns 404.

Requires HTTPBearer authentication.

Parameters

Name Type Description
webhook_id required
path
string

Webhook registration identifier returned when the registration was created.

Responses

204 Successful Response

service

Public relay process liveness.

get /healthz

Check relay availability

Public liveness check for the relay process. A successful response does not establish that any device is online; use the device health endpoint for that.

Responses

200 Successful Response

application/json · HealthResponse

Name Type Description
status
"ok" —

default "ok"

Errors

These responses are shared by most operations, so they are listed here once instead of on each operation.

Status Meaning Body Returned by
400 Invalid request RelayErrorBody 15 of 15
401 Authentication failed RelayErrorBody 15 of 15
403 Operation forbidden RelayErrorBody 15 of 15
404 Resource not found RelayErrorBody 15 of 15
409 Request conflicts with current device state RelayErrorBody 15 of 15
413 Request body too large RelayErrorBody 15 of 15
422 Request validation failed RelayErrorBody 15 of 15
423 Device is temporarily locked by an on-device workflow (older device firmware) RelayErrorBody 15 of 15
429 Rate or queue limit exceeded RelayErrorBody 15 of 15
502 Invalid response from device RelayErrorBody 15 of 15
503 Device or backend unavailable RelayErrorBody 15 of 15

RelayErrorBody

Name Type Description
code required
string —
correlation_id required
string —
message required
string —