FurniOpsDocs

Runs

One pull of a source, from fetch to master records. Triggers and streams, the stages a run goes through, how it ends, the cells it could not read, waiting, replaying a snapshot, and starting a run yourself.

A run (run_…) is one pull of a source: FurniOps fetches what the source holds, reads it, notes what is missing, and updates your master records. A finished run never changes again; a failed one is retried by starting a new run.

{
  "object": "run",
  "id": "run_034XqBaL2mRLTZPXyRbaUe",
  "source": "src_034XqBaL2mRLTZPXyRbaUh",
  "trigger": "schedule",
  "stream": "catalogue",
  "status": "succeeded",
  "stage": "done",
  "stats": {
    "fetch.bytes": 482133,
    "normalise.products": 1204,
    "normalise.problems": 3,
    "presence.absent": 2,
    "master.changed": 41
  },
  "error": null,
  "waiting": null,
  "problems": [
    {
      "sheet": null,
      "line": 418,
      "column": "Width",
      "field": "width",
      "problem": "unparseable",
      "detail": "\"see notes\" is not a length"
    }
  ],
  "created_at": "2026-10-06T06:00:00Z",
  "started_at": "2026-10-06T06:00:02Z",
  "finished_at": "2026-10-06T06:01:37Z"
}

What starts a run

triggerStarted by
scheduleThe source's schedule.
manualA person or a key: POST /v1/sources/{id}/runs, or Run now on the source's page.
pushA file that arrived, such as an emailed attachment.
replayA replay of the current snapshot, after a mapping or rule change.

A run pulls one stream: the whole catalogue, or only stock (quantities and arrivals) for a connector that reads stock apart.

Stages

A run moves through four stages, each committed with its result, so a run that is retried resumes where it stopped:

stageWhat happens
fetchThe source is read, and what it sent is kept as a snapshot. A source that sent exactly what it sent last time ends here as unchanged.
normaliseRows are read through the source's mapping into products, variants and offers, cell by cell.
presenceWhat the source no longer lists is noted. Absence lowers a product step by step, never straight to discontinued, and a pull far smaller than usual is treated as a broken pull, not mass removal.
masterMaster records are updated, and each change becomes an event in the change feed.

stage is the next stage the run performs, and done once it has performed them all.

How it ends

statusMeaning
queued, runningStill in progress. A source has at most one such run.
succeededDone.
unchangedThe source sent what it sent last time; nothing to do.
needs_mappingThe file's headers are new: it waits for a person to confirm a mapping, then resumes.
failedIt stopped; error says why.
abortedFurniOps stopped it, such as a run that ran past its limit.

Errors

error.codeWhy the run failed
fetch_refusedThe URL was refused: a private address, or a scheme FurniOps will not fetch. The source is blocked at once.
fetch_failedThe source could not be reached.
source_errorIt answered with an error.
credentialsIt refused the stored credentials, or none are stored.
too_largeIts file was larger than the snapshot limit.
unreadableIts file could not be read.
emptyIts file was empty.
unsupportedFurniOps cannot fetch this kind of source yet.
no_snapshotA replay found no snapshot to process.
timed_outThe run took too long.
internalAn error on FurniOps' side. It never counts against the source's health.

error.message says what went wrong in FurniOps' words; the vendor's own answer is never echoed. Failures count toward the source's health.

Counters

stats holds counters by stage, such as fetch.bytes, normalise.products, normalise.problems, presence.absent and master.changed. Read them for trends; new counters may appear.

Problems

A cell FurniOps cannot use does not fail the run: the rest of its row is used, and the cell is recorded. problems keeps the first 100 in file order; stats["normalise.problems"] counts every one.

problemMeaning
missingEmpty, or a placeholder where a value was needed.
unparseableNot readable as the field's kind ("see notes" as a width).
ambiguousReadable more than one way.
implausibleOutside what the field can be.
conflictTwo columns gave one field different values.
no_keyThe row has no item number.

Each names its sheet (in a workbook), line, column, the field it maps to, and a detail. With AI agents in your plan, the triage agent explains a run's problems in plain words and says who can fix each.

Waiting

While an active run cannot work, waiting says why and until when:

waiting.reasonMeaning
rate_limitedThe source asked FurniOps to slow down.
retryingAn attempt failed in a way that may pass; the run tries again (attempt counts from 1).

Start a run

POST /v1/sources/{id}/runs queues a pull now, outside the schedule. The body is optional: { "stream": "stock" } pulls stock alone.

sources.ts
// Pull now, outside the schedule; then follow the run.
let run = await furniops.sources.createRun("src_034XqBaL2mRLTZPXyRbaUc");
while (run.status === "queued" || run.status === "running") {
  await new Promise((resolve) => setTimeout(resolve, 5_000));
  run = await furniops.runs.get(run.id);
}
console.log(run.status, run.stats, run.error);
for (const p of run.problems) console.log(p.line, p.column, p.problem, p.detail);
  • 409 while the source has a run queued or running, or is paused or disabled. A source runs one run at a time.
  • 422 for a source FurniOps cannot fetch yet, or a stock pull of a source whose connector does not read stock apart.
  • Starting a run is in the expensive rate class.
  • Runs count toward the source_runs meter. Once a month's live quota is spent, scheduled runs wait for the next month, and asking for a run, a replay or an upload's run answers 429 quota_exceeded. Test mode is never capped.

Replay

POST /v1/sources/{id}/replay processes the source's current snapshot again without fetching: after you change a mapping or category rules, so the change reaches records you already have. Only records whose result changed are written, at the time they were fetched, and absence is not counted. Confirming a mapping and saving category rules replay on their own.

It answers 409 like starting a run, and 422 when the source has no snapshot its records reflect yet.

In the dashboard

Sources › Runs lists every source's runs; a source's page lists its own latest runs. Opening a run shows its stages, counters, error and problems. Run now on a source's page starts a run; it is not offered for a push source, or while the source is paused or disabled.

On this page