Overview
Backbone is inventory software for independent shops. This API lets an AI assistant, such as Meta’s Muse, work with one business’s Backbone account, as the person who connected it and with that person’s Backbone permissions.
It can read stock levels, products, low-stock alerts, purchase orders, the last stock count and stock reports. It can make exactly two kinds of change: adjust a stock count and receive a delivery against a purchase order. Both are prepared first and applied only after the person confirms. A stock count change can be undone the same way. There is no shopping or checkout surface.
The same 12 tools are available three ways: over MCP (the primary transport), as tool calls by name, and as REST endpoints.
Changing stock: preview, then confirm
- Prepare. Call
adjust_inventory_count, receive_purchase_order or undo_change. Nothing changes. You get a one-sentence summary and a preview_token.
- Ask. Show the person the summary.
- Confirm. Only if they clearly say yes, call
confirm_change with the preview_token and an Idempotency-Key.
Backbone enforces this on its own side; it never relies on the assistant. A preview token is signed, tied to this connection, person and business, works once, and expires after 10 minutes (preview_expired). If the stock changed since the preview, confirm refuses with stale_preview and changes nothing. The person’s Backbone permission (“Edit inventory” or “Receive POs”) is checked again at confirm, as is the business owner’s switch for changes through Muse.
1. Prepare
POST /api/connector/v1/tools/adjust_inventory_count
Authorization: Bearer <access_token>
Content-Type: application/json
{
"sku": "CHR-2IN",
"location_id": "5f1d2c3b-4a59-4e68-8d7c-6b5a49382716",
"counted_qty": 9,
"reason": "damaged"
}
{
"preview_token": "bbp1.eyJ2IjoxLCJhIjoi…",
"action_id": "9b2f6c1e-2d7a-4f0e-9a51-3c8d1e7f4a20",
"summary": "Set 'Chrome Emblem 2in' at Front Rack from 12 to 9 (-3). Reason: damaged.",
"before": {
"item": "Chrome Emblem 2in",
"sku": "CHR-2IN",
"location": "Front Rack",
"qty_available": 12
},
"after": {
"qty_available": 9,
"qty_delta": -3
},
"expires_at": "2026-09-27T18:10:00.000Z"
}
3. Confirm
POST /api/connector/v1/changes/confirm
Authorization: Bearer <access_token>
Idempotency-Key: 3c9e1f7a-adjust-chrome-2in
Content-Type: application/json
{
"preview_token": "bbp1.eyJ2IjoxLCJhIjoi…"
}
{
"action_id": "9b2f6c1e-2d7a-4f0e-9a51-3c8d1e7f4a20",
"action": "adjust_inventory_count",
"status": "applied",
"summary": "Set 'Chrome Emblem 2in' at Front Rack from 12 to 9 (-3). Reason: damaged.",
"after": {
"qty_available": 9,
"qty_delta": -3
},
"applied_at": "2026-09-27T18:01:12.000Z",
"result": {
"inventory_event_ids": [
"5e0c…"
],
"qty_delta": -3
},
"reversible": true,
"request_id": "7f3c2a9e-1b4d-4c55-9e61-0a8b2d3c4e5f"
}
Undo: undo_change with the action_id of an applied stock count change prepares the reversing change; confirm_change applies it. Received deliveries cannot be undone through Muse (not_reversible); a manager records a correction in Backbone instead. A change can be undone once. list_recent_changes shows what was changed and what can still be undone.
Tools
Check stock levels query_inventory
Read-only
Read-only. This cannot change anything in Backbone. Shows how many of an item you have on hand, how many are held for orders, and how many are on the way, at each of your store locations. Use it for questions like "how many AA batteries do we have?" or "what is low at the Front Rack?". Search by part of the name, the exact SKU, or the exact barcode, and optionally one location or only items at or below their reorder point. Never shows cost or price.
- Tool call
POST /api/connector/v1/tools/query_inventory or MCP tools/call with name: "query_inventory"
- REST
GET /api/connector/v1/inventory
- Scope
inventory:read
- Backbone permission
- Any member of the business, within what they can see in Backbone
Input
| Field | Type | Required | Meaning |
|---|
variant_query | string, up to 120 characters | no | Part of the product name, for example "AA batteries" or "2in emblem". |
sku | string, up to 120 characters | no | The exact SKU. |
barcode | string, up to 120 characters | no | The exact barcode (UPC or EAN) as scanned. |
location_id | Backbone id (UUID) | no | Only this store location. Leave out for every location. |
low_stock_only | boolean | no | Only items at or below their reorder point. |
limit | integer, 1 to 50 | no | How many rows to return, 1 to 50. Default 20. |
Returns
count (integer), items (list of objects), note (string)
Find a product lookup_product
Read-only
Read-only. This cannot change anything in Backbone. Finds items in your catalog by exact SKU, exact barcode, or part of the name, brand or code, and shows the item's name, codes, selling price, reorder point and case size. Unit cost appears only for people allowed to see financials. Age-restriction flags are shown for information only. For stock on hand, use query_inventory.
- Tool call
POST /api/connector/v1/tools/lookup_product or MCP tools/call with name: "lookup_product"
- REST
GET /api/connector/v1/products/lookup
- Scope
inventory:read
- Backbone permission
- Any member of the business; cost and value figures only for people with “View financials”
Input
| Field | Type | Required | Meaning |
|---|
sku | string, up to 120 characters | no | The exact SKU. |
barcode | string, up to 120 characters | no | The exact barcode (UPC or EAN) as scanned. |
query | string, up to 120 characters | no | Part of the product name, brand or code. Used only when no SKU or barcode is given. |
limit | integer, 1 to 50 | no | How many matches to return, 1 to 50. Default 10. |
Returns
match (one of: sku, barcode, name), count (integer), items (list of objects), note (string)
See low-stock alerts list_low_stock_alerts
Read-only
Read-only. This cannot change anything in Backbone. Lists the low-stock and out-of-stock alerts Backbone has raised for your items, newest first, with the item, the location and the level that triggered each one. The list is as fresh as Backbone's last stock check; for a live count use query_inventory. Open alerts only unless you ask to include ones already marked as seen.
- Tool call
POST /api/connector/v1/tools/list_low_stock_alerts or MCP tools/call with name: "list_low_stock_alerts"
- REST
GET /api/connector/v1/alerts
- Scope
inventory:read
- Backbone permission
- Any member of the business, within what they can see in Backbone
Input
| Field | Type | Required | Meaning |
|---|
type | one of: low_stock, out_of_stock | no | Only "low_stock" or only "out_of_stock". Leave out for both. |
location_id | Backbone id (UUID) | no | Only this store location. Leave out for every location. |
include_acknowledged | boolean | no | Also include alerts someone has already marked as seen. Default false (open alerts only). |
limit | integer, 1 to 50 | no | How many alerts to return, 1 to 50. Default 20. |
Returns
count (integer), alerts (list of objects), note (string)
List purchase orders list_purchase_orders
Read-only
Read-only. This cannot change anything in Backbone. Lists your purchase orders, newest first, with the supplier, the status, and how many units have arrived and how many are still to come. Use status "open" for orders still waiting on a delivery. Order totals appear only for people allowed to see financials.
- Tool call
POST /api/connector/v1/tools/list_purchase_orders or MCP tools/call with name: "list_purchase_orders"
- REST
GET /api/connector/v1/purchase-orders
- Scope
purchasing:read
- Backbone permission
- Any member of the business; cost and value figures only for people with “View financials”
Input
| Field | Type | Required | Meaning |
|---|
status | one of: open, draft, pending_approval, sent, partially_received, received, cancelled, closed | no | "open" = ordered and still waiting for some or all of the delivery. Or one exact status. Leave out for every status. |
vendor | string, up to 120 characters | no | Part of the supplier name. |
location_id | Backbone id (UUID) | no | Only orders shipping to this store location. |
limit | integer, 1 to 50 | no | How many orders to return, 1 to 50. Default 20. |
Returns
count (integer), purchase_orders (list of objects), note (string)
Open a purchase order get_purchase_order
Read-only
Read-only. This cannot change anything in Backbone. Shows one purchase order, by id or PO number, line by line: what was ordered, what has arrived so far, and what is still to come. Use it before receiving a delivery. Costs appear only for people allowed to see financials.
- Tool call
POST /api/connector/v1/tools/get_purchase_order or MCP tools/call with name: "get_purchase_order"
- REST
GET /api/connector/v1/purchase-orders/{purchase_order_id}
- Scope
purchasing:read
- Backbone permission
- Any member of the business; cost and value figures only for people with “View financials”
Input
| Field | Type | Required | Meaning |
|---|
purchase_order_id | Backbone id (UUID) | no | The purchase order id (from list_purchase_orders). |
po_number | string, up to 40 characters | no | The PO number as printed, for example "PO-00001234". Used when no id is given. |
line_limit | integer, 1 to 50 | no | How many lines to return, 1 to 50. Default 50. |
line_offset | integer, at least 0 | no | Skip this many lines first, to page through a long order. Default 0. |
Returns
purchase_order (object), lines (list of objects), lines_returned (integer), line_offset (integer), more_lines (boolean)
See the last stock count last_stock_count
Read-only
Read-only. This cannot change anything in Backbone. Shows the most recent finished stock count at each of your locations: when it was done, how many items were counted, how many units were missing or extra, and the biggest differences. Use it for questions like "when did we last count the back room, and what was off?".
- Tool call
POST /api/connector/v1/tools/last_stock_count or MCP tools/call with name: "last_stock_count"
- REST
GET /api/connector/v1/stock-counts/latest
- Scope
inventory:read
- Backbone permission
- Any member of the business, within what they can see in Backbone
Input
| Field | Type | Required | Meaning |
|---|
location_id | Backbone id (UUID) | no | Only this store location. Leave out for the latest count at each location. |
include_in_progress | boolean | no | Also consider counts that are not finished yet. Default false (finished counts only). |
limit | integer, 1 to 50 | no | How many locations to return, 1 to 50. Default 5. |
Returns
count (integer), stock_counts (list of objects), note (string)
Run a stock report run_report
Read-only
Read-only. This cannot change anything in Backbone. Runs one of your stock reports: "reorder" (what is at or below its reorder point and needs ordering), "dead_stock" (what has stock but has not sold in 90 days or more) or "velocity" (your best sellers, by units sold per day). Quantities and dates for everyone; cost and value figures only for people allowed to see financials.
- Tool call
POST /api/connector/v1/tools/run_report or MCP tools/call with name: "run_report"
- REST
GET /api/connector/v1/reports/{report}
- Scope
reports:read
- Backbone permission
- Any member of the business; cost and value figures only for people with “View financials”
Input
| Field | Type | Required | Meaning |
|---|
report | one of: reorder, dead_stock, velocity | yes | "reorder" = what is at or below its reorder point and needs ordering; "dead_stock" = what has stock but has not sold in 90 days or more; "velocity" = the best sellers, by units sold per day. |
location_id | Backbone id (UUID) | no | Only this store location. Leave out for every location. |
days | integer, at least 90 | no | dead_stock only: at least this many days without a sale (90 or more). |
limit | integer, 1 to 50 | no | How many rows to return, 1 to 50. Default 20. |
Returns
report (one of: reorder, dead_stock, velocity), count (integer), items (list of objects), min_days_without_sale (integer), note (string), note_financials (string)
See recent changes list_recent_changes
Read-only
Read-only. This cannot change anything in Backbone. Lists the recent stock changes made through Muse for this business, newest first: what changed, whether you or someone else made it, and whether it was undone. Use it for questions like "what did you change today?". Each stock count change shows whether undo_change can still undo it.
- Tool call
POST /api/connector/v1/tools/list_recent_changes or MCP tools/call with name: "list_recent_changes"
- REST
GET /api/connector/v1/changes
- Scope
activity:read
- Backbone permission
- Any member of the business, within what they can see in Backbone
Input
| Field | Type | Required | Meaning |
|---|
limit | integer, 1 to 50 | no | How many changes to return, 1 to 50. Default 20. |
Returns
count (integer), changes (list of objects)
Prepare a stock count change adjust_inventory_count
Prepares a change (preview)
Prepares a change to the stock count of one item at one location, for example after a recount or when items are damaged. This step changes NOTHING: it returns a plain summary such as "Set Chrome Emblem 2in at Front Rack from 12 to 9 (-3). Reason: damaged." and a preview_token. Show the summary to the person, and only if they say yes, call confirm_change with the preview_token. The preview expires after 10 minutes.
- Tool call
POST /api/connector/v1/tools/adjust_inventory_count or MCP tools/call with name: "adjust_inventory_count"
- REST
POST /api/connector/v1/inventory/adjustments/preview
- Scope
inventory:write
- Backbone permission
- “Edit inventory”
- Applied by
confirm_change, after the person says yes
Input
| Field | Type | Required | Meaning |
|---|
variant_id | Backbone id (UUID) | no | The item to adjust. Or give its sku or barcode instead. |
sku | string, up to 120 characters | no | The exact SKU of the item to adjust. |
barcode | string, up to 120 characters | no | The exact barcode of the item to adjust. |
location_id | Backbone id (UUID) | yes | The store location whose count changes. |
counted_qty | integer, 0 to 1000000 | no | The new count, as counted on the shelf. Give this OR qty_delta. |
qty_delta | integer, -1000000 to 1000000 | no | Units to add (positive) or remove (negative), never 0. Give this OR counted_qty. |
reason | string, up to 500 characters | yes | Why the count is changing, for example "damaged" or "recount". |
Returns
preview_token (string), action_id (string), summary (string), before (object), after (object), expires_at (string)
Prepare receiving a delivery receive_purchase_order
Prepares a change (preview)
Prepares receiving a delivery against one of your purchase orders: everything still outstanding, or line by line. This step changes NOTHING: it returns a plain summary of what would be added to stock and a preview_token. Show the summary to the person, and only if they say yes, call confirm_change with the preview_token. The preview expires after 10 minutes.
- Tool call
POST /api/connector/v1/tools/receive_purchase_order or MCP tools/call with name: "receive_purchase_order"
- REST
POST /api/connector/v1/purchase-orders/{purchase_order_id}/receipts/preview
- Scope
purchasing:write
- Backbone permission
- “Receive POs”
- Applied by
confirm_change, after the person says yes
Input
| Field | Type | Required | Meaning |
|---|
purchase_order_id | Backbone id (UUID) | no | The purchase order the delivery is for. Or give po_number. |
po_number | string, up to 40 characters | no | The PO number as printed, for example "PO-00001234". |
receive_all | boolean | no | Receive everything still outstanding on the order. |
receipts | list of objects, up to 200 items | no | What arrived, line by line. Leave out when receive_all is true. |
receipts[].line_id | Backbone id (UUID) | no | The PO line (from get_purchase_order). Or give sku. |
receipts[].sku | string, up to 120 characters | no | |
receipts[].quantity | integer, 1 to 1000000 | yes | Single units that arrived. |
receipts[].notes | string, up to 500 characters | no | |
Returns
preview_token (string), action_id (string), summary (string), before (object), after (object), expires_at (string)
Confirm a prepared change confirm_change
Applies a prepared change
Confirms and applies ONE change that was prepared by adjust_inventory_count, receive_purchase_order or undo_change, using its preview_token. Call this ONLY after showing the person the preview summary and hearing them say yes. It fails safely, changing nothing, if the preview expired, was already used, or the numbers changed since it was prepared. Send an idempotency_key so a retry can never apply the change twice.
- Tool call
POST /api/connector/v1/tools/confirm_change or MCP tools/call with name: "confirm_change"
- REST
POST /api/connector/v1/changes/confirm
- Scope
inventory:write or purchasing:write
- Backbone permission
- “Edit inventory” or “Receive POs”
Input
| Field | Type | Required | Meaning |
|---|
preview_token | string, up to 4096 characters | yes | The preview_token from the preview the person agreed to. |
idempotency_key | string, up to 255 characters | no | Any retry key of your choice. Sending the same key again returns the first result and never applies the change twice. |
Returns
action_id (string), action (one of: adjust_inventory_count, receive_purchase_order, reverse_inventory_adjustment), status (one of: applied), summary (string), before (object), after (object), applied_at (string), result (object), reversible (boolean), request_id (string)
Prepare undoing a stock change undo_change
Prepares an undo (preview)
Prepares undoing one stock count change that was made through Muse. This step changes NOTHING: it returns a summary of the reversing change and a preview_token. Show the summary to the person, and only if they say yes, call confirm_change with the preview_token. Received deliveries cannot be undone through Muse.
- Tool call
POST /api/connector/v1/tools/undo_change or MCP tools/call with name: "undo_change"
- REST
POST /api/connector/v1/changes/{action_id}/undo
- Scope
inventory:write
- Backbone permission
- “Edit inventory”
- Applied by
confirm_change, after the person says yes
Input
| Field | Type | Required | Meaning |
|---|
action_id | Backbone id (UUID) | yes | The applied stock adjustment to undo (from confirm_change or list_recent_changes). |
Returns
preview_token (string), action_id (string), summary (string), before (object), after (object), expires_at (string)