Listrune / Docs

API reference

The same API the dashboard uses, with one bearer key.

Available on Standard, Pro and Shop. Create a key in Settings in the dashboard; the secret is shown once. You can hold up to ten active keys at a time and revoke any of them without affecting the others.

Base URL and authentication

https://api.listrune.com/v1

Send the key as a bearer token on every request:

curl https://api.listrune.com/v1/status \
  -H "Authorization: Bearer lr_xxxxxxxx_xxxxxxxx"

A key is scoped to the organisation that created it and can only ever see that organisation's data. Two endpoints are deliberately closed to keys and need a signed-in session: managing API keys themselves, and connecting or disconnecting an eBay account.

Errors

StatusBodyMeaning
400{"error":{"formErrors":[],"fieldErrors":{…}}}The request body or query failed validation. The object names the fields.
401{"error":"unauthorized"}Missing or unrecognised key.
402{"error":"subscription_required"}No active subscription.
402{"error":"trial_over"}The Starter trial has ended.
402{"error":"scan_limit","scans":{…}}This month's AI photo scans are used up. The scans object carries used and limit.
403{"error":"api_plan_required"}The key is valid but the organisation is no longer on a plan that includes API access.
404{"error":"not_found"}No such record in your organisation.

There are no rate-limit or allowance headers. Read GET /v1/status for what is left.

Catalogue

GET /v1/games
Every supported game with its languages. Returns an array of { id, name, languages }.
GET /v1/sets
Query: game (required), lang (default en), q to filter by name or code, limit 1–1000 (default 500). Returns { count, sets }, newest release first.
GET /v1/cards/search
Query: game (required), lang, q, set, number, limit 1–50 (default 10). Returns { count, results } where each result is a printing with its set, rarity, finishes and external ids.
GET /v1/cards/{game}/{sourceId}
One printing. Query: lang.

Batches

GET /v1/batches
Every batch with its card count and value.
POST /v1/batches
Body: name (1–120 characters, required), note (≤2000), defaults — { game, lang, condition, finish, merge }, inherited by cards added to the batch. Returns 201.
GET /v1/batches/{id}
One batch.
GET /v1/batches/{id}/dashboard
Current estimated value of recorded batch cards, recorded 7–90 day third-party market-price history for comparable holdings, biggest movers and card/price activity. History begins with the first batch dashboard check; earlier prices are not reconstructed. The chart uses only batch quantities and Cardmarket/TCGplayer quotes, never eBay orders or eBay quotes.
POST /v1/batches/{id}/market-quotes/refresh
Refresh only Cardmarket/TCGplayer quotes for cards in a batch. Does not change asking prices or contact eBay.
PATCH /v1/batches/{id}
Body: any of name, status (open, exported, done), note, defaults.
DELETE /v1/batches/{id}
Returns 204. A batch holding cards needs ?cards=N matching the real count as confirmation, otherwise 409 batch_not_empty. A batch with cards live on eBay returns 409 live_on_ebay.

Inventory

GET /v1/inventory
Query: batchId to scope to one batch. Each item carries its printing, condition, finish, quantity, cost, quotes, ask price, photo, status and any issues.
POST /v1/inventory
Body: batchId, game, sourceId (all required), plus lang, condition, finish, quantity (default 1), costEur, price (default true), merge, scanId. Returns 201, or 200 with merged: true when it merged into an identical row already in the batch. Adding and pricing cards do not consume AI scan allowance.
PATCH /v1/inventory/{id}
Body: any of quantity, askEur, costEur, condition, finish, cardmarketId. Pass costEur: null or cardmarketId: null to clear them. If you change condition, finish or cost without setting askEur, the price is recalculated.
POST /v1/inventory/{id}/reprice
Reprice one card against the current rule. Costs no allowance.
POST /v1/inventory/{id}/photo
multipart/form-data with a single field named image — JPG, PNG or WebP, up to 15 MB. Replaces the listing photo.
DELETE /v1/inventory/{id}
Returns 204, or 409 live_on_ebay if the card is listed.
GET /v1/inventory/export.csv
Your own inventory as a plain CSV. Query: batchId. Never counts against allowance.

Pricing

GET /v1/pricing/rule
Returns { rule, default, fx } — your rule, the shipped default, and the conversion rates in use.
PUT /v1/pricing/rule
Partial update. Fields: anchor (one or two of cardmarket, tcgplayer, in order of preference), multiplier 0.1–5, minMargin 0–10, floorEur, conditionFactor (per condition, 0–5), rounding (psychological or cents).
DELETE /v1/pricing/rule
Back to the default.
POST /v1/pricing/preview
Body: marketEur (required), condition, costEur. Returns { askEur } without touching anything.
POST /v1/pricing/reprice-all
Body: batchId or itemIds; omit both for everything. Returns { repriced, failed, items }. Costs no allowance.

Listings and export

POST /v1/listings/check
Body: marketplace (ebay or cardmarket, required), plus batchId or itemIds. Returns what would be exported, what would be skipped and why, and any account-level blockers — missing eBay business policies, a disconnected account, a site the CSV template does not cover. Call this before exporting.
POST /v1/listings/preview
Same body. Returns just the listings that would go out.
POST /v1/listings/export
Same body. Returns the CSV itself, with the filename in Content-Disposition and the number of held-back rows in X-Listrune-Skipped. Given a batchId, it records the export and moves an open batch to exported.

Status

GET /v1/status
Everything about the account in one call: live games, price sources, marketplaces, plan, interval, trial state and usage.scansThisMonth against your AI scan allowance. This is where you check remaining scans before a bulk run.

A worked example

# 1. make a batch
curl -X POST https://api.listrune.com/v1/batches \
  -H "Authorization: Bearer $LR_KEY" -H "content-type: application/json" \
  -d '{"name":"Obsidian Flames ETB","defaults":{"game":"pokemon","lang":"de"}}'

# 2. find the printing
curl -G https://api.listrune.com/v1/cards/search \
  -H "Authorization: Bearer $LR_KEY" \
  --data-urlencode game=pokemon --data-urlencode lang=de \
  --data-urlencode "q=Glurak ex"

# 3. add it, priced
curl -X POST https://api.listrune.com/v1/inventory \
  -H "Authorization: Bearer $LR_KEY" -H "content-type: application/json" \
  -d '{"batchId":"…","game":"pokemon","sourceId":"…","lang":"de","condition":"NM"}'

# 4. see what would be held back
curl -X POST https://api.listrune.com/v1/listings/check \
  -H "Authorization: Bearer $LR_KEY" -H "content-type: application/json" \
  -d '{"marketplace":"ebay","batchId":"…"}'

# 5. take the file
curl -X POST https://api.listrune.com/v1/listings/export \
  -H "Authorization: Bearer $LR_KEY" -H "content-type: application/json" \
  -d '{"marketplace":"ebay","batchId":"…"}' -OJ