Measura API documentation · v1
Consume components, produce kits, and reverse production using saved recipe snapshots.
Requires a public API key with Public API access and an active Kit Builder add-on with an available tier. Each request operates at one active Shopify location and accepts 1–50 unique kits, changing at most 100 distinct variants after component/output deltas are merged. The server calculates inventory deltas from saved recipes and their measurement configuration.
Inventory validation:
POST /api/v1/kit-assemblies
Headers:
Authorization: Bearer <api-key>
Content-Type: application/json
Idempotency-Key: <unique-operation-key>{
"direction": "assemble",
"locationId": "123456",
"kits": [
{
"kitId": "507f1f77bcf86cd799439011",
"quantity": 2,
"expectedRevision": "2026-10-17T08:00:00.000Z"
}
]
}{
"success": true,
"data": {
"direction": "assemble",
"locationId": "123456",
"assemblyLogId": "507f1f77bcf86cd799439012",
"kits": [
{
"kitId": "507f1f77bcf86cd799439011",
"quantity": 2,
"revision": "2026-10-17T08:00:00.000Z"
}
],
"inventoryDeltas": [
{
"variantId": "201",
"productId": "200",
"stockUnits": -1,
"unit": "kg",
"measurementPerStockUnit": 1
},
{
"variantId": "101",
"productId": "100",
"stockUnits": 2,
"measurementPerStockUnit": 1
}
],
"operationId": "7f7831f2-2675-4f5c-ae59-4c2d04095a60",
"operationStatus": "completed"
},
"error": null
}Note
Assembly consumes the calculated component quantities and adds one stock unit of the linked kit output variant per kit. A successful request completes synchronously and returns HTTP 200. No separate preview or queued-job endpoint is provided.
Scroll horizontally to see all columns.
| Field | Type | Description |
|---|---|---|
direction | string | Required. assemble or disassemble. |
locationId | string | Required. Positive Shopify legacy numeric location ID string, not a GraphQL GID. |
kits | array | Required. 1–50 objects with unique kit IDs. |
kits[].kitId | string | Required. Kit ID, 24 hexadecimal characters. |
kits[].quantity | integer | Required. Whole-kit count from 1 to 1,000,000. Numeric strings and fractional quantities are rejected. |
kits[].expectedRevision | string | Optional. Exact current recipe revision for assembly; exact original snapshot revision for disassembly. Mismatch returns revision_conflict (409). |
assemblyId | string | Required only for disassemble. UUID operationId of the completed original public assembly, not assemblyLogId. |
allowInsufficientInventory | boolean | Optional, defaults to false. true explicitly permits tracked inventory to become negative; other validation and concurrency checks still apply. |
Unknown request and kit-item fields are rejected. Do not send client-calculated inventory deltas. Shared component requirements are merged across the whole batch, and all resulting deltas must fit supported numeric and Shopify inventory limits.
POST /api/v1/kit-assemblies
Headers:
Authorization: Bearer <api-key>
Content-Type: application/json
Idempotency-Key: <unique-operation-key>{
"direction": "disassemble",
"locationId": "123456",
"assemblyId": "7f7831f2-2675-4f5c-ae59-4c2d04095a60",
"kits": [
{
"kitId": "507f1f77bcf86cd799439011",
"quantity": 1,
"expectedRevision": "2026-10-17T08:00:00.000Z"
}
]
}Note
Use a new idempotency key for disassembly. The original assembly must be completed, belong to this shop and use the same location. Disassembly removes assembled output and returns components using the original saved recipe and stock-unit conversions, even after the recipe is edited or deleted. Cumulative completed disassemblies cannot exceed each kit’s original quantity. Its response also includes originalAssemblyId.
Scroll horizontally to see all columns.
| Field | Type | Description |
|---|---|---|
data.operationId / operationStatus | string | Permanent public operation UUID and completed status. Use this operationId for status retrieval and future disassembly. |
data.direction / locationId | string | Executed direction and location. |
data.assemblyLogId | string | Identifier of the merchant’s Kit Builder production-history entry; distinct from operationId. |
data.originalAssemblyId | string | Present for disassembly; references the original assembly operation. |
data.kits | array | Executed kitId, positive quantity and snapshot revision for every requested kit. |
data.inventoryDeltas | array | Merged deltas for all component and output variants. Zero net deltas are omitted. |
inventoryDeltas[].variantId / productId | string | Shopify legacy numeric IDs. |
inventoryDeltas[].stockUnits | number | Signed change in Shopify stock units. Negative consumes stock; positive adds stock. |
inventoryDeltas[].measurementPerStockUnit | number | Measured value represented by one stock unit; 1 for ordinary quantity/output deltas. |
inventoryDeltas[].unit | string | Present for measured components, in the configured base unit. Multiply stockUnits by measurementPerStockUnit to obtain the signed measured change. |
GET /api/v1/kit-assemblies
Headers:
Authorization: Bearer <api-key>Scroll horizontally to see all columns.
| Parameter | Type | Description |
|---|---|---|
limit | integer | Optional. 1–100 operations per page; default 50. |
cursor | string | Optional. Opaque meta.nextCursor from the preceding response. |
Scroll horizontally to see all columns.
| Field | Type | Description |
|---|---|---|
data | array | Public kit_assembly operation records, including rejected and uncertain operations as well as completed assemblies/disassemblies. |
meta.hasMore / nextCursor | boolean / string | null | Forward pagination metadata; ordered by creation time descending, with operation ID as a tie-breaker. |
Note
History is scoped to the authenticated shop and contains public API assembly operation receipts. Reads use Cache-Control: no-store.
GET /api/v1/kit-assemblies/{id}
Headers:
Authorization: Bearer <api-key>Scroll horizontally to see all columns.
| Parameter | Type | Description |
|---|---|---|
id | string | Required. Public assembly operation UUID, returned as operationId by POST. |
{
"success": true,
"data": {
"id": "7f7831f2-2675-4f5c-ae59-4c2d04095a60",
"kind": "kit_assembly",
"status": "completed",
"phase": "finished",
"createdAt": "2026-10-17T08:30:00.000Z",
"updatedAt": "2026-10-17T08:30:01.000Z",
"result": {
"direction": "assemble",
"locationId": "123456",
"assemblyLogId": "507f1f77bcf86cd799439012",
"kits": [
{
"kitId": "507f1f77bcf86cd799439011",
"quantity": 2,
"revision": "2026-10-17T08:00:00.000Z"
}
],
"inventoryDeltas": [
{
"variantId": "201",
"productId": "200",
"stockUnits": -1,
"unit": "kg",
"measurementPerStockUnit": 1
},
{
"variantId": "101",
"productId": "100",
"stockUnits": 2,
"measurementPerStockUnit": 1
}
]
}
},
"error": null
}Scroll horizontally to see all columns.
| Field | Type | Description |
|---|---|---|
data.id / kind | string | Operation UUID and kit_assembly kind. |
data.resourceId | string | Present for disassembly: the original assembly operation ID. |
data.status | string | processing, completed, rejected or requires_review. |
data.phase | string | validating, applying or finished. |
data.createdAt / updatedAt | string | ISO timestamps for the receipt. |
data.snapshot | object | Present once preparation has been recorded: original recipes, calculated inventory deltas, direction/location and inventory plan. Omitted from the compact example above. |
data.result | object | Completed domain result. operationId and operationStatus belong to the POST response wrapper; the receipt uses id and status. |
data.error | object | Recorded code, message and optional details for rejected/requires_review outcomes. Optional fields are omitted when unavailable. |
Note
HTTP 200 means the receipt was retrieved, so inspect data.status to determine whether the production operation completed. Invalid, missing, wrong-kind and other-shop operation IDs return 404.
Every write requires an Idempotency-Key of 1–255 characters. Operation receipts are retained permanently for this shop. Retry the same operation with the same key; terminal replays include Idempotency-Replayed: true. A key used for a different request returns idempotency_key_reused.
Uncertain production outcome:
{
"success": false,
"data": null,
"error": {
"code": "operation_requires_review",
"message": "The operation may have applied changes. Retrieve its status and reconcile it before starting another write.",
"details": {
"operationId": "7f7831f2-2675-4f5c-ae59-4c2d04095a60",
"operationStatus": "requires_review"
}
}
}Scroll horizontally to see all columns.
| Status | Description |
|---|---|
| 400 | Malformed JSON, invalid/missing Idempotency-Key or invalid operation cursor. |
| 401 / 403 | Invalid credentials, unavailable Public API access, or inactive/unavailable Kit Builder add-on tier. |
| 404 | Kit or public assembly operation not found. |
| 405 | Unsupported method. |
| 409 | insufficient_kit_inventory (details.shortages lists available/required/shortage by variant), disassembly_quantity_exceeded, revision_conflict, inventory_conflict, idempotency_key_reused, operation_in_progress, resource_in_progress or operation_requires_review. |
| 422 | Invalid fields, IDs or quantities; batch_too_large; invalid original assembly; unavailable snapshot; invalid/ineligible recipe, location, stock or measurements. Invalid list limit is also 422. |
| 500 | Unexpected preparation, storage or upstream failure. Preserve the key while checking the outcome. |