Conventies
Leer deze één keer; ze gelden overal.
Catalogus lezen en schrijven
Versie 2 leest de catalogus en biedt gedocumenteerde schrijfoperaties voor items, afbeeldingen, conceptveilingen en sessies, en kavels activeren voordat het bieden opent. Zie items schrijven voor JSON, rechten, validatie en het herstellen van afgebroken itemverzoeken. Elke operatie heeft eigen rechten en grenzen; de OpenAPI-specificatie beschrijft de ondersteunde velden. Een schrijfantwoord betekent niet dat publicatie, bieden of het verwerken van afbeeldingen of sluitingstijden voltooid is.
ID’s
Elk object heeft een ID met prefix: auc_ voor veilingen, ses_ voor sessies, lot_ voor kavels, itm_ voor items, img_ voor afbeeldingen, sel_ voor inbrengers, cat_ voor categorieën, mkr_ voor makers, dlc_ voor bezorgklassen, inc_ voor biedstappen en con_ voor consignaties.
Door die prefix spreekt een ID in een logregel voor zich, en een sessie-ID doorgeven waar een kavel-ID hoort levert een 404 op in plaats van stilletjes het verkeerde object. Behandel ID’s als ondoorzichtige strings: het deel achter de prefix mogen wij wijzigen.
De prefix is verplicht in antwoorden en optioneel in verzoeken: GET /lots/lot_b48e0a19-… en GET /lots/b48e0a19-… werken allebei, dus een koppeling die kale identifiers heeft opgeslagen hoeft die niet eerst om te schrijven. Een verkeerde prefix wordt wél geweigerd: GET /lots/ses_b48e0a19-… levert een 404 op, want om het verkeerde soort object vragen is een fout die gemeld hoort te worden.
Geld
Geld is een object met een heel bedrag in minor units en een ISO 4217-valuta:
"starting_bid": { "amount": 12000, "currency": "EUR" }
Dat is € 120,00. Geen floats, geen dubbelzinnigheid door locale, en geen los valutaveld elders in de response dat synchroon gehouden moet worden.
Een taxatie is een reeks waarvan de grenzen hetzelfde object zijn, zodat één formatteerfunctie in de code elk bedrag aankan dat de API teruggeeft. Elke grens mag ontbreken:
"estimate": { "low": { "amount": 8000, "currency": "EUR" },
"high": { "amount": 12000, "currency": "EUR" } }
Tijd
Tijdstempels zijn RFC 3339 in UTC: 2026-07-01T10:00:00Z.
Tekst
Catalogustekst (titels en omschrijvingen van items, namen van veilingen en sessies) komt terug als platte string in de eigen taal van het veilinghuis:
"title": "Delfts blauwe tulpenvaas, 18e eeuw"
Elk huis op het platform draait één taal, dus objecten per locale zouden ceremonie om één waarde heen zijn. Voegt een huis ooit een tweede taal toe, dan komt er een locale-parameter om die te kiezen; de vorm van het veld blijft hoe dan ook plat.
Paginering
Lijsten werken met cursors:
curl "https://app.bidvise.com/api/v2/lots?session=ses_7c1d5e88-2a34-4f19-9b0c-6d2e8f4a1357&limit=50" \
-H "Authorization: Bearer $BIDVISE_API_KEY"
{ "data": [ … ], "has_more": true, "next_cursor": "cur_MGY4Yz…" }
Stuur next_cursor terug als cursor voor de volgende pagina, en stop zodra has_more false is. limit loopt van 1 tot 100 en staat standaard op 25.
Elke collectie heeft een vaste volgorde, en de cursor is een positie daarin: kavels op kavelnummer, sessies op wanneer het bieden opent (nieuwste eerst), veilingen en items op wanneer ze zijn aangemaakt (nieuwste eerst). Ontbreekt een waarde, dan sorteert die achteraan, en de identifier van het record breekt gelijke standen zodat de volgorde volledig is en een paginagrens nooit op een dubbelzinnige plek valt.
Cursors werken op keyset, niet op offset: een catalogus die groeit tijdens het doorlopen, schuift nooit rijen in een pagina die al gelezen is, en herhaalt er geen. De garantie geldt voor rijen die er waren bij het begin: een rij die achter de huidige positie wordt toegevoegd (kavel 10 terwijl de doorloop al voorbij 50 is) verschijnt in de rest van die doorloop niet. Haal die op met een nieuwe doorloop, of door op updated_at te letten. Een cursor is ondoorzichtig: stuur hem ongewijzigd terug in plaats van hem te ontleden. Responses dragen daarnaast een RFC 8288 Link-header met rel="next", die op de laatste pagina ontbreekt; cursorpaginering loopt alleen vooruit, dus er is geen prev of last om te volgen.
Expansie
Relaties zijn standaard ID’s. Vouw er een ter plekke uit met expand[]:
curl "https://app.bidvise.com/api/v2/lots/lot_b48e0a19-5c72-4d83-91af-3e6b2c07d514?expand[]=item&expand[]=item.images" \
-H "Authorization: Bearer $BIDVISE_API_KEY"
Uitvouwen vereist het recht van de uitgevouwen resource, naast dat van wat er gelezen wordt: een sleutel met alleen lots.read krijgt ?expand[]=session geweigerd, want een sessie is wat auctions.read beschermt. Iets inline opvragen mag geen omweg zijn om het tóch te mogen lezen.
Het uitgevouwen veld houdt zijn naam en zijn plek: item is een string vóór expansie en een object erna, nooit een tweede veld ergens anders in de response. Daarom zijn er geen aparte “gedetailleerde” endpoints: diepte is een parameter, geen andere URL.
Onbekende en ongeldige parameters
Er wordt niets geraden. Een limit die geen heel getal is, een cursor die deze API niet heeft uitgegeven, een expand-waarde die de resource niet ondersteunt, een boolean-filter die niet true of false is, of een filter-ID van het verkeerde soort levert een 400 op, en de detail noemt de parameter en wat er verwacht werd: bij expand staat erbij wat de resource wél kan uitvouwen.
Dat is bewust. Het alternatief is stilzwijgend een standaard nemen, negeren of opnieuw beginnen: expand[]=iamges dat geen afbeeldingen en geen fout geeft, of een beschadigde cursor die stilletjes vooraan begint zodat een synchronisatie de hele catalogus twee keer verwerkt. Een typfout moet gemeld worden: één keer, meteen.
Fouten
Fouten zijn RFC 9457-problem-documenten, geserveerd als application/problem+json:
{
"type": "https://docs.bidvise.com/api/problems/not-found",
"title": "Resource not found",
"status": 404,
"instance": "/api/v2/lots/lot_b48e0a19-5c72-4d83-91af-3e6b2c07d514",
"detail": "Unknown lot id"
}
4xx betekent: pas het verzoek aan. 5xx betekent: probeer het later opnieuw.
Rate limits
300 verzoeken per minuut per sleutel. Elke response op een sleutel die aan een veilinghuis gekoppeld is, draagt RateLimit-Limit, RateLimit-Remaining en RateLimit-Reset (seconden tot het venster opnieuw begint); daarboven volgt een 429 met Retry-After.
Het venster is vast en niet schuivend, wat op de grens uitmaakt: een client kan zijn hele tegoed in de laatste seconde van een minuut opmaken en opnieuw in de eerste seconde van de volgende, dus het echte worstcase is twee keer de limiet over twee seconden. Minder en grotere aanroepen (limit=100) zijn beter dan veel kleine.
De limiet geldt per sleutel, dus de ene koppeling kan het tegoed van de andere niet opmaken.
Afbakening en isolatie
Een API-sleutel hoort bij precies één veilinghuis, en elke response is daarop afgebakend. Er is geen opzoeking over huizen heen en geen parameter die de afbakening verbreedt: een ID van een ander huis leest als 404, niet als 403, omdat het bestaan van dat object niet via de API te achterhalen mag zijn.
Versionering
De hoofdversie staat in het pad (/api/v2) en verandert alleen bij breaking changes. Binnen een versie zijn wijzigingen aanvullend: er kunnen nieuwe velden en endpoints bij komen, dus parse responses soepel en negeer onbekende velden.