Skip to content

Rate Limits & Errors

Every HTTP API response carries a ret_code field. The HTTP status code is not the source of truth — ret_code: 100 means success regardless of the transport. Inspect ret_code first.

Return codes

ret_codeMeaningRecommended client action
100Success.Use the exp_data / data payload as is.
101No permission.Verify X-Ak matches a key in this project, and the key is Active. See API keys.
102Traffic limit.You have hit a rate or quota ceiling. Back off and retry; see below.
103Required project ID.The request body is missing or has an empty project_id.
104Server error.Treat as transient; retry with backoff.
105Server error.Treat as transient; retry with backoff.
0Unknown.Treat as transient; retry once with backoff before logging an error.

The msg field carries a human-readable string when one is available; treat it as advisory, not machine-readable.

Designing retries

Retries on 102, 104, 105, and 0 are safe — the call is idempotent. Use exponential backoff:

attempt 1: immediate
attempt 2: wait 250 ms
attempt 3: wait 1 s
attempt 4: wait 4 s
fail

Cap the total retry budget at the timeout your caller is willing to spend. The HTTP API endpoint serves assignments, not data plane writes — if the deadline expires, fall back to the parameter default rather than blocking the user. See Default values & fallback.

Do not retry on 101 and 103 — these signal a configuration mistake on the caller side (wrong key, missing project ID). Fix the request and try again.

Rate-limit response

ret_code: 102 is the platform's signal that the caller is currently rate-limited. The platform does not currently return rate-limit headers (no X-RateLimit-Remaining, no Retry-After); apply the backoff schedule above.

If you see 102 repeatedly under steady load, you have crossed a project-level traffic ceiling. Reach out to support to review the limit for your project.

Transport-level errors

Treat anything below the application layer as transient and retry with the same backoff:

  • connect / dns failures;
  • TLS handshake errors;
  • HTTP 5xx responses without a parseable JSON body.

For HTTP 4xx responses with no JSON body, log and stop — the platform did not see a request worth processing.

Idempotency

/abc/get_experiments and /abc/get_feature_flags are idempotent reads. Retrying never changes the assignment; it only causes the platform to re-record an exposure when the call ultimately succeeds. If you are concerned about exposure duplication during retries:

  • back off aggressively so the same unit does not produce a burst of exposures;
  • for batch jobs, write a small idempotency guard around the call site;
  • for online traffic, accept the duplicates — the engine deduplicates within an exposure window.

Worked example

bash
http POST openapi.abetterchoice.ai/abc/get_experiments \
  X-Ak:$ak X-Et:$et X-Es:$sig \
  project_id=6666 unit_id=user_id_1
# {"ret_code":102,"msg":"traffic limit","exp_data":{}}

# Wait 1 second, retry...
sleep 1
http POST openapi.abetterchoice.ai/abc/get_experiments ...
# {"ret_code":100,...}