FurniOpsDocs

Connectors

The vendor data FurniOps reads today beyond files. A Shopify storefront's public feed, and Coaster's dealer API with its separate stock stream. Setup, schedules, credentials and the limits each one keeps.

Besides files, FurniOps reads two kinds of vendor data today: a Shopify storefront's public product feed, and Coaster's dealer API. Each comes with a built-in mapping, so its runs never wait for one.

Shopify storefront feed

A platform_feed source with platform: "shopify" reads a store's public /products.json.

sources.ts
// A storefront's public Shopify feed: retailer prices unless you say otherwise.
await furniops.sources.create({
  name: "Acme storefront",
  kind: "platform_feed",
  config: { url: "https://shop.vendor.example", platform: "shopify" },
  schedule: { interval_minutes: 1440 },
  licence_basis: "public_data",
});
  • What it reads. Every page of the feed, 250 products a page, from the first page to the first empty one, as one snapshot per run.
  • Politely. One request at a time per store. A 429, or Shopify's own 430, waits for its Retry-After and asks again.
  • Only what changed. Each page's ETag is kept. The next run sends them back, and when every page answers 304 Not Modified the run ends unchanged. When one page changed, every page is read again, since a product added or removed shifts every page after it.
  • Within Shopify's cap. Shopify refuses pages beyond 25,000 products (page × page size); a store larger than that fails its runs rather than import part of its catalogue.
  • Prices. A storefront shows what a shopper pays: the source's role is retailer unless you set supplier.

No credentials are needed. A store that hides its feed (a password page, a bot challenge) cannot be read this way: a probe tells you before you add it.

Coaster dealer API

An api source with connector: "coaster" reads Coaster's dealer API with your organisation's own Coaster account (licence_basis: "tenant_account").

sources.ts
// Coaster's dealer API: the catalogue once a day, stock every 30 minutes.
const coaster = await furniops.sources.create({
  name: "Coaster dealer API",
  kind: "api",
  connector: "coaster",
  config: { warehouse: "TX" },
  schedule: { interval_minutes: 1440, stock_interval_minutes: 30 },
  licence_basis: "tenant_account",
});
// Write-only: sealed as it arrives, never returned. The source shows has_credentials: true.
await furniops.sources.setCredentials(coaster.id, { values: { api_key: "…" } });
const test = await furniops.sources.test(coaster.id);
console.log(test.ok, test.http_status, test.detail);
Credentialsapi_key: your Coaster API key. Sent only in the header Coaster asks for, over HTTPS, and never in a URL, a log or an error.
config.warehouseThe warehouse whose stock to read. Unset: your account's default ship-to warehouse.
config.price_codeThe price list to read. Unset: your account's own.
Streamscatalogue and stock, on one source.

Two streams. A catalogue run reads the whole account: taxonomy, every product, product information, prices and inventory. A stock run reads inventory only and lays it over the catalogue the source already has, so only offers move; unchanged stock ends unchanged.

  • Coaster allows one catalogue pull a day, after midnight. With a schedule, the source's catalogue runs fall due after midnight Pacific time, not an interval after the last.
  • schedule.stock_interval_minutes sets the stock runs: every 15 minutes at the most often, once a day at the least. Without it there are no scheduled stock runs.
  • Start one stream by hand with POST /v1/sources/{id}/runs and { "stream": "stock" } (catalogue when the body is empty).

Failures. A key Coaster refuses fails the run as credentials at once, never retried, in FurniOps' own words (Coaster's answer can echo the key). Timeouts, network errors, 429 and 5xx answers are retried with a backoff.

Test the key before the first run with POST /v1/sources/{id}/test: the connector signs in with the stored credentials and reports what Coaster answered.

Other platforms

platform_feed sources for WooCommerce and BigCommerce, and the structured_page, browser and push kinds, are accepted but cannot run yet. A probe that finds such a site still reports its platform, its structured data and the effort to read it.

On this page