Skip to content
APIv1
Menu

Rate limits

60 requests per minute per key, RateLimit headers on every response, and Retry-After on 429.

View as markdown

Each API key may make 60 requests per minute.

Headers

Every response carries:

HeaderMeaning
RateLimit-LimitRequests allowed per minute for this key.
RateLimit-RemainingRequests left in the current window.
RateLimit-ResetSeconds until the window resets.

A 429 also carries Retry-After: seconds to wait before retrying.

HTTP
HTTP/1.1 429 Too Many Requests
Content-Type: application/problem+json
RateLimit-Limit: 60
RateLimit-Remaining: 0
RateLimit-Reset: 17
Retry-After: 17
JSON
{
  "type": "https://developers.gocubic.io/errors/rate-limited",
  "title": "Rate limit exceeded",
  "status": 429,
  "code": "rate_limited",
  "detail": "This key has made more than 60 requests in the last minute.",
  "hint": "Wait the number of seconds in the 'Retry-After' header, then retry the same request."
}

Handling 429

TypeScript
async function getWithBackoff(url: string, headers: Record<string, string>) {
  for (let attempt = 0; ; attempt++) {
    const response = await fetch(url, { headers });
    const retryable = response.status === 429 || response.status >= 500;
    if (!retryable || attempt === 5) return response;

    const retryAfter = Number(response.headers.get('Retry-After'));
    const seconds = retryAfter > 0 ? retryAfter : 2 ** attempt;
    await new Promise((resolve) => setTimeout(resolve, seconds * 1000));
  }
}
Python
import time

import requests


def get_with_backoff(url, headers, params=None):
    for attempt in range(6):
        response = requests.get(url, headers=headers, params=params, timeout=30)
        retryable = response.status_code == 429 or response.status_code >= 500
        if not retryable or attempt == 5:
            return response
        retry_after = response.headers.get("Retry-After")
        time.sleep(int(retry_after) if retry_after else 2**attempt)

Staying under the limit

  • Use limit=100 when reading many shipments.
  • List items are full Shipment objects; do not fetch each one again.
  • Poll with updatedSince instead of re-reading everything.
  • Run requests one after another, not in parallel.