Stock & transfers

Read unified stock levels, the movement ledger, and low-stock state; apply batched adjustments; manage transfers and restock demand through the Store API.

The inventory plane covers what no single catalog resource owns. Reads use read_inventory; writes use write_inventory.

A SKU is a store-wide address: simple products, variants, and inventory groups share one SKU registry, so POST /inventory/adjustments resolves any of the three from the SKU alone. Adjustments are batched with per-row results — one bad row never rolls back the others — and each applied row writes the movement ledger with your app as the actor, re-evaluates low-stock, and emits inventory_levels/update. Prefer adjust (signed delta, safe under concurrency) over set unless you are reconciling a physical count; reasons come from the same six-value enum merchants use.

Two fields are scope-gated for privacy. Movement reference_type/reference_id (the order behind a sale) appear only when your token also holds read_orders. Restock request contact details appear only with read_customers — otherwise they arrive redacted and can_view_contact is false.

Transfers move stock between locations: create (pending), ship (in_transit), then complete — completion is the stock-mutating step, writing transfer_out/transfer_in ledger rows and stock-level webhooks for both locations atomically. Only pending transfers can be deleted. Products, variants, and inventory groups referenced by pending or in-transit transfers cannot be deleted or switched away from their inventory source; the 409 response names the blocking TRF numbers. Completed and cancelled transfers remain immutable history after a catalog resource is deleted: each line keeps its title and SKU snapshot and returns resource_deleted: true.

Endpoints#

Inventory limits

GET read_inventory

Get stock limits and supported options.

Returns the paging caps, sort columns, item types, the user reason enum accepted by adjustments, the adjustment batch cap (adjustments.max_batch_size, the per-request row cap shared by every stock write), the Idempotency-Key length limit, and the movement retention window enforced by the services.

Headers

Name Type Description
Authorization required string

Bearer Store API token.

List stock levels

GET read_inventory

List per-location stock for every tracked item.

Returns one row per (item, location) across directly tracked simple products and variants plus inventory groups. quantity is physical on hand. reserved is all held stock; checkout_held is its short unpaid-checkout subset, order_committed is its placed-order subset, and other_held covers active transfers and other operational holds. available = quantity - reserved. Every visible active location is projected for every inventory group; a missing stored level reads as zero and the first set, adjustment, or threshold write creates it atomically. App tokens see merchant-managed locations and their own app-managed locations, never another app's locations. Filter by location, item type, SKU search, or low-stock only. Query validation is strict: invalid sort or filter values return coded 400s, never silent defaults.

Pages follow the sort, then item type and IDs. While has_next is true, pass next_cursor as cursor to read the next page; page numbers reach only the first 10,000 rows. total is exact up to 10,000 rows; above that it is an estimate and total_estimated is true.

Query parameters

Name Type Description
location_id string

Only stock at this location (UUID).

item_type string

simple, variant, or group.

Example: variant
search string

Matches SKU exactly or item title as a prefix search.

low_stock_only boolean

Only rows at or below their low-stock threshold.

Example: true
cursor string

Opaque next_cursor from the previous page; replaces page. Send the same filters and sorting with it. Page numbers reach the first 10,000 rows; read further with the cursor.

page integer

Page number, starting at 1.

Example: 1
limit integer

Rows per page, up to the limits endpoint's list_max_limit.

Example: 50
sort_by string

One of the limits endpoint's sort_columns. Invalid values return a coded 400.

sort_direction string

asc or desc.

Example: desc

Headers

Name Type Description
Authorization required string

Bearer Store API token.

Errors

  • 400 VALIDATION_LIST_INVALID_PAGE

    Page must be a positive integer.

  • 400 VALIDATION_LIST_INVALID_LIMIT

    Limit must be a positive integer no greater than list_max_limit from transfer limits.

  • 400 STORE_API_INVALID_REQUEST_BODY

    A boolean or UUID filter is malformed.

  • 400 STOCK_LEVEL_PER_PAGE_RANGE

    Limit is outside 1..list_max_limit.

  • 400 STOCK_LEVEL_INVALID_SORT_BY

    Sort column is not in sort_columns.

  • 400 STOCK_LEVEL_INVALID_SORT_DIR

    Sort direction must be asc or desc.

  • 400 STOCK_LEVEL_SEARCH_TOO_LONG

    Search exceeds the search length limit.

  • 400 STOCK_LEVEL_ITEM_TYPE_FILTER_INVALID

    Item_type is not simple, variant, or group.

  • 400 INVALID_INPUT

    cursor is not a stock-levels cursor for these filters and sorting, or page reaches past the first 10,000 rows.

List movements

GET read_inventory

List the unified stock movement ledger.

Returns the append-only ledger every physical stock change writes — admin edits, imports, scanner sessions, transfers, order fulfillment, and your own adjustments — newest first. An app-token write records App: <app name> in user_name; opaque app ids are never shown as merchant-facing actor names. A valid app token always resolves its authoritative app name, and a request with incomplete app identity is rejected. A merchant-created Store API token records its creator's merchant email. System rows without a human or app actor return an empty actor. reference_type and reference_id (e.g. the order behind a movement) are included only when the token also holds read_orders; without it the movement row is returned with those fields omitted. Rows are retained for the window reported by the limits endpoint.

Query parameters

Name Type Description
location_id string

Only movements at this location (UUID).

