Imports

A mass import turns a spreadsheet into passports in bulk. Upload a file, preview it to build a column mapping, start the import, then poll it, inspect the rows that failed, and retry them with corrections. One mass import is far kinder to rate limits than firing thousands of single-passport creates.

The import model

  • Name
    object
    Type
    string
    Description

    Always import.

  • Name
    id
    Type
    string
    Description

    Unique identifier, e.g. import_00a1b2c3d4e5f607.

  • Name
    target
    Type
    string
    Description

    The passport the import runs under — usually the ontology's root passport. Nullable.

  • Name
    status
    Type
    string
    Description

    pending, importing, complete, complete_with_errors, or failed. The last three are terminal.

  • Name
    file
    Type
    string
    Description

    The uploaded file being imported. Nullable.

  • Name
    levels
    Type
    array
    Description

    The mapping plan — one entry per phase, each pairing a level key with its column mapping. Nullable.

  • Name
    total_rows
    Type
    integer
    Description

    Data rows detected in the file.

  • Name
    processed_rows
    Type
    integer
    Description

    Rows imported so far.

  • Name
    failed_rows
    Type
    integer
    Description

    Rows that failed — validation plus infrastructure.

  • Name
    failed_validation_rows
    Type
    integer
    Description

    Rows rejected by validation.

  • Name
    failed_infra_rows
    Type
    integer
    Description

    Rows that hit a transient infrastructure error.

  • Name
    phases
    Type
    array
    Description

    Per-phase progress records for a multi-level import.

  • Name
    started_at
    Type
    string
    Description

    ISO 8601 timestamp when processing began. null while pending.

  • Name
    finished_at
    Type
    string
    Description

    ISO 8601 timestamp when the import reached a terminal status. null until then.

  • Name
    metadata
    Type
    object
    Description

    Caller-owned metadata bag, set at create time. Imports are immutable once started, so there is no update path. GET /v1/imports always reports {} here regardless of what the import carries — the list is served from an index with no metadata column. GET /v1/imports/{import} is truthful; do not reconcile against the list.

  • Name
    created_at
    Type
    string
    Description

    ISO 8601 timestamp of creation. Nullable.

The import row model

  • Name
    object
    Type
    string
    Description

    Always import_row.

  • Name
    id
    Type
    string
    Description

    Row id, shaped "{phase}#{zero-padded index}" — e.g. "0#000017".

  • Name
    status
    Type
    string
    Description

    done, failed_validation, failed_infra, or retrying.

  • Name
    row
    Type
    array
    Description

    The raw spreadsheet cell values for this row.

  • Name
    errors
    Type
    array
    Description

    Validation or infrastructure errors, or null when the row succeeded.

  • Name
    attempts
    Type
    integer
    Description

    How many times this row has been tried.

  • Name
    passport
    Type
    string
    Description

    The pass_… id created from this row once done, otherwise null.


POST/v1/imports

Start a mass import

Reads rows rows from an uploaded file, maps each spreadsheet column to an ontology property, and creates a passport per row under target. Build the mapping from the file preview, then poll the returned import until its status is terminal. Requires imports:write. Accepts an optional Idempotency-Key header.

Required attributes

  • Name
    file
    Type
    string
    Description

    The uploaded file's id (a file_… id).

  • Name
    target
    Type
    string
    Description

    The passport to import under — usually the ontology's root passport (a pass_… id).

  • Name
    rows
    Type
    integer
    Description

    Data row count from the file preview. Minimum 1, and never more than the file's size in bytes — a larger count is a stale-preview mistake and is rejected.

  • Name
    levels
    Type
    array
    Description

    At least one mapping phase. Each entry pairs a level key with a mapping of column index → property id (or the literal friendly_id). Mapping keys are 0-based column indexes given as strings; unmapped columns are ignored.

Request

POST
/v1/imports
curl https://api.synexcloud.com/v1/imports \
  -H "Authorization: Bearer $SYNEX_API_KEY" \
  -H "Idempotency-Key: units-2026-07-12" \
  -H "Content-Type: application/json" \
  -d '{
    "file": "file_9f2k7dq1w2e3r4t5",
    "target": "pass_00a1b2c3d4e5f607",
    "rows": 120,
    "levels": [
      { "level": "B", "mapping": { "0": "property_9f2k7d", "1": "friendly_id" } }
    ]
  }'

