Get a product
A master product with its variants and offers, from the organisation's own or a licensed catalogue, with only the fields its licences cover.
- Scopes
products:read - Rate classread
/v1/products/{id}A master product with its variants and offers, from the organisation's own or a licensed catalogue, with only the fields its licences cover.
Authorization
apiKey An API key (fo_live_… / fo_test_…) as a bearer token
In: header
Path Parameters
Product (master record) ID
^prod_[0-9A-Za-z]{22}$Header Parameters
Dated API version; pinned per organisation on first use and overridable per request
Value in
- "2026-10-01"
- "2026-10-04"
The data the request acts on: test is the organisation's sandbox. An OAuth token picks it (live by default); an API key's mode is fixed, and naming the other one is refused
Value in
- "live"
- "test"
ETag of a cached representation; a match returns 304
Response Body
application/json
application/problem+json
application/problem+json
application/problem+json
application/problem+json
application/problem+json
application/problem+json
application/problem+json
application/problem+json
curl -X GET "https://example.com/v1/products/string"{ "object": "product", "id": "string", "catalogue": "string", "status": "active", "version": 1, "data": { "title": "string", "brand": "string", "collection": "string", "description": "string", "category_path": [ "string" ], "category": "string", "tags": [ "string" ], "gpc_brick": "string", "features": [ "string" ], "compliance": { "tsca_title_vi": true, "sturdy_act": true, "stability_rating": 0, "ca_tb117_2013": true, "prop65_warning": true, "prop65_chemicals": [ "string" ], "country_of_origin": "string" }, "media": [ { "url": "http://example.com", "role": "hero", "alt": "string", "position": 0, "id": "string", "stored_url": "http://example.com" } ] }, "variants": [ { "object": "variant", "id": "string", "status": "active", "version": 1, "data": { "sku": "string", "gtin": "string", "mpn": "string", "title": "string", "axes": { "property1": "string", "property2": "string" }, "colour": "string", "finish": "string", "materials": [ "string" ], "dimensions": { "width": { "hundredths_in": 0, "given": { "value": 0, "unit": "mm" } }, "depth": { "hundredths_in": 0, "given": { "value": 0, "unit": "mm" } }, "height": { "hundredths_in": 0, "given": { "value": 0, "unit": "mm" } }, "diameter": { "hundredths_in": 0, "given": { "value": 0, "unit": "mm" } }, "seat_height": { "hundredths_in": 0, "given": { "value": 0, "unit": "mm" } }, "seat_depth": { "hundredths_in": 0, "given": { "value": 0, "unit": "mm" } }, "arm_height": { "hundredths_in": 0, "given": { "value": 0, "unit": "mm" } }, "clearance": { "hundredths_in": 0, "given": { "value": 0, "unit": "mm" } } }, "weight": { "hundredths_lb": 0, "given": { "value": 0, "unit": "g" } }, "components": [ { "name": "string", "sku": "string", "quantity": 1, "dimensions": { "width": { "hundredths_in": 0, "given": { "value": 0, "unit": "mm" } }, "depth": { "hundredths_in": 0, "given": { "value": 0, "unit": "mm" } }, "height": { "hundredths_in": 0, "given": { "value": 0, "unit": "mm" } }, "diameter": { "hundredths_in": 0, "given": { "value": 0, "unit": "mm" } }, "seat_height": { "hundredths_in": 0, "given": { "value": 0, "unit": "mm" } }, "seat_depth": { "hundredths_in": 0, "given": { "value": 0, "unit": "mm" } }, "arm_height": { "hundredths_in": 0, "given": { "value": 0, "unit": "mm" } }, "clearance": { "hundredths_in": 0, "given": { "value": 0, "unit": "mm" } } }, "weight": { "hundredths_lb": 0, "given": { "value": 0, "unit": "g" } } } ], "cartons": [ { "width": { "hundredths_in": 0, "given": { "value": 0, "unit": "mm" } }, "depth": { "hundredths_in": 0, "given": { "value": 0, "unit": "mm" } }, "height": { "hundredths_in": 0, "given": { "value": 0, "unit": "mm" } }, "weight": { "hundredths_lb": 0, "given": { "value": 0, "unit": "g" } }, "count": 1 } ], "assembly_required": true, "white_glove": true, "freight_class": "string", "rug": { "shape": "rectangle", "size_text": "string", "nominal": "string", "construction": "hand_knotted", "pile_height": { "hundredths_in": 0, "given": { "value": 0, "unit": "mm" } }, "indoor_outdoor": "indoor" }, "media": [ { "url": "http://example.com", "role": "hero", "alt": "string", "position": 0, "id": "string", "stored_url": "http://example.com" } ], "discontinued": true, "replacement_sku": "string" }, "offers": [ { "object": "offer", "id": "string", "source": "string", "location": "string", "currency": "usd", "cost": 0, "msrp": 0, "map": 0, "price": 0, "compare_at": 0, "quantity": 0, "incoming": [ { "quantity": 1, "eta": "2019-08-24" } ], "availability": "in_stock", "lead_time_days": 0, "version": 1, "observed_at": "2019-08-24T14:15:22Z", "withdrawn_at": "2019-08-24T14:15:22Z" } ], "updated_at": "2019-08-24T14:15:22Z" } ], "visibility": "listed", "created_at": "2019-08-24T14:15:22Z", "updated_at": "2019-08-24T14:15:22Z"}Get a stored image GET
FurniOps' stored copy of an image a product or variant names (its `media[].id`; `media[].stored_url` points here): the copy's size and a download link signed for 15 minutes, so a reader can keep its own copy without fetching from the vendor. Readable when the organisation can see a product or variant that names the image, else 404. Until the copy is stored, `status` is `pending` or `failed` and `download_url` is null.
List offers GET
Every source's price and stock the organisation can see, newest first: filter by variant, product, source, availability or `updated_since`. Each offer shows only the fields its licences cover, as in `GET /v1/products`, and names its variant and catalogue; its product, title and SKU only where the licences show them.