Rate Limiting

Each account has a built-in rate limiter and may optionally use queues to streamline the handling of peak sales. These rate limiters are also applicable to the API: order creation (and ticket assignment) is limited globally for an account, so a high demand on the web sales pages will also impact the available capacity on the API (and vice-versa).

This rate limiting can manifest itself when creating orders or when adding tickets to an order: a response status of 429 Rate Limit Exceeded will be returned.

This article describes how you can detect and properly handle rate limiting.

Detecting rate limiting

As mentioned earlier, whenever the system detects excessive demand, it will trigger a rate limit. When you create an order, the returned status will be 429 Rate Limit Exceeded.

Like web sales users, you will need to wait in a queue before you can proceed. Once it’s your turn, the system will create the requested order and allow you to continue.

A similar thing might happen when you try to add tickets to an order: the requested event (or product) might be rate limited and a 429 will be returned.

Key take-away: Always check the response status of “order creation” and “add tickets” calls, be prepared to handle a 429 Rate Limit Exceeded response.

Waiting in a rate limiter queue

Whenever an operation is refused due to rate limiting, you MUST wait in the rate limiting queue before retrying the operation or continuing further actions.

If you do not correctly request status updates, the order will be considered abandoned. Simply retrying your operation at some point in the future will not work and will cause more throttling.

The body of a 429 Rate Limit Exceeded response contains all the data needed to handle rate limiting. Here’s an example:

1 {
2   "id": "fa37e57a-5614-4726-9a53-89155424f82d",
3   "progress": 1,
4   "backoff": 30000,
5   "started": false,
6   "starttime": "2018-12-12T22:00:00Z",
7   "orderid": 621
8 }

The following fields are returned:

  • id: The queue ID, which you will need to poll for status updates
  • progress: The queue status, which will either be 1 (in progress) or 2 (finished). You cannot proceed as long as this is 1.
  • backoff: Number of milliseconds to wait before requesting a new status update. This will change dynamically based on where you are in the queue.
  • started: Whether the queue has started (as in: is progressing) or not (as in: is waiting until a fixed time before starting).
  • starttime: When the queue will start. Only returned for queues that have not started (started == false).
  • ahead: Number of people waiting in front of this request. Only returned for queues that have started (started == true, not shown above).
  • orderid: The ID of the newly created order. Only returned when a create order operation was rate limited and subsequently progressed through the queue. This can be used to retrieve the new order once progressed through the queue.

When encountering a rate limiting response, you must:

  1. Wait for the amount of time specified in backoff.
  2. Request a new status.
    • If progress == 1: Return to (1) and repeat
    • If progress == 2: Continue with normal operations

Requesting a new status is done by sending a POST request to /ratelimiting/status/{id}.

Once the returned progress equals 2, it is safe to proceed.

If the throttled operation was “create order”, you will not need to retry: the order will have been created and is now ready to use. The order ID will be supplied as part of the rate limiting status once progress == 2.

If the throttle operation was “add tickets”, you will need to retry the operation: the tickets you requested initially will not have been added to the basket when the call was rate-limited.

Avoiding rate limiting on “add tickets”

Rate limiting on “add tickets” may occur when there are specific queues active for certain events. This means that you might get throttled despite having an active order.

This is not ideal: it means that users will get placed into a queue when they try to add tickets. A much better experience would be to ensure that no rate limiting will occur while selecting tickets.

This can be done by passing the event and product IDs for which tickets might end up in the order when creating the order.

As an example: suppose you have a custom order page for events 324 and 452. Pass these event IDs when creating the order:

1 {
2     "saleschannelid": 1,
3     "events": [324, 452]
4 }

If this operation gets rate limited, you will be given a rate limiter session that guarantees that any “add tickets” calls for these events will succeed once you progress through the queue.

This is a much better user experience and thus highly recommended.

The recommended way to build a custom order page that handles rate limiting is as follows:

  • When a user arrives that the order page, create an order with any possible event and product IDs that might occur (see above).
    • If this simply returns an order, you will be certain that no further rate limiting will occur, the user can now fill his/her basket.
  • If a 429 Rate Limit Exceeded response is returned:
    • Show the user a page that explains that there is heavy demand (or that the sales haven’t started yet, depending on the started field).
    • Use JavaScript on this page to set a timeout for backoff milliseconds and then request a new status with the supplied queue ID. You will need to foresee an endpoint in your backend that calls the Ticketmatic API to request a new queue status and returns it to the client.
    • Make sure you tell the user not to close his/her browser.

This configuration has a number of advantages:

  • No additional rate limiting will happen once the order has been created.
  • No retry logic is needed on the server: the polling logic happens on the client. As long as each user keeps his/her browser open, it will periodically fetch new status updates.

Rate limiting in libraries

Go

A rate limited call will return a RateLimitError. This error has a status field which contains the rate limiting info.

 1 _, err = orders.Create(c, &ticketmatic.CreateOrder{
 2     Events: []int64{
 3         777714,
 4     },
 5     Saleschannelid: 1,
 6 })
 7 if err != nil {
 8     if e, ok := err.(*ticketmatic.RateLimitError); ok {
 9         // Do something useful with e:
10         return fmt.Errorf("Need to queue with ID %s\n", e.Status.Id)
11     } else {
12         return err
13     }
14 }

PHP

A rate limited call will throw a RateLimitException. This exception has a data field which contains the rate limiting info.

 1 try {
 2     $order = Orders::create($client, array(
 3         "events" => array(
 4             777714,
 5         ),
 6         "saleschannelid" => 1,
 7     ));
 8 } catch (RateLimitException $ex) {
 9     $status = $ex->data;
10     // Use $status to inform user about queue.
11     // The queue ID needed for polling is in $status->id
12 }

Operations