item_type string

simple, variant, or group.

reason string

One movement reason (see the limits endpoint's all_reasons).

Example: received
search string

Matches SKU or item title.

from_date string

Inclusive start date, YYYY-MM-DD in the store timezone.

to_date string

Inclusive end date, YYYY-MM-DD in the store timezone.

page integer

Page number, starting at 1.

Example: 1
limit integer

Rows per page, up to the limits endpoint's list_max_limit.

Example: 50
sort_by string

One of the limits endpoint's sort_columns. Invalid values return a coded 400.

sort_direction string

asc or desc.

Example: desc

Headers

Name Type Description
Authorization required string

Bearer Store API token.

Errors

  • 400 VALIDATION_LIST_INVALID_PAGE

    Page must be a positive integer.

  • 400 VALIDATION_LIST_INVALID_LIMIT

    Limit must be a positive integer no greater than list_max_limit from transfer limits.

  • 400 INVENTORY_MOVEMENT_LIST_INVALID_SORT_BY

    Sort column is not in sort_columns.

  • 400 INVENTORY_MOVEMENT_LIST_INVALID_SORT_DIRECTION

    Sort direction must be asc or desc.

  • 400 INVENTORY_MOVEMENT_LIST_INVALID_TYPE

    Item_type is not simple, variant, or group.

  • 400 INVENTORY_MOVEMENT_SEARCH_TOO_LONG

    Search exceeds the search length limit.

List low-stock items

GET read_inventory

List items at or below their low-stock threshold.

Returns items whose available stock (quantity - reserved) is at or below the configured threshold, with the positive deficit (threshold - available). Covers per-location and overall thresholds for directly tracked simple products and variants plus inventory groups; filter by location or overall scope, item type, or location. App tokens see merchant-managed locations and locations owned by their own active installation, never another app's locations.

Query parameters

Name Type Description
location_id string

Only alerts at this location. Ignored when scope=overall.

type string

simple, variant, or group.

scope string

location or overall. Overall thresholds are supported for tracked simple products, variants, and inventory groups.

search string

Matches SKU or item title.

page integer

Page number, starting at 1.

Example: 1
limit integer

Rows per page, up to the limits endpoint's list_max_limit.

Example: 50
sort_by string

One of the limits endpoint's sort_columns. Invalid values return a coded 400.

sort_direction string

asc or desc.

Example: desc

Headers

Name Type Description
Authorization required string

Bearer Store API token.

Errors

  • 400 VALIDATION_LIST_INVALID_PAGE

    Page must be a positive integer.

  • 400 VALIDATION_LIST_INVALID_LIMIT

    Limit must be a positive integer no greater than list_max_limit from transfer limits.

  • 400 LOW_STOCK_LIST_INVALID_SORT_BY

    Sort column is not in sort_columns.

  • 400 LOW_STOCK_LIST_INVALID_SORT_DIRECTION

    Sort direction must be asc or desc.

  • 400 LOW_STOCK_LIST_INVALID_TYPE

    Type is not simple, variant, or group.

  • 400 LOW_STOCK_LIST_INVALID_SCOPE

    Scope is not location or overall.

  • 400 LOW_STOCK_SEARCH_TOO_LONG

    Search exceeds the search length limit.

List current commitments

GET read_inventory

List open order-inventory commitments across the store.

Returns open, successfully applied reservation slices for simple products, variants and inventory groups, newest first. Narrow the listing to one item with source_type and source_id, and to one location with location_id. Each row is stock held for one order line at one location: state provisional while the shopper is paying (it counts in checkout_held until expires_at) or committed once the order is placed and paid or confirmed (it counts in order_committed). state is the authoritative applied state, not a pending desired state. Released and fulfilled stock is not listed; read commitment activity for that history. While an order's stock change is still being applied its rows are left out, so the rows add up to a location's checkout_held and order_committed once it applies. source_type (product, variant or group), source_id and sku name the item. Pages are keyed: pass the response's next_cursor as cursor to read the next page with the same filters; an empty next_cursor means there are no more rows. Order ids, item ids, and order numbers are included only when the token also has read_orders; internal transition status, errors, and operation ids are never exposed through the Store API. App tokens see merchant-managed locations and their own app-managed locations, never another app's locations.

Query parameters

Name Type Description
cursor string

Opaque next_cursor of the previous page. Omit it for the first page.

Example: eyJ0IjoiMjAyNi0wNy0wNlQxMDoyNTowMFoifQ
limit integer

Page size, 1 to 100. Defaults to 50.

Example: 50
source_type string

Item type: product (a simple product), variant, or group (an inventory group). Required with source_id.

Example: variant
source_id string

Item id: the numeric product or variant id, or the inventory group UUID.

Example: 4821
location_id uuid

Filter to one visible location.

Example: af720cef-7f1b-40f4-a5f8-8a55ea5b0d84

Headers

Name Type Description
Authorization required string

Bearer Store API token.

Errors

  • 400 VALIDATION_LIST_INVALID_LIMIT

    Limit must be between 1 and 100.

  • 400 INVALID_INPUT

    A filter is invalid: the error names cursor, source_type, source_id, location_id, event_type, from_date or to_date.

List commitment activity

GET read_inventory

List applied order-inventory commitment activity across the store.

Returns the append-only lifecycle ledger for successfully applied provisional holds, commitments, releases, reacquisitions, fulfillment consumption, and cancelled fulfillments, newest first. Narrow it to one item with source_type and source_id, one location with location_id, an event type, or a date range in the store timezone. event_type is provisional_held (a checkout hold started), committed (units committed to a placed order), released (held units became available again), reacquired (released units were held again), fulfilled (units left stock with a fulfillment) or fulfillment_reversed (a cancelled fulfillment put its units back). reason says why: order_created (an order was placed or an edit added units), payment_captured (the payment completed; with reacquired, a late payment held the same units again after its hold had been released), payment_retry (the shopper retried a payment), payment_failed or provider_init_failed (the payment failed or could not be started), checkout_hold_expired (the checkout hold duration ran out), order_released (the order was cancelled or removed), order_edited (an order edit or refund removed units), order_edit_abandoned (an unsaved order edit was discarded), order_create_failed (an order that could not be completed returned units sold on commit), order_fulfilled (units shipped), sold_without_shipping (items that don't need shipping left stock when the order was committed) or fulfillment_cancelled (a fulfillment was cancelled). reserved_after, checkout_held_after and order_committed_after are the location's numbers right after the event. source_type, source_id and sku name the item. Pages are keyed: pass the response's next_cursor as cursor to read the next page with the same filters; an empty next_cursor means there are no more rows. This is separate from physical stock movement history. Order ids, item ids, and order numbers are included only when the token also has read_orders; internal pending-operation and error details are never exposed through the Store API. App tokens see merchant-managed locations and their own app-managed locations, never another app's locations.

Query parameters

Name Type Description
cursor string

Opaque next_cursor of the previous page. Omit it for the first page.

Example: eyJ0IjoiMjAyNi0wNy0wNlQxMDoyNTowMFoifQ
limit integer

Page size, 1 to 100. Defaults to 50.

Example: 50
source_type string

Item type: product (a simple product), variant, or group (an inventory group). Required with source_id.

Example: variant
source_id string

Item id: the numeric product or variant id, or the inventory group UUID.

Example: 4821
location_id uuid

Filter to one visible location.

Example: af720cef-7f1b-40f4-a5f8-8a55ea5b0d84
event_type string

Filter by provisional_held, committed, released, reacquired, fulfilled, or fulfillment_reversed.

Example: committed
from_date string

Inclusive start date, YYYY-MM-DD in the store timezone.

Example: 2026-07-01
to_date string

Inclusive end date, YYYY-MM-DD in the store timezone.

Example: 2026-07-31

Headers

Name Type Description
Authorization required string

Bearer Store API token.

Errors

  • 400 VALIDATION_LIST_INVALID_LIMIT

    Limit must be between 1 and 100.

  • 400 INVALID_INPUT

    A filter is invalid: the error names cursor, source_type, source_id, location_id, event_type, from_date or to_date.

Apply adjustments

POST write_inventory

Apply a batch of stock adjustments by SKU.

Applies up to max_batch_size rows in one database transaction: every row applies or none do. Each row addresses an item by SKU — simple product, variant, or inventory group resolve identically — at the batch location_id or its own location_id, and either adjusts by a signed delta (adjust) or writes an absolute quantity (set). A SKU may appear only once per location in a batch. Stock cannot change at an archived location: such a row fails the batch (inactive locations stay writable so stock can be corrected or zeroed before archiving). A set row may carry expected_quantity: the row is then a compare-and-set against the current on-hand quantity, and when they differ the whole batch is refused with 409 STOCK_LEVEL_EXPECTED_QUANTITY_MISMATCH and nothing changes. When any row fails, the response is that row's own error code with details.row (1-based), details.sku and details.location_id, and no row is applied. Send a stable Idempotency-Key when retrying: keys are scoped to your app (or the merchant user), UUIDs are canonicalized before comparison, an identical replay within 7 days returns the original result without a second movement, audit entry or webhook, and reusing a key for different input returns 409 STOCK_WRITE_IDEMPOTENCY_CONFLICT. App tokens may target merchant-managed locations and locations owned by their own active installation; they cannot write another app's location. Every applied row writes the movement ledger with your app as the actor, re-evaluates low-stock, and emits inventory_levels/update. Deltas are safe under concurrency; use set with expected_quantity when reconciling a physical count.

Headers

Name Type Description
Authorization required string

Bearer Store API token.

Idempotency-Key string

Optional on the first attempt and required for a safe retry. Scoped to the calling app or merchant actor, at most 200 characters. An identical replay within 7 days returns the original result without a second stock write, audit entry or webhook; reuse with different input returns 409 STOCK_WRITE_IDEMPOTENCY_CONFLICT.

Example: scanner-count-2026-09-27-aisle-4

Body parameters

Name Type Description
location_id string

Default location for rows that do not name their own (UUID). Required unless every row has location_id.

Example: 0b54c9c1-6a2f-4f6e-9d1c-7e8a2b3c4d5e
items required array<object>

Up to the limits endpoint's max_batch_size rows. Each row: sku (string, required — resolves to a simple product, variant, or inventory group), optional location_id (UUID, overrides the batch location), exactly one of adjust (integer, signed delta) or set (integer ≥ 0, absolute), optional expected_quantity (integer ≥ 0, set rows only — the on-hand quantity you counted against), reason (string, required — one of the limits endpoint's user_reasons), and optional notes.

Example: [{"sku":"TRAIL-TEE-FOR-M","adjust":5,"reason":"received"},{"sku":"TRAIL-TEE-FOR-L","set":30,"expected_quantity":28,"reason":"recount"}]

Errors

  • 400 STOCK_LEVEL_BATCH_ITEMS_REQUIRED

    The batch has no rows.

  • 400 STOCK_LEVEL_BATCH_TOO_LARGE

    The batch exceeds the adjustment batch cap.

  • 400 STOCK_LEVEL_BATCH_DUPLICATE_ROW

    A SKU appears more than once for the same location.

  • 400 STOCK_LEVEL_ACTION_INVALID

    A row does not contain exactly one of adjust or set.

  • 400 STOCK_LEVEL_REASON_INVALID

    A row's reason is not one of the user reasons. Row failures carry details.row, details.sku and details.location_id; nothing in the batch is applied.

  • 404 STOCK_LEVEL_NO_PRODUCT_FOR_SKU

    A row's SKU does not resolve to a tracked simple product, variant, or inventory group. Nothing in the batch is applied.

  • 400 STOCK_LEVEL_SET_BELOW_RESERVED

    A set row would leave on hand below reserved stock. Nothing in the batch is applied.

  • 400 STOCK_LEVEL_ADJUST_NEGATIVE

    An adjust row would make on hand negative. Nothing in the batch is applied.

  • 400 STOCK_LEVEL_EXPECTED_QUANTITY_INVALID

    expected_quantity is negative.

  • 400 STOCK_LEVEL_EXPECTED_QUANTITY_SET_ONLY

    expected_quantity was sent on an adjust row.

  • 409 STOCK_LEVEL_EXPECTED_QUANTITY_MISMATCH

    A set row's expected_quantity differs from the current on-hand quantity (params.expected, params.current). Nothing in the batch is applied.

  • 400 STOCK_WRITE_IDEMPOTENCY_KEY_TOO_LONG

    Idempotency-Key exceeds 200 characters.

  • 409 STOCK_WRITE_IDEMPOTENCY_CONFLICT

    The idempotency key was already used for a different stock write.

  • 409 LOCATION_ARCHIVED_NO_EDIT

    A row would change stock at an archived location. Nothing in the batch is applied.

  • 400 LOCATION_NOT_FOUND

    The location does not exist in this store.

  • 403 LOCATION_APP_MANAGED_NO_EDIT

    The location belongs to another app or its owning installation is inactive.

List transfers

GET read_inventory

List stock transfers.

Returns paginated transfers with a stable transfer_number, status, endpoint ownership, locations, item counts, and total quantity. Filter by status, source location, destination location, or date range; search matches transfer number, UUID, merchant reference, or endpoint location name. Merchant callers can read all store transfers. App callers see transfers whose endpoints are merchant-managed or owned by that same app; another app's managed location and transfer remain undiscoverable. Writes are narrower: merchant tokens may mutate merchant-managed endpoints, while app tokens may mutate merchant-managed endpoints and endpoints owned by their own active installation. Pending and in-transit transfers protect their product, variant, or inventory-group references from deletion. Completed and cancelled transfers keep immutable title and SKU snapshots if a referenced catalog resource is later deleted.

Query parameters

Name Type Description
status string

pending, in_transit, completed, or cancelled.

from_location_id uuid

Only transfers from this visible location.

to_location_id uuid

Only transfers to this visible location.

search string

Matches the stable transfer number, transfer UUID, merchant reference, or source/destination location name.

from_date string

Inclusive start date, YYYY-MM-DD in the store timezone.

to_date string

Inclusive end date, YYYY-MM-DD in the store timezone.

page integer

Page number, starting at 1.

Example: 1
limit integer

Rows per page, up to the limits endpoint's list_max_limit.

Example: 50
sort_by string

One of the limits endpoint's sort_columns. Invalid values return a coded 400.

sort_direction string

asc or desc.

Example: desc

Headers

Name Type Description
Authorization required string

Bearer Store API token.

Errors

  • 400 VALIDATION_LIST_INVALID_PAGE

    Page must be a positive integer.

  • 400 VALIDATION_LIST_INVALID_LIMIT

    Limit must be a positive integer no greater than list_max_limit from transfer limits.

  • 400 INVALID_INPUT

    A source or destination location filter is not a valid UUID.

  • 400 TRANSFER_LIST_INVALID_SORT_BY

    Sort column is not in sort_columns.

  • 400 TRANSFER_LIST_INVALID_SORT_DIRECTION

    Sort direction must be asc or desc.

  • 400 TRANSFER_STATUS_FILTER_INVALID

    Status filter is not a transfer status.

  • 400 TRANSFER_SEARCH_TOO_LONG

    Search exceeds the search length limit.

Get transfer

GET read_inventory

Fetch one transfer with its items.

Returns the transfer, its status history timestamps, and every line item with quantities. Each line includes resource_deleted. It is false while the referenced product, variant, or inventory group exists, and true when a terminal transfer is displaying the immutable title/SKU snapshot of a resource deleted later. Active transfers cannot enter this state because catalog deletion is blocked until the transfer is completed or cancelled.

Path parameters

Name Type Description
transferId required string

Transfer id (UUID).

Example: d3b7c2a4-91e5-4f0a-b6c8-2f4e5a6b7c8d

Headers

Name Type Description
Authorization required string

Bearer Store API token.

Errors

  • 400 TRANSFER_INVALID_ID

    Transfer id is not a valid UUID.

  • 404 TRANSFER_NOT_FOUND

    Transfer does not exist in this store.

Create transfer

POST write_inventory

Create a stock transfer between two locations.

Creates a pending transfer. Each item contains exactly one identifier matching its item type. Simple products and variants must use direct tracked inventory; when one is backed by an inventory group, transfer the group instead so a stale direct row can never move. Quantities are validated against available stock at the source location. Pending transfers hold nothing. Marking the transfer in_transit atomically moves the source units into reserved/other_held so orders cannot sell stock that is travelling. App tokens may use merchant-managed locations and locations owned by their own active installation, but cannot discover or mutate another app's locations. Send a stable Idempotency-Key when retrying creation: UUIDs are canonicalized before comparison, an identical replay returns the existing transfer without a second audit entry or webhook, and reuse for different input returns 409.

Headers

Name Type Description
Authorization required string

Bearer Store API token.

Idempotency-Key string

Stable retry key scoped to the calling app or merchant actor, maximum 200 characters. Reuse only with the identical request.

Example: warehouse-a-to-shop-2026-08-30-01

Body parameters

Name Type Description
from_location_id required string

Source location (UUID). Must differ from the destination.

Example: 0b54c9c1-6a2f-4f6e-9d1c-7e8a2b3c4d5e
to_location_id required string

Destination location (UUID).

Example: 7c1d2e3f-4a5b-6c7d-8e9f-0a1b2c3d4e5f
reference_number string

Your reference, up to the limits endpoint's reference_number_max_length.

notes string

Free-form notes, up to notes_max_length.

items required array<object>

Up to max_items_per_transfer rows. Each row contains item_type (simple, variant, or group), exactly one matching id field (product_id, variant_id, or group_id), and quantity (integer ≥ 1, validated against available stock at the source). Simple products and variants must have inventory_source=track; transfer the linked group for group-backed items.

Example: [{"item_type":"variant","variant_id":342,"quantity":20}]

Errors

  • 400 STORE_API_INVALID_REQUEST_BODY

    Request JSON is malformed, has trailing data, or contains an unknown field.

  • 400 INVALID_INPUT

    A source or destination location id is not a valid UUID.

  • 400 TRANSFER_SAME_LOCATIONS

    Source and destination locations are the same.

  • 400 TRANSFER_ITEMS_REQUIRED

    The transfer has no items.

  • 400 TRANSFER_TOO_MANY_ITEMS

    The transfer exceeds max_items_per_transfer.

  • 400 TRANSFER_REFERENCE_NUMBER_TOO_LONG

    Reference number exceeds its published limit.

  • 400 TRANSFER_NOTES_TOO_LONG

    Notes exceed their published limit.

  • 400 TRANSFER_QUANTITY_NOT_POSITIVE

    Every line quantity must be at least one.

  • 400 TRANSFER_QUANTITY_TOO_LARGE

    A line quantity exceeds max_quantity.

  • 400 TRANSFER_INSUFFICIENT_STOCK

    A line's quantity exceeds available stock at the source location.

  • 400 TRANSFER_ITEM_TYPE_INVALID

    A line's item_type is not simple, variant, or group.

  • 400 TRANSFER_ITEM_IDENTIFIERS_INVALID

    A line contains an identifier that does not match its item_type.

  • 400 TRANSFER_PRODUCT_ID_REQUIRED

    A simple line is missing product_id.

  • 400 TRANSFER_VARIANT_ID_REQUIRED

    A variant line is missing variant_id.

  • 400 TRANSFER_GROUP_ID_REQUIRED

    A group line is missing group_id.

  • 400 TRANSFER_GROUP_ID_INVALID

    A group_id is not a valid UUID.

  • 400 TRANSFER_ITEM_SOURCE_NOT_TRACK

    A product or variant is group-backed; transfer its linked inventory group instead.

  • 400 TRANSFER_DUPLICATE_PRODUCT_ITEM

    The same simple product appears more than once.

  • 400 TRANSFER_DUPLICATE_VARIANT_ITEM

    The same variant appears more than once.

  • 400 TRANSFER_DUPLICATE_GROUP_ITEM

    The same inventory group appears more than once.

  • 400 TRANSFER_PRODUCT_NOT_FOUND

    The simple product does not exist in this store.

  • 400 TRANSFER_VARIANT_NOT_FOUND

    The variant does not exist in this store.

  • 400 TRANSFER_GROUP_NOT_FOUND

    The inventory group does not exist in this store.

  • 400 TRANSFER_PRODUCT_NO_STOCK_AT_SOURCE

    The simple product has no stock row at the source location.

  • 400 TRANSFER_VARIANT_NO_STOCK_AT_SOURCE

    The variant has no stock row at the source location.

  • 400 TRANSFER_GROUP_NO_STOCK_AT_SOURCE

    The inventory group has no stock row at the source location.

  • 400 TRANSFER_SOURCE_LOCATION_NOT_FOUND

    The source location does not exist in this store.

  • 400 TRANSFER_DEST_LOCATION_NOT_FOUND

    The destination location does not exist in this store.

  • 400 TRANSFER_SOURCE_LOCATION_INACTIVE

    The source location is inactive.

  • 400 TRANSFER_DEST_LOCATION_INACTIVE

    The destination location is inactive.

  • 400 TRANSFER_IDEMPOTENCY_KEY_TOO_LONG

    Idempotency-Key exceeds 200 characters.

  • 409 TRANSFER_IDEMPOTENCY_CONFLICT

    The idempotency key was already used for different transfer input.

  • 403 LOCATION_APP_MANAGED_NO_EDIT

    An endpoint belongs to another app or its owning installation is inactive.

Update transfer status

PUT write_inventory

Advance or cancel a transfer.

Moves the transfer through its lifecycle: pending → in_transit (ship) or cancelled; in_transit → completed (receive) or cancelled. Shipping holds the source units without changing physical on hand. Setting completed receives every unit that is still unaccounted for as received — the same as one receipt through the receive endpoint — consuming that part of the source transfer hold, decrementing source on hand, and incrementing destination on hand atomically with paired transfer_out and transfer_in movement rows. Units already recorded by earlier receipts are not moved again. Cancelling an in-transit transfer, including a partially received one, releases only the units that are still held; received, short and damaged units stay as recorded. Every availability or physical change emits inventory_levels/update.

Path parameters

Name Type Description
transferId required string

Transfer id (UUID).

Example: d3b7c2a4-91e5-4f0a-b6c8-2f4e5a6b7c8d

Headers

Name Type Description
Authorization required string

Bearer Store API token.

Body parameters

Name Type Description
status required string

Target status: in_transit or cancelled from pending; completed (receive every remaining unit) or cancelled from in transit.

Example: in_transit

Errors

  • 400 STORE_API_INVALID_REQUEST_BODY

    Request JSON is malformed, has trailing data, or contains an unknown field.

  • 400 TRANSFER_INVALID_ID

    Transfer id is not a valid UUID.

  • 400 INVALID_INPUT

    Status is not a supported transfer status.

  • 400 TRANSFER_STATUS_TRANSITION_INVALID

    The target status is not reachable from the transfer's current status.

  • 400 TRANSFER_INSUFFICIENT_STOCK

    Source availability is no longer sufficient to ship the transfer.

  • 404 TRANSFER_NOT_FOUND

    Transfer does not exist in this store.

  • 409 TRANSFER_RESERVATION_INVARIANT

    The transfer inventory could not be reconciled safely; nothing changed.

  • 403 LOCATION_APP_MANAGED_NO_EDIT

    An endpoint belongs to another app or its owning installation is inactive.

Bulk update transfer status

POST write_inventory

Advance or cancel multiple transfers atomically.

Applies one valid lifecycle transition to up to 100 transfers. The complete batch is serialized and committed in one transaction: if any id is missing, duplicated, unwritable, has an invalid transition, or cannot reconcile its reservation safely, no transfer or inventory row changes. Repeating an already-applied target status is safe.

Headers

Name Type Description
Authorization required string

Bearer Store API token.

Body parameters

Name Type Description
ids required array<uuid>

One to 100 unique transfer ids.

Example: d3b7c2a4-91e5-4f0a-b6c8-2f4e5a6b7c8d
status required string

One target status applied atomically to every selected transfer.

Example: in_transit

Errors

  • 400 STORE_API_INVALID_REQUEST_BODY

    Request JSON is malformed, has trailing data, or contains an unknown field.

  • 400 TRANSFER_INVALID_ID

    Transfer id is not a valid UUID.

  • 400 INVALID_INPUT

    Status is not a supported transfer status.

  • 400 TRANSFER_STATUS_TRANSITION_INVALID

    The target status is not reachable from the transfer's current status.

  • 400 TRANSFER_INSUFFICIENT_STOCK

    Source availability is no longer sufficient to ship the transfer.

  • 404 TRANSFER_NOT_FOUND

    Transfer does not exist in this store.

  • 409 TRANSFER_RESERVATION_INVARIANT

    The transfer inventory could not be reconciled safely; nothing changed.

  • 403 LOCATION_APP_MANAGED_NO_EDIT

    An endpoint belongs to another app or its owning installation is inactive.

  • 400 TRANSFER_BULK_IDS_REQUIRED

    Select at least one transfer.

  • 400 TRANSFER_BULK_TOO_MANY

    The request exceeds the 100-transfer cap.

  • 400 TRANSFER_BULK_DUPLICATE_ID

    A transfer id appears more than once.

Receive transfer

POST write_inventory

Record a full or partial receipt against an in-transit transfer.

Records one receipt for some or all lines of an in_transit transfer; both the source and destination must still be active locations. For each line send received_quantity, short_quantity and damaged_quantity (whole numbers, at least one unit per line); together they may not exceed the line's remaining_quantity. Received units leave the source (on hand and transfer hold) and are added to destination on hand with paired transfer_out/transfer_in movements. Short units never left the source: their transfer hold is released so they become available at the source again, with no movement row. Damaged units leave the source on hand and hold and are written off with a transfer_damaged movement; they are not added to the destination. Receipts can be repeated until every unit of every line is accounted for; the receipt that accounts for the last unit completes the transfer. Each receipt commits atomically, emits inventory_levels/update for every changed level and transfers/received, and the completing receipt also emits transfers/status_changed. Concurrent receipts serialize on the transfer. Send a stable Idempotency-Key when retrying: an identical replay returns the original transfer without recording a second receipt; reuse for different input returns 409.

Path parameters

Name Type Description
transferId required string

Transfer id (UUID).

Example: d3b7c2a4-91e5-4f0a-b6c8-2f4e5a6b7c8d

Headers

Name Type Description
Authorization required string

Bearer Store API token.

Idempotency-Key string

Optional on the first attempt and required for a safe retry. Scoped to the calling app or merchant actor, at most 200 characters. An identical replay within 7 days returns the original result without a second stock write, audit entry or webhook; reuse with different input returns 409 STOCK_WRITE_IDEMPOTENCY_CONFLICT.

Example: dock-3-receipt-2026-09-27-01

Body parameters

Name Type Description
lines required array<object>

One row per transfer line being accounted for, at most one per line. Each row: transfer_item_id (uuid, from the transfer's items[].id), received_quantity, short_quantity, damaged_quantity (integers ≥ 0, omitted means 0, at least one positive, total ≤ the line's remaining_quantity).

Example: [{"transfer_item_id":"5e6f7a8b-9c0d-4e1f-8a2b-3c4d5e6f7a8b","received_quantity":18,"short_quantity":1,"damaged_quantity":1}]
notes string

Optional receipt note, up to the transfer notes_max_length.

Example: Pallet 2 of 3; one unit crushed.

Errors

  • 400 STORE_API_INVALID_REQUEST_BODY

    Request JSON is malformed, has trailing data, or contains an unknown field.

  • 400 TRANSFER_INVALID_ID

    Transfer id is not a valid UUID.

  • 400 TRANSFER_RECEIVE_LINES_REQUIRED

    The receipt has no lines.

  • 400 TRANSFER_RECEIVE_TOO_MANY_LINES

    The receipt has more lines than the per-request cap.

  • 400 TRANSFER_RECEIVE_LINE_NOT_FOUND

    A transfer_item_id is not a line of this transfer.

  • 400 TRANSFER_RECEIVE_LINE_DUPLICATE

    A transfer line appears more than once.

  • 400 TRANSFER_RECEIVE_QUANTITY_INVALID

    A quantity is negative, or a line accounts for no units.

  • 400 TRANSFER_RECEIVE_EXCEEDS_REMAINING

    A line's received + short + damaged exceeds its remaining quantity.

  • 400 TRANSFER_NOTES_TOO_LONG

    Notes exceed their published limit.

  • 400 STOCK_WRITE_IDEMPOTENCY_KEY_TOO_LONG

    Idempotency-Key exceeds 200 characters.

  • 403 LOCATION_APP_MANAGED_NO_EDIT

    An endpoint belongs to another app or its owning installation is inactive.

  • 404 TRANSFER_NOT_FOUND

    Transfer does not exist in this store.

  • 409 TRANSFER_RECEIVE_NOT_IN_TRANSIT

    The transfer is not in transit.

  • 409 TRANSFER_RECEIVE_LOCATION_UNAVAILABLE

    The source or destination location no longer exists.

  • 400 TRANSFER_SOURCE_LOCATION_INACTIVE

    The source location is inactive or archived.

  • 400 TRANSFER_DEST_LOCATION_INACTIVE

    The destination location is inactive or archived.

  • 409 TRANSFER_RESERVATION_INVARIANT

    The transfer hold could not be reconciled safely; nothing changed.

  • 409 STOCK_WRITE_IDEMPOTENCY_CONFLICT

    The idempotency key was already used for a different receipt.

Delete transfer

DELETE write_inventory

Delete a pending transfer.

Deletes a transfer that has not shipped. Transfers that are in transit, completed, or cancelled are immutable history and cannot be deleted.

Path parameters

Name Type Description
transferId required string

Transfer id (UUID).

Example: d3b7c2a4-91e5-4f0a-b6c8-2f4e5a6b7c8d

Headers

Name Type Description
Authorization required string

Bearer Store API token.

Errors

  • 400 TRANSFER_INVALID_ID

    Transfer id is not a valid UUID.

  • 403 LOCATION_APP_MANAGED_NO_EDIT

    An endpoint belongs to another app or its owning installation is inactive.

  • 404 TRANSFER_NOT_FOUND

    Transfer does not exist in this store.

  • 409 TRANSFER_IMMUTABLE

    Only pending transfers can be deleted.

Bulk delete transfers

POST write_inventory

Delete multiple pending transfers atomically.

Deletes up to 100 pending transfers. In-transit, completed, and cancelled transfers are immutable operational history. If any selected transfer is missing, duplicated, immutable, or not writable by the caller, none are deleted. Every deleted transfer emits transfers/delete in the same transaction.

Headers

Name Type Description
Authorization required string

Bearer Store API token.

Body parameters

Name Type Description
ids required array<uuid>

One to 100 unique pending transfer ids.

Example: d3b7c2a4-91e5-4f0a-b6c8-2f4e5a6b7c8d

Errors

  • 400 TRANSFER_INVALID_ID

    Transfer id is not a valid UUID.

  • 403 LOCATION_APP_MANAGED_NO_EDIT

    An endpoint belongs to another app or its owning installation is inactive.

  • 404 TRANSFER_NOT_FOUND

    Transfer does not exist in this store.

  • 409 TRANSFER_IMMUTABLE

    Only pending transfers can be deleted.

  • 400 STORE_API_INVALID_REQUEST_BODY

    Request JSON is malformed, has trailing data, or contains an unknown field.

  • 400 TRANSFER_BULK_IDS_REQUIRED

    Select at least one transfer.

  • 400 TRANSFER_BULK_TOO_MANY

    The request exceeds the 100-transfer cap.

  • 400 TRANSFER_BULK_DUPLICATE_ID

    A transfer id appears more than once.

List restock requests

GET read_inventory

List customer back-in-stock subscriptions.

Returns customer "notify me when available" requests with product, status, and lifecycle timestamps — restock demand data for planning. Contact details (email or phone) are PII: they are returned only when the token also holds read_customers, and arrive redacted otherwise. The response's can_view_contact flag reports which mode you are in. Because contact is the searchable field, using search also requires read_customers; this prevents a redacted caller from inferring a subscription through result counts.

Query parameters

Name Type Description
status string

pending, queued, notified, failed, suppressed, converted, cancelled, or expired. Queued means admitted but not yet accepted by the provider; notified means provider-accepted.

contact_type string

email or sms. SMS uses the requested channel and is not substituted with WhatsApp.

product_id integer

Only requests for this product.

variant_id integer

Only requests for this variant.

search string

Matches the request email address or phone number. Requires read_customers in addition to read_inventory.

page integer

Page number, starting at 1.

Example: 1
limit integer

Rows per page, up to the limits endpoint's list_max_limit.

Example: 50
sort_by string

One of the limits endpoint's sort_columns. Invalid values return a coded 400.

sort_direction string

asc or desc.

Example: desc

Headers

Name Type Description
Authorization required string

Bearer Store API token.

Errors

  • 403 STORE_API_SCOPE_REQUIRED

    Searching contact details requires read_customers.

  • 400 STORE_API_INVALID_REQUEST_BODY

    A product or variant id is malformed.

  • 400 INVENTORY_RESTOCK_LIST_LIMIT_RANGE

    Limit is outside 1..list_max_limit.

  • 400 INVENTORY_RESTOCK_LIST_PAGE_INVALID

    Page must be 1 or greater.

  • 400 INVENTORY_RESTOCK_LIST_STATUS_INVALID

    Status filter is not in the allowed set.

  • 400 INVENTORY_RESTOCK_LIST_CONTACT_TYPE_INVALID

    Contact type is not email or sms.

  • 400 INVENTORY_RESTOCK_LIST_SEARCH_TOO_LONG

    Search exceeds the search length limit.

  • 400 INVENTORY_RESTOCK_LIST_INVALID_SORT_BY

    Sort column is not in sort_columns.

  • 400 INVENTORY_RESTOCK_LIST_INVALID_SORT_DIR

    Sort direction must be asc or desc.

Restock request limits

GET read_inventory

Fetch restock-request list limits and enums.

Returns the paging, search, status, contact-type, and sorting contract used by restock-request list clients.

Headers

Name Type Description
Authorization required string

Bearer Store API token.

Restock request statistics

GET read_inventory

Fetch restock-request lifecycle totals.

Returns a stable zero-filled count for every supported status. Requests whose expiry time has passed are atomically transitioned from pending to expired before the counts are read.

Headers

Name Type Description
Authorization required string

Bearer Store API token.

Notify restock subscribers

POST write_inventory

Notify pending subscribers for one product or variant.

Queues the same email or SMS delivery used by automatic restock notification. Alerts must be enabled and the product must be active with sellable stock. Expired, queued and already-notified requests are not claimed. Enqueued counts are not delivery confirmations; read request statuses for provider acceptance or failure.

Headers

Name Type Description
Authorization required string

Bearer Store API token.

Body parameters

Name Type Description
product_id required integer

Product whose pending subscribers should be notified.

Example: 42
variant_id integer

Variant whose pending subscribers should be notified. Omit for product-level requests.

Example: 107

Errors

  • 400 STORE_API_INVALID_REQUEST_BODY

    The body is malformed, contains unknown fields, or has an invalid product or variant id.

  • 400 INVENTORY_RESTOCK_PRODUCT_INVALID

    The product or requested variant does not exist in this store.

Get restock settings

GET read_inventory

Fetch Notify Me settings.

Returns whether capture is enabled, how long new requests remain pending, whether notifications send automatically when stock is available again, and the accepted expiry range.

Headers

Name Type Description
Authorization required string

Bearer Store API token.

Update restock settings

PUT write_inventory

Update Notify Me settings.

Replaces the three settings together. Unknown fields are rejected. Disabling capture prevents new requests; existing pending requests retain their lifecycle and can still be reviewed.

Headers

Name Type Description
Authorization required string

Bearer Store API token.

Body parameters

Name Type Description
enabled required boolean

Whether storefronts may capture new Notify Me requests.

Example: true
request_expiry_days required integer

Days a new pending request remains eligible for notification.

Example: 90
auto_send_when_restocked required boolean

Whether Tringify automatically notifies eligible pending subscribers after stock becomes available.

Example: true

Errors

  • 400 STORE_API_INVALID_REQUEST_BODY

    The body is malformed or contains unknown fields.

  • 400 INVENTORY_RESTOCK_EXPIRY_DAYS_INVALID

    request_expiry_days is outside the range returned by the settings endpoint.