API docs
Inventory
Permission: inventory (read / write).
Iron Register is the source of truth for on-hand stock. Every quantity change, whether a sale, a receiving, a count, a transfer or an API adjustment, is recorded as a stock movement. The level is the running total of those movements. A key limited to some locations only sees those locations.
Levels
GET /v1/inventory: one row per product per location.
| Filter | |
|---|---|
product_id, sku |
One product |
location_id |
One location (must be one the key can see; otherwise the list is empty) |
updated_since, limit, cursor |
See Conventions |
curl "https://app.ironregister.com/api/v1/inventory?location_id=93&updated_since=2026-09-24T00:00:00Z" \
-H "Authorization: Bearer $KEY"
{
"object": "inventory_level",
"product_id": 2062,
"location_id": 93,
"qty_on_hand": 40,
"qty_reserved": 0,
"qty_available": 40,
"reorder_point": 12,
"bin_location": "A-3",
"updated_at": "2026-09-25T01:48:03Z",
"sku": "AMM-9-115-50",
"name": "Blazer Brass 9mm 115gr FMJ (50)"
}
qty_available is qty_on_hand minus qty_reserved. Use qty_available when you publish stock to a sales channel.
qty_reserved counts serialized units that are on the premises but not for sale: a firearm on an open 4473 or outbound transfer, waiting for its transfer pickup, in repair, or in the rental fleet. Non-serialized products always show 0.
Adjust
POST /v1/inventory/adjust (write) adds to or removes from on-hand stock.
| Field | |
|---|---|
product_id or sku |
Required (one of them) |
location_id |
Defaults to the key's only location, else the shop's default location |
qty_delta |
Required, non-zero integer; negative removes |
reason |
adjust (default), damage, return_to_vendor, count, receive, transfer_in, transfer_out |
note |
Up to 200 characters. Stored as API (<key name>): <note> |
unit_cost_cents |
Optional cost for the movement |
curl -X POST https://app.ironregister.com/api/v1/inventory/adjust \
-H "Authorization: Bearer $KEY" -H "Content-Type: application/json" \
-H "Idempotency-Key: dropship-return-88213" \
-d '{ "sku": "AMM-9-115-50", "location_id": 93, "qty_delta": 5, "reason": "receive", "note": "Flxpoint PO 88213" }'
Returns the level after the change.
Set a count
POST /v1/inventory/set (write) sets an absolute quantity, as from a physical count. Send product_id or sku, location_id, qty_on_hand (≥ 0) and an optional note. It's recorded as a count movement for the difference.
Both writes are refused:
- On serialized products:
409 SERIALIZED. Serialized units, including every firearm, come in by receiving and go out by a sale or transfer in Iron Register, because each is a bound-book entry. - On products that don't track inventory:
409 NOT_TRACKED. - When the result would go below zero and the shop doesn't allow negative stock:
409 INSUFFICIENT_STOCK.
Both writes accept Idempotency-Key. Always send one on adjustments, because a retried adjustment without it counts twice.
Serialized units
GET /v1/inventory/serialized lists individual units with their serial numbers. Serial numbers are read-only.
| Filter | |
|---|---|
product_id, sku |
One product |
status |
in_stock, reserved, awaiting_transfer, sold, transferred, returned_to_vendor, returned_to_consignor, in_repair, consignment, stolen_lost, voided, rental |
serial_number |
Exact match |
location_id, updated_since, limit, cursor |
{
"object": "serialized_item",
"id": 2189,
"product_id": 2053,
"location_id": 93,
"serial_number": "BZRW99298B",
"status": "in_stock",
"condition": "new",
"price_cents": null,
"cost_cents": 43900,
"acquired_on": "2026-09-15",
"is_consigned": false,
"updated_at": "2026-09-24T06:22:23Z",
"sku": "GLK-G19G5"
}
price_cents is the unit's own price when it differs from the product's (used guns, consignments). Otherwise it's null.
Movements
GET /v1/inventory/movements is the stock ledger, oldest first. Filter by product_id, sku, location_id or updated_since; for this list, updated_since filters on creation time.
{ "object": "stock_movement", "id": 90112, "product_id": 2062, "location_id": 93, "qty_delta": -2, "qty_after": 38, "reason": "sale", "reference_type": "sale", "reference_id": 5521, "created_at": "2026-09-25T02:10:44Z" }
| Field | Values |
|---|---|
reason |
sale, sale_void, refund, receive, adjust, count, damage, return_to_vendor, transfer_in, transfer_out, online_sale, online_refund, migration, consignment, trade_in, consignment_in, consignment_return, bound_book_void |
reference_type |
sale, return, receiving, api, …, or null |
reference_id |
Set for sale, return and receiving. A sale reference is an order id. |
For real-time stock changes, subscribe to the inventory.changed webhook.