Skip to content

Understanding errors and rate limits

Every error has the same shape, so your code can branch on error.code instead of reading the message. Messages are written for people and can change. Codes are stable.

{
"error": {
"code": "rate_limited",
"message": "Rate limit of 100 requests per minute exceeded.",
"request_id": "req_4f1c2b7e9a0d4e6f8b1a2c3d4e5f6a7b"
}
}
HTTP Code What it means What to do
400 invalid_request A parameter is wrong, unknown, repeated, sent as an array, or combined with one it cannot be combined with. message names the parameter Fix the request. Don’t retry it unchanged
400 invalid_cursor The cursor cannot be read Restart the list from your last saved updated_at
401 invalid_api_key The key is missing, malformed, unknown or revoked Check the Authorization: Bearer header. Create a new key if it was revoked
403 plan_not_eligible The store’s plan does not include the API Upgrade to Premium, or contact support
403 shop_inactive Bloop is not installed on the store, or API access is suspended for it Reinstall Bloop. If it is installed, contact support
403 insufficient_scope The key does not have the scope the endpoint needs Create a key that has the scope
404 referrer_not_found No referrer matches, the id is not a valid referrer id, or the referrer belongs to another store Treat the person as “not a referrer”
404 not_found The path, the method or the campaign does not exist, or the campaign belongs to another store Check the URL, use GET, check campaign_id
429 rate_limited Too many requests for the store, or too many invalid keys from your IP Wait the number of seconds in Retry-After, then retry
500 internal_error Something failed on Bloop’s side Retry later with backoff. If it persists, contact support with the request_id
503 service_unavailable Bloop is briefly unable to check the key or read the data Wait the number of seconds in Retry-After, then retry

New codes can appear within version 1. Handle a code you don’t know by its HTTP status.

Bloop checks a request in this order and stops at the first problem:

  1. An IP that already received 30 401 responses within the current 60-second window gets 429, before its key is even read.
  2. The key: 401 invalid_api_key.
  3. The store’s access: 403 plan_not_eligible or 403 shop_inactive.
  4. The rate limit: 429 rate_limited.
  5. The path and method: 404 not_found.
  6. The key’s scope: 403 insufficient_scope.
  7. The parameters: 400 invalid_request or 400 invalid_cursor.

Requests rejected at steps 5 to 7 still count toward your rate limit, and so does GET /v1/me.

  • Version 1 only has GET endpoints. Any other method, including OPTIONS and HEAD, returns 404 not_found once the key is valid. A request without a key gets 401 first, and that is what a browser preflight receives.
  • GET /v1/me and GET /v1/referrers/{id} take no query parameters. Adding one returns 400 invalid_request.
  • Unknown parameters, repeated parameters (?email=a&email=b) and array or object syntax (?email[]=a) return 400 invalid_request.
  • Query values are read like form data, so a + means a space. Encode a + in an email as %2B.

The limit applies per store and is shared by every key of the store. Today every eligible plan gets 100 requests per minute. Read the current value from limits.requests_per_minute in GET /v1/me, or from the headers below.

Header Meaning
X-RateLimit-Limit Requests allowed in a 60-second window
X-RateLimit-Remaining Requests left in the current window
X-RateLimit-Reset Seconds until the current window ends
Retry-After On 429 and 503: seconds to wait before you retry

Responses that pass the key and store checks carry the X-RateLimit-* headers. Errors returned before the rate limit is checked do not: 401, 403 plan_not_eligible, 403 shop_inactive, the IP block 429, and a 503 while the key is checked.

When you get 429, wait for Retry-After and retry. Spread large syncs out instead of sending pages as fast as possible.

Separately, after 30 requests with a missing, malformed or invalid key from one IP within 60 seconds, every request from that IP gets 429 until that 60-second window ends. A loop that retries a revoked key can lock out your other integrations on the same server.

  • Retry with backoff: 429, 500, 503. Honor Retry-After when it is present.
  • Don’t retry unchanged: 400, 401, 403, 404. The same request gets the same answer.

Every response carries an X-Request-Id header, and every error repeats it as request_id. Quote it when you contact support. To tie Bloop’s answer to your own logs, send your own X-Request-Id: 8 to 64 letters, digits, _ or -. A value in another format is replaced by one Bloop generates.

  • Parsing message. Branch on code. Messages change.
  • Retrying a 400 or 401 in a loop. It never succeeds, and repeated 401 responses get your IP blocked.
  • Giving each integration its own budget in your head. All keys of a store share one limit.
  • Ignoring Retry-After. Retrying sooner just earns another 429.