Beezr API

Limit layers

These are the defaults. All workspace keys share the workspace limits.

LimitDefaultScopeWhen exceeded
Requests per minute60Workspace429 RATE_LIMIT_EXCEEDED, Retry-After seconds
Requests per hour2,000Workspace429 RATE_LIMIT_EXCEEDED, Retry-After
Requests at the same time2Workspace429 TOO_MANY_CONCURRENT_REQUESTS, Retry-After: 1
Requests per minute from one IP120Caller IP, before key check429 RATE_LIMIT_EXCEEDED, Retry-After
Read calls per key1,000 per hourKey, for query/get/content429 RATE_LIMIT_EXCEEDED, X-RateLimit-Reset
Monthly API callsSet by planWorkspace, calendar month429 MONTHLY_QUOTA_EXCEEDED past 110% of allowance; resets on the 1st
Records per bulk call100Request413 PAYLOAD_TOO_LARGE
File size10 MBFile, upload and downloadUpload: 400 CONTENT_TOO_LARGE; download: 413 CONTENT_TOO_LARGE
Query page size1–100; default 20QueryClamped, no error

A bulk call counts as one request for rate limits and the monthly count. If your integration needs higher limits, contact us.

Decide when to retry

All 429s are retryable after waiting, except MONTHLY_QUOTA_EXCEEDED: stop until the 1st of the next month. On other 429s, wait Retry-After seconds. For the per-key read window, X-RateLimit-Reset gives the reset time in epoch milliseconds.

Keep at most 2 calls in flight. Batch writes with bulk endpoints and request only the fields you need. For create and update retries, keep the same idempotency key and body.

Read the headers

Read responses carry X-RateLimit-Limit, X-RateLimit-Remaining and X-RateLimit-Reset for the per-key hourly read limit. Write responses don't carry these headers. The per-key values don't describe the workspace minute limit.

Retry code

These helpers take an existing JSON request body. They bound retries, inspect the monthly error before waiting, and use the read reset header when Retry-After is absent. If neither wait header is present, they stop for the caller to inspect. A create or update caller must provide the same idempotency key on each attempt. Bulk calls don't support idempotency.

# Bash helper; Python reads headers and JSON. Usage: beezr_post URL BODY [IDEMPOTENCY_KEY]
beezr_post() (
  url=$1; body=$2; key=${3:-}
  tmp=$(mktemp -d)
  trap 'rm -rf "$tmp"' EXIT
  extra=()
  [ -z "$key" ] || extra=(-H "Idempotency-Key: $key")
  for attempt in 1 2 3 4; do
    status=$(curl --silent --show-error -o "$tmp/body" -D "$tmp/headers" -w '%{http_code}' \
      "$url" -H "X-API-Key: $BEEZR_API_KEY" -H "Content-Type: application/json" \
      "${extra[@]}" --data "$body") || return 1
    if [ "$status" != 429 ]; then
      cat "$tmp/body"
      [[ "$status" == 2* ]] && return 0
      return 1
    fi
    wait=$(python - "$tmp/body" "$tmp/headers" <<'PY'
import json, sys, time
with open(sys.argv[1]) as f:
    result = json.load(f)
if result.get("error", {}).get("code") == "MONTHLY_QUOTA_EXCEEDED":
    sys.exit(1)
with open(sys.argv[2]) as f:
    headers = dict(line.strip().split(": ", 1) for line in f if ": " in line)
headers = {k.lower(): v for k, v in headers.items()}
if "retry-after" in headers:
    print(max(0, float(headers["retry-after"])))
elif "x-ratelimit-reset" in headers:
    print(max(0, float(headers["x-ratelimit-reset"]) / 1000 - time.time()))
else:
    sys.exit(1)
PY
    ) || { cat "$tmp/body"; return 1; }
    [ "$attempt" -lt 4 ] || { cat "$tmp/body"; return 1; }
    sleep "$wait"
  done
)

Watch monthly usage

Usage is visible in Designer → Usage (API calls) and Subscription. Emails go to the workspace alert address at 80% and 100% of allowance and when calls are blocked. See Handle rate limits well.