API docs
Products, categories, vendors
Permission: products (read / write).
The product object
{
"object": "product",
"id": 2053,
"sku": "GLK-G19G5",
"upc": "764503037269",
"name": "Glock 19 Gen 5 9mm",
"brand": "Glock",
"manufacturer": "Glock Inc.",
"model": "19 Gen5",
"description": null,
"product_type": "firearm",
"category_id": 511,
"vendor_id": 155,
"vendor_sku": "GLPA195S203",
"is_active": true,
"is_serialized": true,
"is_firearm": true,
"is_nfa": false,
"track_inventory": true,
"min_age": 21,
"tax_class": "standard",
"price_cents": 57900,
"cost_cents": 43900,
"map_price_cents": 54900,
"compare_at_cents": null,
"sale_price_cents": null,
"sale_starts_at": null,
"sale_ends_at": null,
"sale_scope": "store",
"effective_price_cents": 57900,
"firearm": { "type": "pistol", "caliber": "9mm", "action": "striker", "barrel_length": "4.02\"", "capacity": "15", "finish": "Black", "importer": null, "country_of_origin": "Austria" },
"weight_grams": 850,
"image_url": "https://cdn11.bigcommerce.com/…/g19.jpg",
"reorder_point": 2,
"reorder_qty": 3,
"sell_online": true,
"bigcommerce": { "product_id": 141, "variant_id": 188 },
"flxpoint_product_id": null,
"inventory": [ { "object": "inventory_level", "product_id": 2053, "location_id": 93, "qty_on_hand": 3, "qty_reserved": 0, "qty_available": 3, "reorder_point": null, "bin_location": "Case 2", "updated_at": "2026-09-24T06:22:22Z" } ],
"created_at": "2026-09-03T15:10:00Z",
"updated_at": "2026-09-24T06:22:22Z"
}
| Field | Notes |
|---|---|
product_type |
firearm, ammunition, accessory, service, fee, gift_card |
is_firearm |
Sale needs a Form 4473 at the counter |
is_serialized |
Stocked as individual units with serial numbers (see Inventory) |
tax_class |
standard, exempt, ammunition, service |
effective_price_cents |
sale_price_cents while a sale window is open, otherwise price_cents |
sale_scope |
store (counter only) or store_online (also pushed to BigCommerce) |
firearm |
Present for firearms, otherwise null. type is one of pistol, revolver, rifle, shotgun, receiver, frame, silencer, sbr, sbs, machine_gun, aow, other |
inventory |
Levels at the locations the key can see. Always on single-product responses; on lists with include=inventory |
List products
GET /v1/products
| Filter | |
|---|---|
sku, upc, vendor_sku |
Exact match |
product_type, category_id, vendor_id, bigcommerce_product_id |
Exact match |
is_active |
true / false |
q |
Name, SKU prefix, model, or exact UPC |
include=inventory |
Embed levels |
updated_since, limit, cursor |
See Conventions |
curl "https://app.ironregister.com/api/v1/products?product_type=ammunition&include=inventory&limit=100" \
-H "Authorization: Bearer $KEY"
Get a product
GET /v1/products/{id}: the product with its inventory levels.
Create a product
POST /v1/products (write). Requires name and price_cents. Everything else is optional:
skuis generated if you leave it out.- Send the read shape:
is_firearm,reorder_point,reorder_qtyand a nestedfirearm{}. The internal flat names (requires_4473,default_reorder_point,default_reorder_qty,firearm_type,caliber,action_type, …) are accepted too. reorder_pointandreorder_qtyare the product's defaults. A product needs reordering at a location when what's available there (on hand less held) plus what's on order is at or below its reorder point; Reorder then ordersreorder_qty(a location's own reorder point and quantity win when set).vendor_id/vendor_skuare the product's preferred vendor. Setting them makes that vendor the preferred one on the product's vendor list in Iron Register (other vendors stay listed).- A
product_typeoffirearmalways makes the productis_firearm: trueandis_serialized: true.
curl -X POST https://app.ironregister.com/api/v1/products \
-H "Authorization: Bearer $KEY" -H "Content-Type: application/json" \
-H "Idempotency-Key: 7d3f0c1e-2b8a-4c55-9d1e-0f6a2c1b9e44" \
-d '{
"sku": "HRN-9-124-XTP-25",
"name": "Hornady Critical Defense 9mm 115gr (25)",
"brand": "Hornady",
"product_type": "ammunition",
"tax_class": "ammunition",
"price_cents": 2899,
"cost_cents": 1950,
"upc": "090255900905",
"vendor_id": 155,
"vendor_sku": "90250",
"reorder_point": 6
}'
Returns 201 with the product.
Possible errors:
409 SKU_TAKEN400 VALIDATION_ERRORfor an unknowncategory_idorvendor_id, or a badfirearm.type
Update a product
PATCH /v1/products/{id} (write). Send only the fields you're changing.
- Prices, descriptions and the rest are ordinary edits.
- Compliance fields are fixed.
is_firearm,is_serialized,is_nfa, and changingproduct_typeto or fromfirearm, can't be changed after creation:409 COMPLIANCE_FIELDwithdetails.field. They decide whether a sale needs a 4473 and a bound-book entry, so they're changed only in Iron Register. Sending the current value is fine. - Sale prices online. Changing
sale_price_cents,sale_starts_atorsale_ends_aton a product withsale_scope: "store_online"also queues the sale price to BigCommerce.
curl -X PATCH https://app.ironregister.com/api/v1/products/2062 \
-H "Authorization: Bearer $KEY" -H "Content-Type: application/json" \
-d '{ "price_cents": 1799, "sale_price_cents": 1599, "sale_starts_at": "2026-10-01T04:00:00Z", "sale_ends_at": "2026-10-08T04:00:00Z" }'
Delete a product
DELETE /v1/products/{id} (write). Refused with 409 HAS_STOCK while any location has stock on hand. To take a product out of use, set is_active: false instead.
{ "status": "ok", "data": { "object": "product", "id": 2062, "deleted": true } }
Categories
GET /v1/categories (products:read). Paginated, with updated_since.
{ "object": "category", "id": 511, "name": "Handguns", "parent_id": 510, "sort_order": 1, "bigcommerce_category_id": 24, "updated_at": "2026-09-03T15:10:00Z" }
Vendors
GET /v1/vendors (products:read). Paginated, with updated_since.
{ "object": "vendor", "id": 155, "name": "Lipsey's", "code": "LIP", "contact_name": "Rep Desk", "email": "orders@example.com", "phone": "800-555-0100", "website": "https://www.lipseys.com", "is_distributor": true, "flxpoint_source_id": "src_8812", "status": "active", "updated_at": "2026-09-03T15:10:00Z" }