Skip to main content

Best Available

Rate limits

This endpoint belongs to the priority lane.

Don't want ticket buyers to select their seats? That's possible by passing in bestAvailable when booking (or holding) objects. will then automatically book (or hold) available objects that are closest to the focal point.

The best available seat algorithm uses an algorithm to determine which are the best available seats at any given moment. The algorithm itself is not configurable, but you can limit the possible results via input parameters such as the number of seats to select and the category or categories the resulting seats need to belong to.

The best available seats are determined in a number of steps. If a step in the algorithm does not result in a solution (i.e. available seats are found), the algorithm tries the following step , until a solution is found, or until there are no more steps to perform. In that case no solution is found.

The best available objects (seats/tables/booths/GA Places/...) are determined as follows:

  1. The algorithm selects a group of seats that are on the same row, are located next to each other and leave no orphan seats. From all the possible solutions, it selects the one that is closest to the focal point.
  2. If no solution is found in step 1, the algorithm selects a group of seats that are on the same row and next to each other, possibly leaving orphan seats. Again, if there are multiple solutions, it selects the one that’s closest to the focal point.
  3. Then, the algorithm simply selects the required number of seats that are closest to the focal point, without taking into consideration whether or not they’re on the same row. The algorithm makes sure to not leave people sitting alone, unless there's really no other option.
  4. If still no solution was found, the algorithm tries to select seats over different sections
  5. Up until this point, only seats (either at a table or in a row) were taken into account. If no solution has been found yet, this step will select the best available booths or tables. Of course, tables will only be selected if they are selectable, i.e. if they are bookable by table. Tables where only the individual seats are selectable will not be taken into account in this step.
  6. And finally, as a last step, the general admission (GA) areas are scanned for free spots, as always starting with the one closest to the focal point.
  7. If, at this point, there is no solution, then the API returns 400 Bad Request.

Some notes:

  • The above algorithm will never ever select seats (or GA places or tables or booths) that do not belong to one of the categories that are passed in as a parameter. This means you can use categories as a filter, to bypass steps in the algorithm.
    An example. Suppose your chart contains both GA areas and seats in blocks of rows. And to simplify, let’s assign “Category A” to all seats, and “Category B” to all General Admission areas. In this case, you can select the best available GA places, even if there are plenty of free seats left, simply by instructing the Best Available algorithm to only select places in Category B, which effectively bypasses step 1-4 of the algorithm.
  • The algorithm will always select just a single GA. For example, it will not select GA1 and GA2 if 2 places are selected, and both GA1 and GA2 have a single place left.
  • On multi-floor charts, the algorithm considers objects on lower floors to be "better" than objects on higher floors. Meaning: it first tries to find seats next to each other on floor 1. If that fails, it tries floor 2, and so on.

How to use it

POST https://api-{region}{eventKey}/actions/change-object-status

POST https://api-{region}{eventKey}/actions/book

POST https://api-{region}{eventKey}/actions/hold


"bestAvailable": {
number: 2,
categories: ["balcony", "stalls"],
extraData: [{"userId": "123"}, {"userId": "456"}],
ticketTypes: ["adult", "child"]
// Temporarily holding best available seats
"bestAvailable": {
number: 2
"holdToken": "wvXbB9MlHt"
// Finding best available objects within channel
"bestAvailable": {
number: 2
"channelKeys": ["28378c14-ae6a-46a4-ada4-9c745a45e018"]
// Finding best available objects that are within a channel and also belong to either category balcony or stalls
"bestAvailable": {
number: 2
"channelKeys": ["28378c14-ae6a-46a4-ada4-9c745a45e018"],
"categories": ["balcony", "stalls"]
  • bestAvailable.number the number of objects to book (required)
  • bestAvailable.categories optional array of categories from which the best available objects should be picked. Can be either category keys or category labels.
  • bestAvailable.extraData optional array of extraData elements. The first extraData element gets assigned to the first best available object, the second extraData element to the second best available object and so on. That's why the number of extraData elements must match the number of requested objects.
  • bestAvailable.ticketTypes optional array of ticket type strings. The total number in this ticketTypes object must match the number of requested objects.
  • holdToken (optional): the hold token must be supplied when temporarily holding best available objects.
  • orderId (optional): an order id, defined by yourself, to be able to retrieve the objects IDs per order later on.
  • keepExtraData (optional): boolean. If set to true, the existing extra data doesn't get cleared
  • channelKeys (optional): an array of channel key strings. The best available algorithm will only look for objects within those channels. Pass in NO_CHANNEL to allow finding best available objects without a channel.
  • ignoreChannels (optional): if true, the best available algorithm searches across all channels.
  • tryToPreventOrphanSeats (optional): by default, the best available algorithm tries not to leave orphan seats. If you pass in false to this flag, we don't try to prevent orphan seats. Should not be used in combination with channelKeys.


200 OK: if everything went ok and the best available seats were booked/held/changed status. 400 Bad Request: if there were not enough available seats, if there was no focal point specified on the seating chart, or for other reasons. Check the response body for details.

"objects": ["A-1", "A-2"],
"objectDetails": {
"A-1": {
"label": "A-1",
"labels": {
"own": {
"label": "1",
"type": "seat"
"parent": {
"label": "Row A",
"type": "row"
"ids": {
"own": "1",
"parent": "A"
"status": "booked",
"categoryLabel": "Ground Floor",
"categoryKey": "4",
"forSale": true,
"objectType": "seat",
"isAccessible": true,
"isCompanionSeat": false,
"hasRestrictedView": false,
"rightNeighbour": "A-2",
"entrance": "Blue"
"nextToEachOther": true
  • objects: array of strings, containing the labels of the objects that were chosen as best available
  • objectDetails: same as in the change object status response.
  • nextToEachOther: boolean that indicates if the best available seats are next to each other. When the algorithm picks booths or tables, nextToEachOther is not present in the response.

BestAvailable cannot be used when booking objects in an event group. Use seasons for that.