Skip to content
Docs

02API guides

API v1For developers

Keep Rollmark stock in sync from your inventory system

Rollmark supports FastBound for the store's guns. A store's other stock (ammunition, optics, parts, gear, and guns the store does not keep in FastBound) is kept by hand in Rollmark, and an inventory management system can keep it up to date through the API instead. You use your own id for every item, so the same id is always the same item.

What is yours to change, and what is not

Hand-managed itemsFastBound items
Where they come fromMade by hand in Rollmark or through this APISynced from FastBound
Readyes (inventory:read)yes, read only; the serial is shown as its last four characters
Writeyes (inventory:write)never: 409 fastbound_managed. FastBound is the record for guns; change it there.

Your cost is never in the API, in either direction: a field named cost is refused. Pricing rules and MAP are not in the API.

You need a key with inventory:read and inventory:write (the "Inventory system" preset). Nothing else.

Choose your external_id

A stable id from your system, 1 to 100 characters: your SKU, or your item record id. It is the handle: PUT /inventory/items/{external_id} creates the item the first time and changes it after. Never reuse one for a different item. (An id that equals a FastBound item's Rollmark id is refused, so the two cannot be mixed up.)

One item at a time

Shell
# create or update (what you send is set; what you leave out stays)
curl -X PUT "https://app.getrollmark.com/api/v1/inventory/items/SKU-1001" \
  -H "Authorization: Bearer $ROLLMARK_KEY" -H "Content-Type: application/json" \
  -d '{"title":"Cleaning kit","category":"gear","manufacturer":"Otis","quantity":3,"price":24.99}'

# a sale of 1 (applied in the database: two systems adjusting at once do not lose an update)
curl -X PATCH ".../inventory/items/SKU-1001" -H "Authorization: Bearer $ROLLMARK_KEY" \
  -H "Content-Type: application/json" -d '{"quantity_delta":-1}'

# none on hand (the item stays, and so does your id)
curl -X POST ".../inventory/items/SKU-1001/zero" -H "Authorization: Bearer $ROLLMARK_KEY"

# keep it off the store without deleting it
curl -X PATCH ".../inventory/items/SKU-1001" -H "Authorization: Bearer $ROLLMARK_KEY" \
  -H "Content-Type: application/json" -d '{"hidden":true}'

An item is either a product of its own (title, category, and optionally manufacturer, model, upc, mpn) or stock added to a catalog product (link_to: the product key, for example upc:012345678905, which must be a product the store has). The same checks as the Add item form apply: a valid UPC check digit, quantity 0 to 9999, lengths. A category is one of handguns, rifles, shotguns, nfa, ammunition, magazines, optics, parts, gear, reloading. An item cannot be moved to another product after it is made: remove it and make a new one.

Hide, zero or delete?

You wantDoThe store shows
The item gone from the store but kept in your inventoryhidden: trueNothing from this item. A product it only added stock to loses that stock; a product of its own leaves the store.
Sold out but still yoursPOST …/zeroNone on hand
The item is no moreDELETENothing; the id is free to reuse

Many at once, and a nightly resync

POST /inventory/batch takes up to 500 operations (upsert, patch, zero, delete), each with its external_id and the fields of the single call. Each is applied on its own, so one bad item does not lose the rest. The answer is always 200 with a result per item:

JSON
{
  "results": [
    { "external_id": "SKU-1001", "status": "updated" },
    { "external_id": "SKU-1002", "status": "error", "error": { "code": "bad_request", "message": "Some fields need a change. Nothing was saved.", "fields": [{ "field": "quantity", "message": "…" }] } }
  ],
  "summary": { "total": 2, "created": 0, "updated": 1, "unchanged": 0, "deleted": 0, "error": 1 },
  "effective": "after_rebuild"
}

An Idempotency-Key is required on a batch, so a request that timed out can be sent again and answers the same. Use one that names the run (inventory-2026-10-16-0200-part-3).

Node
// A nightly full resync: send everything you have, 500 at a time. (To remove items you no longer have, read the
// store's list first and send `op: 'delete'` for the ids that are not in your system.)
async function resync(items, runId) {
  for (let i = 0; i < items.length; i += 500) {
    const chunk = items.slice(i, i + 500).map((it) => ({ external_id: it.sku, op: 'upsert', ...it.fields }));
    const res = await rollmark('POST', '/inventory/batch', { items: chunk }, `${runId}-${i / 500}`);
    for (const r of res.results.filter((x) => x.status === 'error')) {
      console.warn(r.external_id, r.error.code, r.error.fields ?? r.error.message); // fix these in your system
    }
  }
}

The batch is rate limited to 60 a minute (one call, however many items); single changes to 300 a minute. See Rate limits.

It shows on the store after the next rebuild

Every change queues a rebuild of the store's listings, the same way the Add item form does. The store's product pages, search and stock update after that rebuild, normally within minutes, not instantly; the answer says "effective": "after_rebuild". A batch asks for one rebuild, not 500. Do not poll the catalog expecting the change in the same second.

Reconcile

Read back what Rollmark has, and compare:

Shell
curl "https://app.getrollmark.com/api/v1/inventory/items?source=manual&limit=100" -H "Authorization: Bearer $ROLLMARK_KEY"

Follow next_cursor. Use updated_since=<time> to read only what changed (including changes staff made by hand in Rollmark), and external_id= to check one item. A good integration does events in the day and a full resync at night.

When something is refused

AnswerMeaningDo
409 fastbound_managedYou named a FastBound itemDo not write it. Change it in FastBound.
400 bad_request with fieldsA value failed the checksFix it in your system; the field name says which
404 not_found on PATCH, zero, DELETENo item with that external_idPUT it first
403 missing_permissionThe key lacks inventory:writeMake a key with it
429Over the limitWait Retry-After; use the batch
503 setting_upThe store's database update is pendingTry later
Rollmark is made by Illumina Studios LLC. It was built at Ironcrest Arms LLC. Sample dealers, license numbers and costs in these docs are made up. Questions: [email protected].