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, fromGET /v1/products. Required unless you supply acardmarketIdortcgplayerId.cardmarketId,tcgplayerId— a Cardmarket or TCGplayer product id, resolved to the catalogue product whenproductIdis absent. When a row has both aproductIdand a marketplace id, theproductIdwins. A marketplace id that matches no product fails that row withPRODUCT_NOT_FOUND.finish— the card's finish, e.g.Standard,Foil,Reverse Holo. Required.condition—NM(Near Mint),LP(Lightly Played),MP(Moderately Played),HP(Heavily Played), orDMG(Damaged). Required for raw cards; leave empty for graded cards.gradedGrade,gradedCertification,gradedGradingService— grading details for graded cards. A graded card needsgradedGradeandgradedGradingService;gradedCertificationmay 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 bycustomIdsets 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 (seeGET /v1/inventory/locations); an unknown name fails that row withLOCATION_NOT_FOUND.tags— the names of tags to attach to the line. Each must match one of your existing tags (seeGET /v1/inventory/tags); an unknown name fails that row withTAG_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.
- application/json
- application/json
- application/json
- application/json
- application/json
- application/json
- application/json
- application/json
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"
}
}