Managing lines
Create, update, delete, and attach photos to inventory lines. For the line model and the merge rules these endpoints follow, see the Inventory overview.
Create lines
POST /v1/inventory adds between 1 and 1000 lines in one call. Each line names a productId (from GET /v1/products — send it as a number or a numeric string), a finish, a language, and a quantity, plus either a condition (raw cards) or graded details (graded cards). You can also attach a customId, a comment (a note buyers see on your listing), private notes, a location, tags, or a listing to publish the line to the Marketplace right away. location and tags are referenced by name and must already exist — see Tags & locations.
curl -X POST https://public-api.cardnexus.com/v1/inventory \
-H "Authorization: Bearer cnk_live_4f2d8c91e5b34a7f9e6c2d1a8b5f7e3c" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: 6a1d9f02-3c7e-4b18-9f2a-1e5c8d4b7a30" \
-d '{
"lines": [
{
"productId": 50212,
"finish": "Standard",
"condition": "NM",
"language": "en",
"quantity": 5,
"customId": "YRG|5555-5DS1-2EX-006-f-2-2008-08-01",
"comment": "From a sealed box, sleeved straight away",
"listing": { "price": { "amount": 42.50, "currency": "EUR" } }
},
{
"productId": 50213,
"finish": "Foil",
"language": "jp",
"quantity": 1
}
]
}'
Per-line results
Lines are processed one by one. Valid lines land in created; rejected lines are reported in errors, each with the index it had in the lines array you sent. The response is 200 even when some — or every — line was rejected, so check both fields.
{
"created": [
{
"id": "665f3a2b1c8d4e9f7a6b5c4d",
"customId": "YRG|5555-5DS1-2EX-006-f-2-2008-08-01",
"comment": "From a sealed box, sleeved straight away",
"productId": 50212,
"game": "ygo",
"finish": "Standard",
"condition": "NM",
"language": "en",
"quantity": 5,
"graded": null,
"forSale": true,
"listing": { "price": { "amount": 42.50, "currency": "EUR" } },
"updatedAt": "2026-06-10T09:15:31.000Z"
}
],
"errors": [
{
"index": 1,
"code": "INVALID_LANGUAGE",
"data": { "productId": 50213, "language": "jp" }
}
]
}
A line in created is the line as it now stands in your inventory — including the existing line your cards merged into, when a new line without a customId matched one of yours exactly (see How lines merge). In that case the existing line's quantity has grown and it comes back in created.
Per-line error codes
code |
Meaning |
|---|---|
PRODUCT_NOT_FOUND |
No catalogue product with this id. |
INVALID_LANGUAGE |
The product doesn't exist in this language. |
INVALID_FINISH |
The product doesn't exist in this finish. |
INVALID_QUANTITY |
Quantity must be a whole number of 1 or more. |
CONDITION_REQUIRED |
Raw cards need a condition. |
INVALID_IDENTITY |
A line takes either condition (raw cards) or graded (graded cards), not both. |
CUSTOM_ID_CONFLICT |
Another of your live lines — or another line in this same request — already uses this customId. |
When any line carries a listing, your seller account must be active (403 SELLER_ACCOUNT_NOT_ACTIVE) and every listing price must use your seller currency (422 CURRENCY_MISMATCH). These apply to the whole request, not a single line.
Update a line
PATCH /v1/inventory/{inventoryId} changes one line. Send only the fields you want to change: quantity, condition, language, finish, graded, customId, comment, notes, location, or tags. Setting a line's location and tags is covered in Tags & locations.
Quantity: set vs adjust
quantity takes one of two shapes:
{ "quantity": { "set": 8 } }
{ "quantity": { "adjust": -2 } }
set replaces the total. adjust adds (positive) or removes (negative) cards relative to the current quantity. Prefer adjust for concurrent updates: two pushes that each adjust by +3 and -1 settle on the right total regardless of order, whereas two set calls race and the last one wins. A change that would leave zero or fewer cards is rejected with 409 INSUFFICIENT_QUANTITY — use delete to remove a line.
{
"inventoryId": "665f3a2b1c8d4e9f7a6b5c4d",
"available": 5,
"requested": 8
}
Attribute changes
Change condition, language, finish, or grading the same way. To turn a graded line back into a raw card, send "graded": null and a condition in the same call. Set customId, comment, or notes to null to clear them, and location to null to move the line to no location.
If your changes make the line identical to another of your lines (same product, finish, condition, language, grading, and listing state, neither line carrying a customId), the two merge and the surviving line is returned as line.
Changing only part of a line
count applies the attribute changes to only some of the cards on the line. When count is lower than the line's quantity, the line splits: count cards take the changes and come back as line, the rest stays unchanged and comes back as remainder.
curl -X PATCH https://public-api.cardnexus.com/v1/inventory/665f3a2b1c8d4e9f7a6b5c4d \
-H "Authorization: Bearer cnk_live_4f2d8c91e5b34a7f9e6c2d1a8b5f7e3c" \
-H "Content-Type: application/json" \
-d '{
"count": 2,
"condition": "LP",
"customId": "YRG|5555-5DS1-2EX-006-f-2-2008-08-01-B"
}'
{
"line": {
"id": "665f3a2b1c8d4e9f7a6b5c52",
"customId": "YRG|5555-5DS1-2EX-006-f-2-2008-08-01-B",
"comment": "Minor whitening on the bottom edge",
"productId": 50212,
"game": "ygo",
"finish": "Standard",
"condition": "LP",
"language": "en",
"quantity": 2,
"graded": null,
"forSale": true,
"listing": { "price": { "amount": 42.50, "currency": "EUR" } },
"updatedAt": "2026-06-10T09:15:31.000Z"
},
"remainder": {
"id": "665f3a2b1c8d4e9f7a6b5c4d",
"customId": "YRG|5555-5DS1-2EX-006-f-2-2008-08-01",
"comment": "Minor whitening on the bottom edge",
"productId": 50212,
"game": "ygo",
"finish": "Standard",
"condition": "NM",
"language": "en",
"quantity": 3,
"graded": null,
"forSale": true,
"listing": { "price": { "amount": 42.50, "currency": "EUR" } },
"updatedAt": "2026-06-10T09:15:31.000Z"
}
}
The split-off part (line) inherits the original line's comment unless you send a new one, and never inherits its customId — send a customId to give the new part its own. count needs at least one attribute change and cannot be combined with quantity. When no split happens, remainder is null.
count outside 1…the line's quantity is rejected with 400 INVALID_COUNT. A customId already in use on another of your lines is rejected with 409 CONFLICT.
Delete a line
DELETE /v1/inventory/{inventoryId} removes a line entirely, whatever its quantity. If the line is on the Marketplace, its listing is cancelled with it. The line's customId, if it had one, becomes free for reuse.
{ "deleted": true }
A line id that isn't one of your live lines returns 404 NOT_FOUND.
Line photos
Buyers see photos on your Marketplace listing for a line. PUT /v1/inventory/{inventoryId}/media uploads them directly: send the request as multipart/form-data with each photo in the files field — between 1 and 10 images, any image/* content type, up to 10 MB each.
curl -X PUT https://public-api.cardnexus.com/v1/inventory/665f3a2b1c8d4e9f7a6b5c4d/media \
-H "Authorization: Bearer cnk_live_4f2d8c91e5b34a7f9e6c2d1a8b5f7e3c" \
-F "files=@front.jpg;type=image/jpeg" \
-F "files=@back.jpg;type=image/jpeg"
The call replaces the whole set of photos for the line — include every photo the line should keep. The response is the updated line. The endpoint returns 404 NOT_FOUND for a line that isn't yours; a file that cannot be read as an image is rejected with 400 BAD_REQUEST.
Related
- Inventory overview — the line model and merge rules
- Listings — put lines on the Marketplace
- Bulk operations — change many lines at once
- Webhooks —
inventory.quantity.changedfires on these edits