Import jobs
An Import Job ingests many products at once. Row failures are isolated — one bad row does not fail the batch — and you correct and re-submit against a generated template.
Lifecycle
POST /api/v2/import/jobs (multipart: file=CSV, UTF-8, ≤10 MB, magic-byte validated) → 202 { jobId }
GET /api/v2/import/jobs/{jobId} → status / preview
GET /api/v2/import/jobs/{jobId}/errors → row-level failures (isolated)
GET /api/v2/import/jobs/{jobId}/correction-template → fixable re-upload template
POST /api/v2/import/jobs/{jobId}/confirm → applyGet the right template first: GET /api/v2/schemas/categories/{category}/import-template?jurisdiction=EU renders the CSV columns from the category's effective schema — fill it in and upload it via POST /api/v2/import/jobs; the columns round-trip by construction. Also: POST /api/v2/import (single-shot CSV, ≤ 50 MB) and GET /api/v2/import/templates/{regulationCode} (same generator, keyed by regulation code). Re-submitting the same file is a no-op.
Machine on-ramp (PRD F2)
The JSON batch path TSC-style integrations use — no multipart, API-key auth:
POST /api/v2/ingest/products (scope: ingest:write)
{ "sourceSystem": "tsc-middleware",
"products": [ { "referenceId": "erp-4711", // REQUIRED — per-row idempotency key
"name": "EcoCell Battery Pack", // REQUIRED
"description": "…", "gtin": "…", // optional
"category": "Electronics", // optional display-name enum
"materials": [{ "name": "lithium", "percentage": 5.2 }],
"manufacturing": { "facility": "Gigafactory 1", "country": "DE" },
"customData": { "line": "A" } } ],
"callbackUrl": "https://integrator.example/hooks/ingest" } // optional
→ 202 { jobId }
GET /api/v2/ingest/{jobId} → job status / row outcomesThe item shape is the strict ERP-flavoured ingest schema (unknown keys rejected) — NOT the create-product shape. referenceId is the per-row identity: re-submitting the same rows does not duplicate products, and import.completed / import.failed webhook events close the loop.
POST /api/v2/import/aasx accepts a multipart .aasx (OPC/ZIP) package and creates a Draft product through the canonical create contract; XML-only payloads are refused honestly.