For the complete documentation index, see llms.txt. This page is also available as Markdown.

Importing Components

Duro supports bulk-importing components from a spreadsheet through the GraphQL API. An import runs in two steps — you prepare an import to validate it, then start it to write the results — and you poll the resulting job for progress and per-row outcomes.

Required Headers

All import operations require the library headers:

curl 'https://api.durohub.com/graphql' \
  -H 'x-api-key: YOUR_API_KEY' \
  -H 'x-organization: @your-org' \
  -H 'x-library: @your-org/your-library' \
  -H 'Content-Type: application/json' \
  -d '{"query": "..."}'

The Import Workflow

Imports live under the componentImport namespace on both Query and Mutation.

1. Prepare (validate)

prepare parses and validates your rows and returns a PreparedImportOutput describing what would happen — how many components would be created, how many rows are valid, and any validation errors. Nothing is written to the library at this stage.

mutation PrepareImport {
  componentImport {
    prepare(input: {
      libraryId: "library-uuid"
      fileId: "uploaded-file-uuid"
      keyColumn: CPN
    }) {
      id
      status
      totalComponents
      validCount
      errorCount
      newComponentCount
      linkedToExistingCount
      errors {
        rowNumber
        field
        code
        message
      }
    }
  }
}

The keyColumn (NAME, EID, or CPN) selects the identifier column used to match import rows to existing components for update mode. A row whose value resolves to exactly one live component is treated as an update of that component; otherwise it is a create.

Column mappings

prepare accepts an optional list of ColumnMappingInputs telling Duro which spreadsheet column feeds which field. Each mapping pairs a columnIndex (or column header) with a targetField. Besides the plain component fields, targetField supports prefixed families — attr: for custom attributes, hierarchy: for category hierarchy values, rel: for relationships, and src: for sourcing.

Sourcing (src:) targets

Map a column to a src: target to bring a component's source — its manufacturer part and the quote for it — in on the same row as the component itself:

targetField

Maps to

src:manufacturer

Manufacturer name for the source

src:mpn

Manufacturer part number

src:mfrDescription

Description on the manufacturer part

src:datasheet

Datasheet URL for the manufacturer part

src:distributor

Distributor name for the quote

src:dpn

Distributor part number

src:distDescription

Description on the quote

src:packageType

Package type on the quote (for example Tape & Reel)

src:packageQuantity

Units per package on the quote

src:minQuantity

Minimum order quantity on the quote

src:unitPrice

Price per unit

src:leadTime

Lead time for the quote

A few things to know about the sourcing columns:

  • Values are carried through as written. "$1.00" and "1 Day" are kept as the text you supplied rather than normalized at mapping time, so failure reports can echo back exactly what was in the cell.

  • Manufacturer, distributor, and package values stay as names. They are resolved to sourcing records later, when the import is applied.

  • A row with every sourcing cell blank yields no source. It is treated as a component-only row, not as an empty source.

  • One source per component row. Additional sources on continuation rows are not supported; each row carries at most one source.

src: mappings travel through the same prepare/start flow as the rest of the import: prepare parses them alongside the component columns and reports any row errors, and start records the parsed sourcing rows as part of the job it creates.

Descriptions, datasheets, and package types

The four descriptive sourcing targets have behavior worth knowing before you build a sheet around them:

  • Descriptions are length-limited, and over-long values are refused. src:mfrDescription and src:distDescription are held to the same length limit as the sourcing API's own description fields. A cell that exceeds it fails its row rather than being silently truncated — a half-stored note is a worse outcome than a rejected one.

  • src:datasheet must be an absolute URL. The value is validated the same way the API validates a datasheet URL elsewhere, including requiring a protocol: https://example.com/ds.pdf is accepted, a bare example.com/ds.pdf is not. When the manufacturer part is created, the URL becomes a DATASHEET document linked to that part, committed together with it.

  • src:packageType is a lookup, never a create. Unlike manufacturer and distributor names — which are your own data and are created on demand — package types come from a fixed, shared list. The name is matched case-insensitively; a name Duro does not recognize fails only that row, and the error lists the valid spellings (the usual culprit is punctuation, such as Tape and Reel for Tape & Reel). A name that matches two package types differing only by case is refused rather than guessed at.

  • Package types resolve before anything is written. An unrecognized package type fails its row without having created a manufacturer part first.

Manufacturer parts are create-only today. When a row's manufacturer and MPN match a manufacturer part that already exists, that part is reused as-is, so src:mfrDescription and src:datasheet take effect only on the row that first creates the part. Quote fields, including src:distDescription and src:packageType, are applied to the matched quote.