Response

{
  "object": "import",
  "id": "import_00a1b2c3d4e5f607",
  "target": "pass_00a1b2c3d4e5f607",
  "status": "pending",
  "file": "file_9f2k7dq1w2e3r4t5",
  "levels": [
    { "level": "B", "mapping": { "0": "property_9f2k7d", "1": "friendly_id" } }
  ],
  "total_rows": 120,
  "processed_rows": 0,
  "failed_rows": 0,
  "failed_validation_rows": 0,
  "failed_infra_rows": 0,
  "phases": [],
  "started_at": null,
  "finished_at": null,
  "created_at": "2026-07-12T09:31:00Z"
}

GET/v1/imports

List imports

Lists the team's imports, latest first. Returns a paginated list. Ontology-scoped API keys cannot use this team-wide list — fetch imports by id instead. Requires imports:read.

Optional attributes

  • Name
    created[gte]
    Type
    string
    Description

    Only imports created at or after this time. Unix seconds or an ISO date, inclusive of the whole second named.

  • Name
    created[lte]
    Type
    string
    Description

    Only imports created at or before this time. An inverted range is 400.

  • Name
    limit
    Type
    integer
    Description

    Page size, 1–100 (default 10).

  • Name
    cursor
    Type
    string
    Description

    A pagination cursor from a previous response's next_cursor.

The creation window runs as a SQL WHERE rather than a scan, so pages stay exact. Filters join the cursor's scope; see pagination.

Request

GET
/v1/imports
curl -G https://api.synexcloud.com/v1/imports \
  -H "Authorization: Bearer $SYNEX_API_KEY" \
  -d limit=10

Response

{
  "object": "list",
  "data": [
    {
      "object": "import",
      "id": "import_00a1b2c3d4e5f607",
      "target": "pass_00a1b2c3d4e5f607",
      "status": "complete_with_errors",
      "file": "file_9f2k7dq1w2e3r4t5",
      "levels": [
        { "level": "B", "mapping": { "0": "property_9f2k7d", "1": "friendly_id" } }
      ],
      "total_rows": 120,
      "processed_rows": 120,
      "failed_rows": 2,
      "failed_validation_rows": 1,
      "failed_infra_rows": 1,
      "phases": [],
      "started_at": "2026-07-12T09:31:05Z",
      "finished_at": "2026-07-12T09:33:40Z",
      "created_at": "2026-07-12T09:31:00Z"
    }
  ],
  "has_more": false,
  "next_cursor": null,
  "url": "/v1/imports"
}

GET/v1/imports/:id

Retrieve an import

Retrieves one import by id, with live progress counters. Poll it until status is complete, complete_with_errors, or failed. Requires imports:read.

Request

GET
/v1/imports/import_00a1b2c3d4e5f607
curl https://api.synexcloud.com/v1/imports/import_00a1b2c3d4e5f607 \
  -H "Authorization: Bearer $SYNEX_API_KEY"

Response

{
  "object": "import",
  "id": "import_00a1b2c3d4e5f607",
  "target": "pass_00a1b2c3d4e5f607",
  "status": "importing",
  "file": "file_9f2k7dq1w2e3r4t5",
  "levels": [
    { "level": "B", "mapping": { "0": "property_9f2k7d", "1": "friendly_id" } }
  ],
  "total_rows": 120,
  "processed_rows": 74,
  "failed_rows": 1,
  "failed_validation_rows": 1,
  "failed_infra_rows": 0,
  "phases": [],
  "started_at": "2026-07-12T09:31:05Z",
  "finished_at": null,
  "created_at": "2026-07-12T09:31:00Z"
}

GET/v1/imports/:id/rows

List an import's rows

Lists an import's per-row outcomes, so you can see exactly which rows failed and why. Filter with status; passing status=failed selects both validation and infrastructure failures. The response also carries header (the column labels) and mapping for rendering rows back to their columns. Returns a paginated list. Requires imports:read.

Optional attributes

  • Name
    status
    Type
    string
    Description

    Filter by outcome — failed (both failure kinds), done, failed_validation, failed_infra, or retrying.

  • Name
    cursor
    Type
    string
    Description

    A pagination cursor from a previous response's next_cursor.

Request

