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