Lots, items & images
An item is the physical object: a vase, a cabinet, a painting. A lot is that item offered in one session at one number. The split matters: an unsold item can be re-offered later as a new lot, so the item carries the description, the estimate and the photographs, while the lot carries the number, the bidding and whether it sold.
The lot object
{
"id": "lot_b48e0a19-5c72-4d83-91af-3e6b2c07d514",
"lot_number": 24,
"active": true,
"title": "Delft blue tulip vase, 18th century",
"starting_bid": { "amount": 8000, "currency": "EUR" },
"current_bid": { "amount": 9500, "currency": "EUR" },
"sold": false,
"closes_at": "2026-07-05T19:11:30Z",
"timed": { "scheduled_closes_at": "2026-07-05T19:00:00Z" },
"item": "itm_2d9f6b31-8e4a-4c05-b7d2-9a1e3f8c6047",
"session": "ses_7c1d5e88-2a34-4f19-9b0c-6d2e8f4a1357",
"created_at": "2026-05-20T14:02:00Z",
"updated_at": "2026-07-05T19:08:11Z"
}
active is the lot’s active flag, using the same meaning as the list filter. It is always true or false; an older unset value is returned as false. An active lot can still belong to an unpublished session or auction, and customer bidding can be disabled separately. This field does not promise that the lot is visible on a particular website or currently accepts bids.
Amounts are Money objects: integer minor units plus a currency, so 9500 here is €95,00.
closes_at is when this lot stops taking bids. In a timed sale read it per lot: it is not the session’s closing time, and lots within one session usually close at different moments, often a minute or two apart, though some houses schedule a whole session to close at once. In a live sale every lot carries the same value, the session’s online-bidding close, because that is when online bidding stops for all of them. It may also be null, when no closing time has been set.
What it means depends on the session’s kind.
In a timed sale it is the lot’s own end, and it moves: a bid within the session’s extension_threshold_seconds of the close pushes it to the bid plus extension_seconds, and a bid inside the new window pushes it again, so a contested lot can run well past its scheduled end. Both numbers are on the session (two minutes each unless the house set otherwise). Treat the value as true as of this response and re-read it while the lot is live.
In a live sale it is when online bidding closes for the session. The lot’s own end time is its slot in the running order, not a bidding deadline. Nothing extends, and there is no timed object or scheduled_closes_at field on a live lot.
timed.scheduled_closes_at is the time before any extension, so a difference from closes_at tells you the lot has already been pushed out once and is likely to be again. A live lot has no timed half at all. There is nothing to extend, so for a live lot closes_at is the only closing time there is.
item and session are IDs, or full objects under expand[].
The item object
{
"id": "itm_2d9f6b31-8e4a-4c05-b7d2-9a1e3f8c6047",
"title": "Delft blue tulip vase, 18th century",
"description": "Pear-shaped, with floral decoration…",
"condition": "Hairline crack at the rim",
"dimensions": "H 34 cm",
"weight": "1,2 kg",
"estimate": {
"low": { "amount": 8000, "currency": "EUR" },
"high": { "amount": 12000, "currency": "EUR" }
},
"images": ["img_c17a4e52-6b90-4f38-a2d5-0e8b1c4d7936", "img_e30b95a7-1f42-4c86-b9e0-5d7a2f13c804"],
"created_at": "2026-05-18T09:12:00Z",
"updated_at": "2026-05-19T16:40:00Z"
}
condition, dimensions and weight are free text as the house wrote them, not parsed measurements. Either bound of estimate may be absent.
The item image object
{
"id": "img_c17a4e52-6b90-4f38-a2d5-0e8b1c4d7936",
"url": "https://…/fitted/front.jpg",
"preview_url": "https://…/fitted_thumbnail/front.jpg",
"thumbnail_url": "https://…/thumbnail/front.jpg",
"mini_url": "https://…/mini/front.jpg",
"position": 0,
"featured": true
}
An item image is two things at once, and the schema says so: an Image (the renditions, which every image in the API has) plus the two things the auction house decides about this one in this gallery.
Four sizes are published. Pick by what you are rendering, not by what is largest:
| Field | Size | Shape |
|---|---|---|
url | up to 900x1200 | aspect ratio preserved |
preview_url | up to 250x250 | aspect ratio preserved |
thumbnail_url | exactly 250x250 | cropped square |
mini_url | exactly 70x70 | cropped square |
The distinction matters for a catalogue: a square crop of a longcase clock or a wide landscape cuts the lot off, so use the fitted pair wherever the whole object has to be visible. The original upload is not exposed: it is unbounded in size, and every published rendition has a known ceiling.
position is its place in the gallery, zero-based and never null. It always equals the entry’s index in the images array, so the two can never disagree.
featured is whether the house picked this as the item’s lead photograph. Do not assume exactly one image has it: unfeaturing does not promote a replacement, so an item can have none.
Only publicly visible images are returned, and they always arrive in gallery order.
Endpoints
These four read endpoints require lots.read, which also governs items and their images. The lot activation PATCH below additionally requires lots.write.
GET /lots
GET /lots/{id}
GET /items
GET /items/{id}
The public gallery arrives with its item, as IDs, or in full with expand[]=images. The nested image management endpoints below also expose private and processing images for import reconciliation.
Lists take limit and cursor (pagination), plus:
| Parameter | On | Effect |
|---|---|---|
session | lots | Only lots in that session |
auction | lots | Only lots in that auction |
active | lots | Filter the lot’s active flag; false includes older unset values |
expand[] | lots | item, images, session |
expand[] | items | images |
Examples
A session’s catalogue, everything needed to render it, in one page of requests:
curl "https://app.bidvise.com/api/v2/lots?session=ses_7c1d5e88-2a34-4f19-9b0c-6d2e8f4a1357&limit=100&expand[]=item&expand[]=images" \
-H "Authorization: Bearer $BIDVISE_API_KEY"
Expanding is the point here: without it, rendering 100 lots means 100 follow-up requests for items and another 100 for images.
One lot in full:
curl "https://app.bidvise.com/api/v2/lots/lot_b48e0a19-5c72-4d83-91af-3e6b2c07d514?expand[]=item&expand[]=item.images&expand[]=session" \
-H "Authorization: Bearer $BIDVISE_API_KEY"
Walking the whole inventory, sale or no sale:
curl "https://app.bidvise.com/api/v2/items?limit=100&expand[]=images" \
-H "Authorization: Bearer $BIDVISE_API_KEY"
Keep following next_cursor until has_more is false.
Activate lots before bidding opens
PATCH /api/v2/lots/{id} changes only the active flag of an existing lot. The API key needs both lots.write and lots.read. It also works for lots created through v1; it does not create, move or renumber lots.
curl -X PATCH "https://app.bidvise.com/api/v2/lots/lot_b48e0a19-5c72-4d83-91af-3e6b2c07d514" \
-H "Authorization: Bearer $BIDVISE_API_KEY" \
-H "Content-Type: application/json" \
-d '{"active": true}'
Use false to deactivate. The body must contain only active, as a JSON boolean, not a string. A successful response is 200 with the current lot in data. An already-matching value is a no-op: no save or new scheduling job, even after bidding has opened. false also matches an older unset flag.
A change requires an unfinished session whose opens_at is at least five minutes in the future and which has no bids on any lot, including archived lots. Timed sessions also need a first closing after opening, a positive group size and a positive interval. The five-minute lead is checked again after readback, before committing. Otherwise the request returns 409 without changing the flag. Invalid input returns 422; PUT is not supported. Auction/session publication and customer-bidding controls remain unchanged.
Changing a timed lot’s active flag queues a recalculation of the session’s closing times. Deactivating a lot can move the remaining lots’ closes earlier. The 200 response confirms the flag was saved, not that the job finished. Read back all session lots and verify timed.scheduled_closes_at before opening bidding. Repeating the same PATCH does not restart a failed job; unresolved processing needs staff attention. This endpoint is for catalogue preparation, not changes during an auction.
Item creation and updates
Use item writes for atomic POST/PATCH, translations and seller/category assignments. Reads also return seller, categories and stored translations; flat text fields keep their existing default-language values.
Reconcile every image during an import
GET /api/v2/items/{item_id}/images and GET /api/v2/items/{item_id}/images/{id} require lots.read. These management reads include private and processing images, while expand=images continues to return only the public gallery. Use the returned img_… ID for one image, and itm_… for its parent; bare UUIDs also work. An image from another item or house returns 404.
The list accepts an exact, case-sensitive external_reference filter and the usual limit/cursor. It is ordered by creation time and UUID, so an interrupted importer can reconcile an upload without guessing from image counts. Unknown parameters and blank references return 400; ambiguous legacy identities return 500 rather than selecting an arbitrary record.
Management metadata includes the parent ID, upload reference, public, featured, processing, timestamps, the four existing rendition URLs and original_url. The original may be large; it is not added to the normal public gallery response. A missing file may produce a null URL; a generated URL does not prove the remote file exists.
gallery_position is the dense zero-based position in the complete current public gallery, or null for a private image. Filtering to a single upload or paging the management list does not renumber it. Management pagination order is independent of gallery order.
processing is the existing pending-work flag. False does not prove that processing succeeded, and these reads do not invent ready/failed states. Upload and gallery replacement are documented in the OpenAPI specification. Durable processing-state support remains separate API work.