This page outlines errors encountered when using Topsort’s /auctions and /events endpoints or APIs, classified by HTTP status code:

4xx: Request problem
5xx: Topsort service problem

Both errors return JSON arrays containing error objects with fields: errCode, docUrl, and an optional message.

FieldTypeDescription
errCodestringA short string uniquely identifying the problem.
docUrlstringA link to this documentation providing more information about the error.
messagestringOptional. If present, human-readable explanation of or details about the error. The string for a given error may change over time; code should not parse or dispatch based on particular values for this field.

Error Codes and Meanings:

CodeDescriptionDetails
400Bad RequestUnacceptable request, i.e. Incorrect formatting
403Forbidden/UnauthorizedAPI key issue or missing tokens
404Not FoundThe server cannot find the requested resource. Either the request URL is not on our routes, or the resource is not available (ie. the requested campaign does not exist)
422Unprocessable EntityMismatched request body and model, i.e, you are missing a property, or API is expecting a date but received a number
429Rate Limit ExceededIP-based rate limit reached. This error comes with following headers:
- X-RateLimit-Limit: total number of requests allowed for the time period
- X-RateLimit-Remaining: remaining number of requests for the time period
- X-RateLimit-Reset: when you can make another request

Error Codes

Error CodeDescription
bad_requestRequest couldn’t be parsed; check the OpenAPI specification for the correct schema.
empty_requestRequest is empty; check the OpenAPI specification for the correct schema.
internal_server_errorUnexpected server problem; our team typically fixes these issues quickly.
invalid_api_keyMissing, invalid, or expired API key; see authentication for details.
invalid_auction_idAuction ID doesn’t correspond to an auction; ensure a valid auction ID is passed in the request.
invalid_event_typeEvent type must be “Impression”, “Click”, or “Purchase”.
invalid_promotion_typeInvalid promotion types in slots field.
invalid_sessionsession object must contain a non-empty sessionId.
missing_aspect_ratioRequired aspect ratio for banner ads is missing.
missing_auctionsAt least one auction must be specified.
missing_contextRequired context missing; specify a category, product list, or search query.
missing_placementRequired placement or placement.page field is missing.
missing_product_idproductId missing.
missing_promotion_typeAn auction must request slots for at least one promotion type.
missing_purchased_atRequired purchasedAt field missing.
missing_sessionRequired session field missing.
missing_slotsRequired slots field missing.
no_productsAt least one product must be specified.
no_purchase_itemsAt least one item must be purchased.
purchase_item_quantity_less_or_equal_than_zeroA purchase item has a quantity of less than or equal to zero.
resolved_bid_id_not_foundProvided resolved bid ID doesn’t match an internal record.
too_few_impressionsAt least one impression must be included.
too_few_slotsAt least one slot must be specified in an auction.
too_many_auctionsMaximum of 5 auctions can run in parallel; contact your KAM to increase this limit.

Handling rate limiting

Our endpoints - except making calls to /auctions or /events - are rate-limited to prevent abuse. If you exceed the rate limit, you will receive a 429 error response. There are two recommended ways to handle these limits

Retry with exponential back-off

Exponential backoff retry is a technique used in programming to retry an operation with increasing intervals between retries, which helps to mitigate issues such as network latency, temporary failures, or resource constraints. Below there is a code example in Python on how the technique can be implemented.

def exponential_backoff_retry(url, max_retries=5, base_delay=1, max_delay=64, retry_on_status=429):
    retries = 0
    delay = base_delay
    while retries < max_retries:
        try:
            response = requests.get(url)
            if response.status_code == retry_on_status:
                print(f"Received status code {retry_on_status}, retrying...")
                retries += 1
                if retries < max_retries:
                    print(f"Retrying in {delay} seconds...")
                    time.sleep(delay)
                    delay = min(delay * 2, max_delay)
                else:
                    raise Exception(f"All retries exhausted for status code {retry_on_status}")
            else:
                response.raise_for_status()  # Raise an exception for HTTP errors other than the specified one
                return response.json()  # Assuming the response is JSON, adjust as needed
        except Exception as e:
            print(f"Attempt {retries + 1}/{max_retries} failed: {e}")
            retries += 1
            if retries < max_retries:
                print(f"Retrying in {delay} seconds...")
                time.sleep(delay)
                delay = min(delay * 2, max_delay)
            else:
                raise

Use Retry-After

Use the values in the headers to determine when you can make another request:

  • X-RateLimit-Limit: how many requests you have made during the time period
  • X-RateLimit-Remaining: remaining request during the time period
  • X-RateLimit-Reset: when you can make another request

Note that if you have distributed services hitting the resource, you can still get 429, even if you waited the time amount specified in X-RateLimit-Reset. If you are hitting this problem, you may want to either replace this technique with the Exponential back-off or use them together, that is, first waiting the amount of time given by X-RateLimit-Reset and then fall-back to exponential back-off retries.