2. Start (execute)

Pass the id from the prepared import to start. This begins an ImportJob that stages and promotes the rows in a single transaction.

3. Poll the job

Poll componentImport.jobStatus until the job reaches a terminal state. Per-row results are available on terminal-state jobs.

An ImportJob moves through these statuses:

Status
Meaning

PARSING

Reading the source rows

STAGING_COMPONENTS

Writing components to the transaction

STAGING_LINKS

Writing assembly links to the transaction

PROMOTING

Committing the staged changes

COMPLETED

Every row was written successfully

ROLLING_BACK

A failure was hit; the transaction is being reverted

FAILED

The import was rejected; nothing was written

CANCELLING / CANCELLED

The import was cancelled before completion


Sourcing columns (src: targets)

A spreadsheet column can be mapped to a component field, to a library attribute (attr:<attribute-id>), or to a sourcing target using the src: prefix. Sourcing targets write the manufacturer part and distributor quote for the row's component instead of a field on the component itself — see Sourcing for the underlying model.

Target
Writes to
Notes

src:manufacturer

Manufacturer name

Identifies the manufacturer part together with src:mpn

src:mpn

Manufacturer part number

src:mfrDescription

Manufacturer part description

src:datasheet

Manufacturer part datasheet URL

src:distributor

Distributor name

Identifies the quote together with src:dpn

src:dpn

Distributor part number

src:distDescription

Quote description

src:packageType

Quote package type

Resolved by name — see below

src:packageQuantity

Quote package quantity

src:minQuantity

Quote minimum order quantity

src:unitPrice

Quote unit price

src:leadTime

Quote lead time

Only the targets in this list are recognized. Mapping a column to an unknown src: target is rejected when you prepare the import.

Package type resolution

src:packageType carries a human-readable package name (for example 0402 or SOIC-8), which is resolved against the package types Duro knows about. A value that matches nothing, or that matches more than one package type, fails with a dedicated error code — see Sourcing import errors.

Sourcing values are not validated when you prepare the import; the component rows are. Sourcing is applied after the components themselves are written, so a sourcing failure does not roll back the component import — check the job's row errors to see which sourcing values were rejected.


Atomic behavior (all-or-nothing)

Every import — create-only, update, or mixed — runs in a single transaction. Any error on any row (a create, an update, an assembly link, or a BOM reference) rolls back the whole import. On a rejected import nothing is written to your library, and no row is reported as CREATED or UPDATED.

This matters because import inserts components and links them as separate steps. Without atomicity, a parent row could fail while its children succeed, leaving orphaned children or a structurally broken BOM. All-or-nothing guarantees your library is never left in an incoherent state, and gives one predictable contract across create, update, and mixed sheets.

When an import is rejected, fix the offending row(s) reported in rowResults, then re-upload the sheet once — the rows that came back as NOT_IMPORTED were not partially applied and are safe to import again.


Row Outcomes

Each row's outcome is an ImportRowOutcome:

Outcome
Meaning

CREATED

A new component was created from this row

UPDATED

A matched component was updated because its data changed

UNCHANGED

The row equalled the existing component; a suppressed no-op

SKIPPED_DUPLICATE

The row duplicated another row in the same import and was skipped

FAILED_VALIDATION

The row failed validation (see errors)

FAILED_PROMOTION

The row was valid but failed while being committed (see errors)

NOT_IMPORTED

The row was otherwise valid but the import was rejected because another row failed, so it was rolled back and never written

CREATED, UPDATED, and UNCHANGED only appear when the whole job reaches COMPLETED. On a rejected import, the failing row(s) carry FAILED_VALIDATION or FAILED_PROMOTION and every other row carries NOT_IMPORTED.

Results Summary

rowResultsSummary (ImportRowResultsSummary) reports counts by outcome across the whole job. Every field is a non-null Int:

Field
Meaning

total

Total rows in the import

created

Rows that created a new component

updated

Rows that updated an existing component

unchanged

Matched rows that were no-ops

skippedDuplicate

Rows skipped as duplicates within the import

failedValidation

Rows that failed validation

failedPromotion

Rows that failed while being committed

notImported

Otherwise-valid rows that were rolled back because the import was rejected

Example: a rejected import

One bad row rejects the whole import. Here row 2 failed validation, and the remaining valid rows are reported as notImported rather than created:

Because created is 0 and status is FAILED, no component was written — including row 1 and row 3, which validated fine. Fix row 2 and re-upload.


Next Steps

Last updated

Was this helpful?