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.