Get inventory changes
Endpoint: GET /v10/inventory/changes
Available properties for filtering: product_id, variant_id, inventory_location_id, type, created_at, updated_at
Available nested resources for including: inventoryLocation, product, variant
This endpoint fetches the inventory ledger of the account: every inventory change, ordered by id ascending.
note
This endpoint only supports cursor pagination. Every response includes has_more and next_cursor, and the response never includes totals. Requests using the page parameter return a 422 validation error. Walk the list with limit + cursor (or starting_after) instead.
The maximum limit on this endpoint is 1000. The only supported sorting is id.
Data of response
| Parameter | Required | Default | Description |
|---|---|---|---|
inventory_changes.* | Yes | An array of object inventory change | |
has_more | Yes | Whether more rows exist after the last row of this page | |
next_cursor | Yes | Opaque token pointing at the last row of this page. null when has_more is false |
Incremental sync
Inventory changes are created with increasing ids, so the simplest way to keep a copy of the ledger is to remember the highest id you have stored and only fetch changes after it.
- Read the highest
idyou have stored. Use0the first time. - Request
GET /v10/inventory/changes?limit=1000&starting_after={id}. - Store the returned rows and remember the
idof the last row. - If
has_moreistrue, repeat from step 2 with the newid. If it isfalse, you are done until the next run.
GET /v10/inventory/changes?limit=1000&starting_after=0
GET /v10/inventory/changes?limit=1000&starting_after=48211907
GET /v10/inventory/changes?limit=1000&starting_after=48212907
A full backfill is the same walk starting from 0. At 1000 rows per request and the rate limit of 30 requests per minute, that is 30,000 changes per minute.
Only fetch settled changes
Changes are written in database transactions, and a transaction that started earlier can finish after one that started later. In rare cases a change with a lower id becomes visible after you have already walked past it. To avoid skipping such a change, only fetch changes that are at least a few minutes old by adding a filter on created_at:
GET /v10/inventory/changes?limit=1000&starting_after={id}
&filter_groups[0][filters][0][key]=created_at
&filter_groups[0][filters][0][operator]=lt
&filter_groups[0][filters][0][value]=2026-10-12 02:55:00
Set the value to the time your sync starts minus 5 minutes, and keep the same value for every request of that run.
Changes to existing rows
The walk above picks up new changes. If you also need updates to changes you have already stored (for example booked and book_date being set when a change is booked), run a second walk with a filter on updated_at greater than the start time of your previous sync, still walking by id with starting_after from 0:
GET /v10/inventory/changes?limit=1000&starting_after=0
&filter_groups[0][filters][0][key]=updated_at
&filter_groups[0][filters][0][operator]=gt
&filter_groups[0][filters][0][value]=2026-10-11 03:00:00
Replace the stored rows with the returned ones by id.