Docs

Docs / Data Feed / Inventory API

For Data Feed stores
Reference · Inventory API v1

Inventory API overview

Read and write your store's in-house inventory rows from your own systems: a point of sale, a bound book, a spreadsheet or a script.

Base URL
https://backend.fflmonkey.com/api/v1/inventory
Auth
Authorization: Bearer ffl_sk_live_3f9a… Create a key
Limit
120 requests a minute, per key
Format
JSON in, JSON out

What a row does in your store

The API reads and writes the same rows as the In-house inventory screen: in wp-admin, FFLMonkey.com › Data Feed › In-house inventory, or, for a store on its own website, the licence's settings in your FFL Monkey account. Each row is one product you hold yourself, identified by its UPC, with a stock count and the price you sell it at. Anything you change here shows up on that screen, and anything changed there shows up here.

  • It competes with your distributors' offers for the same product. The cheapest offer wins, and at an equal price your in-house row wins.
  • Your price is published as you set it. Your pricing rules and default margin do not apply to in-house rows.
  • Your restrictions still apply. A rule about the product (its category, brand, product class or UPC, or your own SKU) or about stock hides your in-house row the same way it hides a distributor's offer. Rules about a distributor or a cost range do not apply to items you own.
  • A row with stock 0 is kept but not offered.
  • cost_price is for your own records. It does not change what your store shows.

A row only reaches your store when our catalog carries its UPC

Every item response says so in in_catalog (and product_id). When in_catalog is false, the row is saved and returned like any other, but there is no catalog product for it to attach to, so it does not appear in your store. It starts competing on its own as soon as a distributor supplies that UPC and the product is added to the catalog. You do not need to send it again.

If you have paused updates to your store in your FFL Monkey settings, changes you make through the API are still saved, but your store does not receive them while updates are paused. When you turn updates back on, your store is brought up to date.

Authentication

Send the key in the Authorization header of every request:

Authorization: Bearer ffl_sk_live_3f9a…

Keys start with ffl_sk_live_ followed by 49 letters and digits. A key belongs to one store and can only see and change that store's rows. Reading needs inventory:read, which a key given In-house inventory has; changing anything needs inventory:write, which only a key given In-house inventory: Read and write has. Create a key.

Keep the key on a server

It is a secret that can change your store's stock and prices. Use it from your own server or a script, and never in a web page or browser code. The API does not answer browsers' cross-origin requests, on purpose.

A missing, mistyped, unknown or revoked key gets 401 invalid_api_key. If your FFL Monkey subscription is suspended, cancelled or not yet active, every request but GET /key gets 403 license_not_active, with the reason. GET /key still answers, and reports the same in license.

Base URL and formats

https://backend.fflmonkey.com/api/v1/inventory

  • Send request bodies as JSON with Content-Type: application/json. Responses are always JSON.
  • Times are ISO 8601, in UTC: 2026-10-07T15:00:00+00:00.
  • Money comes back as a string with two decimals ("499.00"). You may send it as a number or a string, with at most two decimals.
  • A UPC is 1 to 32 letters, digits or hyphens, exactly as you store it. Leading zeros matter: 012345678905 and 12345678905 are different rows.

Rate limit

Each key may make 120 requests a minute, counted across the whole API: its Store API requests count towards the same 120. A batch request counts as one request however many rows it carries, so use the batch endpoint for anything over a handful of rows.

Every response to a valid key carries X-RateLimit-Limit and X-RateLimit-Remaining, refusals included: a 403 counts like any other request. A 404 or 405 for an address or a method the API does not have is answered before it is counted, and carries neither header. Past the limit you get 429 rate_limited with a Retry-After header giving the seconds to wait.

The item

Every item response uses this shape.

FieldTypeWhat it holds
upcstringAs you store it. Leading zeros matter.
skustring or nullYour own SKU.
stockinteger0 or more. A row with stock 0 is kept but not offered.
pricestringTwo decimals, such as "499.00". Published as you set it.
cost_pricestring or nullTwo decimals. For your own records: it does not change what your store shows.
notesstring or nullYour notes.
sourcestringHow the row was last written: manual, csv, spreadsheet (the In-house inventory screen) or api. Every write through this API sets it to api. More values may be added.
in_catalogbooleanWhether our catalog carries a product with this UPC. false: saved, but it cannot reach your store until it does.
product_idinteger or nullThe catalog product's id, or null when in_catalog is false.
created_atstringISO 8601, UTC.
updated_atstringISO 8601, UTC.

Versioning

This is version 1, and the /v1/ in the address is a promise: it only grows. We may add endpoints, response fields, optional request fields, error codes and values (such as a new source), so ignore fields you do not know and treat unknown values as valid.

We will not remove or rename a field, change its type or meaning, or make an optional field required. A change that would break that is a new version at a new address.

OpenAPI document

A machine-readable description of this API (OpenAPI 3.1), for Postman, code generators and similar tools:

https://docs.fflmonkey.com/openapi/inventory-v1.json

FFL Monkey Data Feed API, version 1. Questions: Support in your FFL Monkey account, or [email protected].