FurniOpsDocs

Mappings

How a file's columns become product, variant and offer fields. FurniOps proposes a mapping for every new set of headers, a person confirms it once, and every later file with those headers imports on its own. Fields, settings, tiers and confirming through the API.

Every vendor names its columns its own way: Item #, Vendor SKU, W (in), Dealer Cost. A mapping (map_…) says which canonical field each column fills and how its values are read.

  • A mapping belongs to one source and one set of headers. A file whose headers change gets a new mapping; a source keeps one per header set it has seen.
  • For a new header set FurniOps proposes a mapping, and the run stops as needs_mapping until a person confirms it. That happens once: every later file with the same headers imports without asking.
  • Shopify feeds and Coaster use FurniOps' built-in mapping and never wait for one.

How FurniOps proposes

Each column is placed from the most specific evidence there is. The column's tier says which:

tierWhere it came from
built_inA platform's or connector's fixed mapping.
learnedWhat a person chose for the same header on another of your sources.
templateFurniOps' own template column names (sku, width_in).
synonymFurniOps' dictionary of the names vendors use.
personA person confirming this mapping.
agentAn AI agent's proposal, applied without a person under auto_low_risk. Never learned for other sources.

Units and currency are read from the header (W (in), Price (EUR)), and the decimal style from the column's own values. Columns FurniOps could not place are listed in unmapped with the reason, and are not imported unless you map them. With AI agents in your plan, the column repair agent can propose fields for them.

Review and confirm

GET /v1/sources/{id}/mappings lists the source's mappings, newest first; a waiting run waits for the one whose status is proposed. Each shows the headers in file order, the first 5 rows as samples, the mapped columns and the unmapped ones.

POST /v1/mappings/{id}/confirm confirms it. Send no body to confirm the proposal as it is, or send the final columns: every column you want imported, since columns left out are not.

sources.ts
// A run stopped as needs_mapping waits for the source's proposed mapping.
const mappings = await furniops.sources.listMappings("src_034XqBaL2mRLTZPXyRbaUc");
const proposed = mappings.data.find((m) => m.status === "proposed");
if (proposed !== undefined) {
  console.log(proposed.columns, proposed.unmapped);
  // Confirm it as proposed, or send the final columns: those left out are not imported.
  const confirmed = await furniops.mappings.confirm(proposed.id, {
    columns: [
      ...proposed.columns.map(({ column, prefix, field, settings }) => ({
        column,
        field,
        settings,
        ...(prefix === undefined ? {} : { prefix }),
      })),
      { column: "Seat Ht (in)", field: "seat_height", settings: { unit: "in" } },
    ],
  });
  console.log(confirmed.run?.id); // the waiting file resumes
}

Confirming applies the mapping at once: the file waiting in needs_mapping resumes, or, for a mapping confirmed again with changes, the source's current snapshot is replayed. The answer holds the mapping and that run.

It answers 422 when a column is not one of the headers, a column is mapped twice, a field that takes one column is given two, or a setting does not fit its field; and 409 while the source has a run under way or is paused or disabled. Then nothing is confirmed.

A column

{
  "column": "Seat Ht (in)",
  "field": "seat_height",
  "settings": { "unit": "in" },
  "tier": "person"
}
PropertyMeaning
columnThe header as the file writes it, or a JSON or XML record's flattened path.
prefixtrue: the mapping covers every column that starts with column (options. for options.Size, options.Colour).
fieldThe canonical field it fills (below).
settingsHow its values are read (below).
tierWhere the mapping came from (above). Not sent when you confirm.

Settings

SettingForMeaning
unitLengths, dimensions, rug sizes, weights, cartonsThe column's unit: mm, cm, m, in or ft for lengths and cartons' sizes; g, kg, oz or lb for weights.
styleNumbers and moneyThe decimal separator: dot (1,299.00) or comma (1.299,00).
currencyMoneyThe column's currency, when it differs from the source's.
separatorLists, cartonsWhat separates a list's items (or cartons) in one cell; a vertical bar when unset. Never ; for cartons.
axisaxisThe variant axis the column names (finish, size).
htmlTextThe column holds HTML: it is read as plain text.

Fields

Every field a column can fill, with the level it belongs to and the kind of value it holds. A repeatable field takes several columns: each adds to the list, or names its own axis.

FieldLevelValueColumns
groupProducttextOne
titleProducttextOne
brandProducttextOne
collectionProducttextOne
descriptionProducttextOne
categoryProductlistSeveral
featuresProductlistSeveral
tagsProductlistSeveral
country_of_originProductcountryOne
tsca_title_viProductbooleanOne
ca_tb117_2013ProductbooleanOne
prop65_warningProductbooleanOne
product_imagesProducturl_listSeveral
variant_keyVarianttextOne
skuVarianttextOne
gtinVariantgtinOne
mpnVarianttextOne
variant_titleVarianttextOne
axisVarianttextSeveral
colourVarianttextOne
finishVarianttextOne
materialsVariantlistSeveral
dimensionsVariantdimensionsOne
widthVariantlengthOne
depthVariantlengthOne
heightVariantlengthOne
diameterVariantlengthOne
seat_heightVariantlengthOne
seat_depthVariantlengthOne
arm_heightVariantlengthOne
weightVariantweightOne
assembly_requiredVariantbooleanOne
white_gloveVariantbooleanOne
freight_classVarianttextOne
rug_sizeVariantrug_sizeOne
discontinuedVariantbooleanOne
replacement_skuVarianttextOne
imagesVarianturl_listSeveral
cartonsVariantcartonsSeveral
locationOffertextOne
costOffermoneyOne
msrpOffermoneyOne
mapOffermoneyOne
priceOffermoneyOne
compare_atOffermoneyOne
quantityOfferintegerOne
incomingOfferintegerOne
availabilityOfferavailabilityOne
lead_time_daysOfferintegerOne

A variant's shipping boxes go in cartons: several boxes in one cell, each with its size, weight and count. Cartons describes how to write them.

When a cell cannot be read

A cell FurniOps cannot use does not stop the run: the rest of its row is imported, and the run records the cell as a problem, with its line, column, field and why.

On this page