Skip to main content
POST
Open a retailer catalog import job

Authorizations

X-API-Key
string
header
required

Body

application/json

Flags for one catalog import run.

source
enum<string>
required

Catalog source this run merges under. One of: sephora_catalog, ulta_catalog. Not free text — the source decides the canonical retailer, its storefront, and the measured per-field confidence table that resolves every contested field, so an unregistered value is rejected with 422 rather than guessed at. The registered set is asserted against the engine's own registry in the C-5966 tests.

Available options:
ulta_catalog,
sephora_catalog
source_file
string
default:""

Name of the feed drop these rows came from. Recorded as listing provenance, so a listing can be traced to the file it came from.

Maximum string length: 255
fetched_at
string<date-time> | null

When the feed drop was fetched — provenance about the data, not the run. Send the drop's own timestamp; omitting it stamps the run's start time, which misdates a feed imported weeks after it was published.

dry_run
boolean
default:true

Run the real merge and roll back each batch. Default. The counts are directly comparable with a committed run's, so this is a real rehearsal rather than an estimate. Note that quarantine rows roll back too and are reported from the run's in-memory record instead.

reclaim_unattributed
boolean
default:true

Allow this run to claim fields on products that carry no recorded provenance — rows from the pre-C-4096 importers, which overwrote rather than enriched and left no field_sources. Restricted to products still marked imported/seeded, so a brand-claimed product or one sourced from a crawl is never touched. On by default (C-5960); a dry run reports exactly how many fields it would claim, and the flag can still be set to false for a specific run.

skip_ingredients
boolean
default:false

Skip ingredient-list parsing, the slowest part of a run.

batch_size
integer
default:500

Rows per transaction window inside the engine. Each window costs a fixed handful of queries regardless of size, so the default rarely needs changing. It is also the unit a run resumes from after an interruption, so a smaller window loses less work and costs more checkpoint writes.

Required range: 1 <= x <= 5000
chunk_rows
integer | null

Staged rows merged by one background chunk task. The run is a sequential chain of these. Omit it and the size is chosen from dry_run: 10,000 for a dry run, 2,000 for a commit. The two modes are not the same amount of work per row — a commit writes every row and parses every ingredient label inline, measured at 14-25 rows/s against a dry run's ~103 — and sizing both from the dry run is what killed the first full-feed commit run. Send a value only if you have measured your own throughput; the maximum is 12,000.

Required range: 1 <= x <= 12000

Response

OK

A job's current state. The same shape from open, append, start and poll.

job_id
string<shortuuid>
required

Identifier of the job. Use it on the row, start and poll calls.

Required string length: 22
Pattern: ^[23456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz]{22}$
status
string
required

staging — accepting rows; the run has not started. queued — start accepted, waiting for a worker. running — the merge is executing; chunks_done and result advance as it goes. completed — finished; result carries the whole feed's census. failed — the run gave up; error says why, result carries the census of the work that did finish, and POST .../start resumes from where it stopped.

source
string
required

Catalog source this run merges under.

dry_run
boolean
required

Whether this run rolls back each batch.

reclaim_unattributed
boolean
required

Whether this run may claim unattributed fields.

staged_rows
integer
required

Rows accepted into the job so far.

Required range: x >= 0
chunk_rows
integer
required

Staged rows merged by one chunk task. The run is a sequential chain of these, so no single task approaches the worker's time limit. Set at open time from dry_run unless you named one: 10,000 for a dry run, 2,000 for a commit, because a commit does an order of magnitude more work per row.

Required range: x >= 1
chunks_total
integer
required

Chunks this job's staged rows divide into. Zero until rows are staged.

Required range: x >= 0
chunks_done
integer
required

Chunks fully merged and recorded. A resumed run continues from here, so these rows are never merged twice.

Required range: x >= 0
processed_rows
integer
required

Staged rows already merged. A floor, not an estimate: rows counted here are recorded and survive a restart. It advances within a chunk as well as between chunks — a chunk checkpoints every batch_size rows — so it keeps moving during the minutes a commit chunk takes, and is the field to watch to tell a slow run from a stopped one.

Required range: x >= 0
poll_url
string
required

Path to poll for this job's status and result.

source_file
string
default:""

Feed drop name recorded as listing provenance.

started_at
string<date-time> | null

When the run began. Null before it starts.

completed_at
string<date-time> | null

When the run reached a terminal state.

error
string | null

Why the run failed. Null unless status is failed.

result
Result · object

The engine's census. Empty until the first chunk finishes, then the running total for the chunks merged so far, and the whole feed's figures once status is completed — so read status, not this field, to decide whether a run is done. Carries rows_read, products_created / products_enriched / products_unchanged, listings_created / listings_updated, dual_listed (products another retailer's feed had already created — the cross-retailer overlap), duplicate_gtins_in_feed, quarantined with quarantine_reasons, brand and ingredient counts, field_decisions (per field, how each value was decided), reclaimable_fields, and quarantine — the refused rows themselves, capped at 500 entries with quarantined remaining the true total. errors is capped the same way, with errors_total as its true count. census is the same figures as human-readable lines.