GET
/v1/imports/import_00a1b2c3d4e5f607/rows
curl -G https://api.synexcloud.com/v1/imports/import_00a1b2c3d4e5f607/rows \
  -H "Authorization: Bearer $SYNEX_API_KEY" \
  -d status=failed

Response

{
  "object": "list",
  "data": [
    {
      "object": "import_row",
      "id": "0#000017",
      "status": "failed_validation",
      "row": ["not-a-number", "unit-a17"],
      "errors": [
        { "column": 0, "code": "invalid_measurement", "message": "Expected a number." }
      ],
      "attempts": 1,
      "passport": null
    }
  ],
  "header": ["Capacity", "Alias"],
  "mapping": { "0": "property_9f2k7d", "1": "friendly_id" },
  "has_more": false,
  "next_cursor": null,
  "url": "/v1/imports/import_00a1b2c3d4e5f607/rows"
}

GET/v1/imports/:id/rows/export

Export failed rows

Returns the failed rows as text/csv, not JSON — the only operation in v1 that does. Requires imports:read. It is served as an attachment named {import_id}_failed_rows.csv.

The file holds both kinds of failure — rows rejected by validation and rows lost to an infrastructure error — one row each, laid out in the import's own column order, plus a trailing Errors column holding that row's failures as Property: message fragments joined by ; . You get the original cells and the reason side by side, which is the whole point: the sheet is repairable in place.

An import with no failed rows returns a header-only file — not a 404, and not an empty body. A consumer can treat "one line" as "nothing to fix" without special-casing an error status.

The byte-order mark

The file is UTF-8 with a BOM, deliberately. It exists to be opened in a spreadsheet, and Excel reads a BOM-less UTF-8 CSV as the local 8-bit codepage, mangling every non-ASCII character in it — an ontology with a °C unit or a supplier name carrying an accent comes out as mojibake for the very people the export is for.

The cost lands on programmatic consumers instead: strip the BOM before reading the first header cell, or your first column will not match by name. It is the single most common cause of a header lookup that mysteriously fails on column one only.

When to use it

If you are handling failures programmatically, use GET /v1/imports/{import}/rows instead — it returns the same rows as JSON, with no BOM and no CSV parsing in the way.

This endpoint exists because in practice the people who repair import failures work in a spreadsheet. Export the failures, fix the cells where they already live, then feed the corrections back through retry — the retry payload takes column index → corrected value, which maps directly onto the columns you just edited.

Request

GET
/v1/imports/import_8c2d5e1f9a4b7016/rows/export
curl https://api.synexcloud.com/v1/imports/import_8c2d5e1f9a4b7016/rows/export \
  -H "Authorization: Bearer $SYNEX_API_KEY" \
  -o failed_rows.csv

# Strip the BOM on the way in
sed '1s/^\xEF\xBB\xBF//' failed_rows.csv > clean.csv

Response

Capacity,Friendly ID,Errors
not-a-number,U-1,Capacity: must be a number
4600,,Friendly ID: is required

POST/v1/imports/:id/retry

Retry failed rows

Retries an import's failed rows, optionally with inline cell corrections. Supply rows — each entry pairs a row_id with a corrected_row that maps a column index to a fixed value — and/or scope: "infra_all" to re-run every infrastructure failure without listing them. Corrections are re-validated server-side first; rows that are still invalid come back in still_invalid with their errors and are not dispatched. Requires imports:write. Accepts an optional Idempotency-Key header.

Optional attributes

  • Name
    rows
    Type
    array
    Description

    Rows to retry. Each entry needs a row_id and may carry a corrected_row mapping column index → new cell value.

  • Name
    scope
    Type
    string
    Description

    Set to infra_all to retry every infrastructure failure at once.

Request

POST
/v1/imports/import_00a1b2c3d4e5f607/retry
curl https://api.synexcloud.com/v1/imports/import_00a1b2c3d4e5f607/retry \
  -H "Authorization: Bearer $SYNEX_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "rows": [
      { "row_id": "0#000017", "corrected_row": { "0": "4500" } }
    ]
  }'

Response

{
  "object": "import.retry",
  "import": "import_00a1b2c3d4e5f607",
  "dispatched": ["0#000017"],
  "still_invalid": [],
  "skipped": []
}

Was this page helpful?