API reference

A small REST API for inventory software. Everything a seller can do in the portal, their software can do here: push listings, pull orders, mark them shipped, decide returns. JSON in, JSON out. Base URL: https://sellers.booklaan.com/api/v1

Authentication

Create a key under API & webhooks (Professional and Volume plans). Send it as a bearer token. Keys are shown once; we store only a hash.

curl https://sellers.booklaan.com/api/v1/account \
  -H "Authorization: Bearer sk_booklaan_…"

Listings

Listings are matched by your sku. The same body creates or updates. Up to 500 listings per request; each row succeeds or fails on its own.

POST/listings
{
  "listings": [{
    "sku": "BP-10021",
    "department": "BOOKS",          // BOOKS TEXTBOOKS COMICS MAGAZINES MUSIC MOVIES GAMES
    "genre": "Science Fiction & Fantasy",
    "title": "The Left Hand of Darkness",
    "creator": "Le Guin, Ursula K.",
    "binding": "Paperback",
    "publisher": "Ace", "year": 1969, "identifier": "9780441478125",
    "gradeScale": "STANDARD",       // or COLLECTIBLE
    "condition": "Very Good",       // STANDARD: New, Like New, Very Good, Good, Acceptable
                                    // COLLECTIBLE: Fine, Near Fine, Very Good, Good, Fair, Poor
    "signed": false, "firstEdition": false,
    "description": "Ace paperback, light spine lean, clean pages.",
    "price": 12.50, "quantity": 1, "weightOz": 8,
    "photos": ["https://…/front.jpg"],
    "status": "ACTIVE"              // optional: DRAFT | ACTIVE | ENDED
  }]
}

→ { "results": [{ "sku": "BP-10021", "id": "…", "status": "ACTIVE", "created": true }] }
GET/listings?status=ACTIVE&updated_since=2026-11-01T00:00:00Z&page=1&per_page=100

Paginated list of your listings. status is optional (DRAFT, ACTIVE, SOLD, ENDED).

GET/listings/{sku}

One listing.

PATCH/listings/{sku}

Partial update — send only the fields that change, e.g. { "price": 11.00, "quantity": 2 }. Quantity 0 marks the listing sold.

DELETE/listings/{sku}

Ends the listing (kept for order history).

Orders

Poll, or subscribe to the order.created webhook. Each order is from one buyer to you; a buyer’s multi-seller cart becomes several orders.

GET/orders?status=NEW&since=2026-11-01T00:00:00Z
{ "orders": [{
  "id": "ST-284771", "status": "NEW", "placedAt": "…", "shipBy": "…",
  "shipTo": { "name": "Jordan Park", "line1": "…", "city": "Chicago", "state": "IL", "zip": "60614", "phone": null },
  "shipOption": "STANDARD",
  "items": [{ "sku": "BP-10021", "listingId": "…", "title": "…", "quantity": 1, "price": 12.50 }],
  "totals": { "items": 12.50, "shipping": 4.49, "tax": 1.50, "total": 18.49, "commission": 1.50, "processing": 0.65, "net": 14.84 },
  "tracking": null, "carrier": null
}], "page": 1, "pages": 1 }
GET/orders/{id}

One order with its event timeline.

GET/orders/{id}/rates

Label rates for this parcel from the configured carrier account.

POST/orders/{id}/ship

Either buy a label ({ "rateKey": "usps_media" } from /rates) or report your own: { "carrier": "USPS", "tracking": "9400…" }. Releases your proceeds and emails the buyer.

POST/orders/{id}/cancel

{ "reason": "Copy damaged in storage" }. Only unshipped orders. Refunds the buyer in full; counts against your completion rate.

Returns

GET/returns?status=REQUESTED

Open and past returns on your orders.

POST/returns/{id}/decision

{ "decision": "approve" | "refund_no_return" | "decline" | "receive", "note": "…" }. approve issues the buyer a label; receive confirms the item came back and refunds.

Account & payouts

GET/account

Store, plan, listing limit, performance, and Stripe verification status.

GET/payouts

Payout history with the orders each one covered.

Webhooks

Register an HTTPS endpoint in the portal or via the API. We POST JSON and sign it; respond 2xx within 10 seconds. Failed deliveries retry with backoff for 24 hours.

POST/webhooks

{ "url": "https://app.bookzpro.com/hooks/booklaan", "events": ["order.created", "order.cancelled", "listing.sold_out", "return.requested"] } → returns the endpoint and its secret once.

GET/webhooks

Your endpoints and the last 50 deliveries.

DELETE/webhooks/{id}

Remove an endpoint.

Events

  • order.created
  • order.shipped
  • order.cancelled
  • order.delivered
  • listing.sold_out
  • listing.updated
  • return.requested
  • return.decided
  • seller.activated

Verifying signatures

Booklaan-Signature: t=1731000000,v1=5f1a…   // HMAC-SHA256(secret, t + "." + rawBody)
Booklaan-Event: order.created

// Node
const [t, v1] = header.split(",").map(p => p.split("=")[1]);
const expected = crypto.createHmac("sha256", secret).update(t + "." + rawBody).digest("hex");
const valid = expected === v1 && Math.abs(Date.now()/1000 - t) < 300;

BookzPro

The Integrations page creates an API key scoped to BookzPro and a webhook endpoint in one click. BookzPro then pushes listings with POST /listings (its SKU as ours), receives order.created to decrement stock everywhere else, and reports shipments with POST /orders/{id}/ship. Quantity updates use PATCH /listings/{sku}.

Errors & limits

Errors are { "error": { "code": "validation_error", "message": "…" } } with the usual HTTP statuses (400, 401, 403, 404, 409, 429). Limits: 600 requests per minute per key; 500 listings per batch; 100 items per page.