Start a bulk import

Imports inventory lines from a file. Send the request as multipart/form-data with the file in the file field and its content type — text/csv, application/json, or application/gzip; mode and format are sent as plain form fields alongside it. Files up to 256 MB are accepted; larger uploads are rejected with PAYLOAD_TOO_LARGE, other content types with UNSUPPORTED_CONTENT_TYPE. When the file is gzip-compressed, format must say whether it holds json or csv.

The import runs in the background: this call returns a job right away, and you poll GET /v1/inventory/bulk/jobs/{jobId} for progress and results. Files produced by POST /v1/inventory/bulk/export use the same layout, so an export can be edited and imported back unchanged.

File contents

A JSON file is a top-level array of row objects. A CSV file starts with a header row; columns are matched by name, in any order, and columns a row doesn't need can be left out entirely. Unknown columns are ignored. The full column set:

productId,cardmarketId,tcgplayerId,finish,condition,gradedGrade,gradedCertification,gradedGradingService,language,quantity,customId,comment,notes,location,tags,listingPrice,listingCurrency

In JSON, the three graded* columns are a single graded object with grade, certification, and gradingService fields, tags is an array of names, and omitted fields are left out of the row object. In CSV, tags is a single cell of comma-separated names (Trade binder, Graded pile). Files may be gzip-compressed. A file can hold up to 5,000,000 rows and 256 MB of data (after decompression).

Each row describes one inventory line:

  • productId — the catalogue product's numeric id, from GET /v1/products. Required unless you supply a cardmarketId or tcgplayerId.
  • cardmarketId, tcgplayerId — a Cardmarket or TCGplayer product id, resolved to the catalogue product when productId is absent. When a row has both a productId and a marketplace id, the productId wins. A marketplace id that matches no product fails that row with PRODUCT_NOT_FOUND.
  • finish — the card's finish, e.g. Standard, Foil, Reverse Holo. Required.
  • conditionNM (Near Mint), LP (Lightly Played), MP (Moderately Played), HP (Heavily Played), or DMG (Damaged). Required for raw cards; leave empty for graded cards.
  • gradedGrade, gradedCertification, gradedGradingService — grading details for graded cards. A graded card needs gradedGrade and gradedGradingService; gradedCertification may be left empty when you do not have the certification number. Leave all three empty for raw cards.
  • language — the card's language as a two-letter code, e.g. en. Required.
  • quantity — the line's total quantity, a whole number of 0 or more. Required. This is an absolute count, not an increment: a row that matches an existing line by customId sets that line to this quantity.
  • customId — your own stable identifier for the line, unique across your live lines.
  • comment — free-text note for the line, shown to buyers on your Marketplace listing.
  • notes — private note for the line, visible only to you.
  • location — the name of a location to put the line in. Must match one of your existing locations (see GET /v1/inventory/locations); an unknown name fails that row with LOCATION_NOT_FOUND.
  • tags — the names of tags to attach to the line. Each must match one of your existing tags (see GET /v1/inventory/tags); an unknown name fails that row with TAG_NOT_FOUND.
  • listingPrice, listingCurrency — publish the line to the Marketplace at this per-card price, in decimal major units (19.99). Either both or neither.

How rows apply

Rows carrying a customId that matches one of your live lines update that line to the row's state — quantity, attributes, and listing. Fields the row leaves empty (comment, notes, location, tags, the listing pair) keep the line's current value. Rows whose customId matches nothing create a new line. tags and location are referenced by name and must already exist; importing does not create labels.

Rows without a customId are additive: the quantity merges into an existing line with the same product, finish, condition, language, and grading, or creates one.

With mode: "replace", every live line the file does not mention is set to a quantity of zero after all rows are applied.

A row that fails — unknown product, invalid value — does not stop the import. Failed rows are collected into a JSON error report, linked from the job's errorReportUrl when it completes.

Send an Idempotency-Key header to make retries safe: the same key returns the same response for 24 hours.

Requires the inventory:write scope.

Body
required
application/json
Responses
  • application/json
  • application/json
  • application/json
  • application/json
  • application/json
  • application/json
  • application/json
  • application/json
Request Example for post/inventory/bulk/import
curl https://public-api.cardnexus.com/v1/inventory/bulk/import \
  --request POST \
  --header 'Content-Type: multipart/form-data' \
  --header 'Authorization: Bearer YOUR_SECRET_TOKEN' \
  --form 'file=' \
  --form 'mode=upsert' \
  --form 'format=json'
{
  "job": {
    "id": "6848a3f0c8d4e9f7a6b5c4e1",
    "kind": "import",
    "status": "pending",
    "format": "csv",
    "mode": "upsert",
    "counts": null,
    "progress": 0,
    "errorMessage": null,
    "downloadUrl": null,
    "errorReportUrl": null,
    "expiresAt": null,
    "createdAt": "2026-06-10T09:20:45.000Z"
  }
}