Overview
What FurniOps is, how its data reaches you, and the pieces you build with.
FurniOps collects furniture vendors' product data from wherever it lives (vendor APIs, platform feeds, CSV and Excel files, emailed price lists and product pages), turns it into one master record per product, and keeps it current. Every field records where its value came from. When a vendor changes a price, a stock level or a description, FurniOps writes the change once and tells every system that cares.
How data reaches you
There are three ways to read FurniOps, and they all carry the same objects and the same events:
| Way | Use it for | Start with |
|---|---|---|
| REST API | Reading the current state: products, variants, offers, sources, runs. | GET /v1/products |
| Change feed | Keeping a copy in sync. An ordered, replayable log of every change, read with a cursor; it is the source of truth. | The change feed |
| Webhooks | Being told at once. Each change is POSTed to your endpoint, signed, retried for about three days. | Your first webhook |
A server-sent event stream (GET /v1/stream) carries the same events live, for dashboards and
local tools such as furniops listen.
Webhooks are the doorbell, the feed is the ledger
Webhooks get a change to you within seconds, but a receiver can be down. The change feed keeps 30 days of events in commit order, so a system that must not miss a change follows the feed and treats webhooks as the signal to read it sooner. See Sync a catalogue.
The building blocks
- Products, variants and offers. A product (
prod_…) has sellable variants (var_…). Each variant has offers (ofr_…): one vendor's price, stock and availability at one location. Offers change far more often than product content, so they have their own fast path and their own events. - Sources. A source (
src_…) is one connection to a vendor's data. Each pull is a run (run_…) that goes fetch, normalise, presence, master. - Events. Every change is an event (
evt_…) with a type such asoffer.changed, the version of the object after the change, and the fields that changed with their old and new values. See the event types. - Versions. Objects carry a
versionthat only grows. Apply a change only when its version is newer than the one you hold, and retries and reordering can never take you backwards.
How you build
- The REST API at
https://api.furniops.com, JSON over HTTPS, with dated versions in theFurniOps-Versionheader. - The TypeScript SDK,
@furniops/sdk: typed methods for every operation, retries, idempotency keys, pagination, webhook verification and the change stream, with no runtime dependencies. - The CLI,
furniops: sign in from a terminal, forward events to a local webhook handler without a tunnel, trigger test events and tail the stream.
Every account has a test mode: a sandbox catalogue, seeded with sample products, that test keys read and write instead of your live data.
Conventions at a glance
- Requests and responses are JSON with
snake_casefields. Errors are RFC 9457 problem details with a stablecode. - IDs are prefixed and opaque (
prod_034XqBaL2mRLTZPXyRbaUc). A wrong prefix, like another organisation's resource, answers404. - Money is an integer in minor units with its currency:
94900withusdis $949.00. - Timestamps are RFC 3339 in UTC.
- Lists use cursor pagination. Every
POSTtakes anIdempotency-Key. Updates that could overwrite someone else's change takeIf-Match. - Every response carries a
Request-Id; quote it to support, or find the request in your request logs. - Requests carry an API key or an OAuth access token as a bearer token.