API
Errors, limits and reliability
Status codes, error bodies and how to build an integration that survives them.
Status codes
| Code | Meaning | What to do |
|---|---|---|
| 200 | Success | - |
| 400 | Missing or invalid parameter | Read error; it names what is wrong and lists valid values |
| 401 | Invalid, missing or expired API key | Check the header format and the key's expiry |
| 403 | Scope or client access denied | Confirm the key's scopes and that the client is linked to your agency |
| 405 | Wrong method | Use GET to read and POST to act |
| 500 | Server error | Retry with backoff; if it persists, report it with the timestamp |
{ "error": "Invalid order field. Allowed: created_at, updated_at, id, fetched_at, tracked_at, external_pages, linking_domains, appearances, scored_at" }Handling errors in code
res=$(curl -s -w "\n%{http_code}" "$AISOIQ_API_BASE?resource=keywords&client_id=$CLIENT_ID")
body=$(echo "$res" | head -n -1)
code=$(echo "$res" | tail -n1)
if [ "$code" -ge 400 ]; then
echo "Request failed ($code): $body" >&2
exit 1
fiRetry and backoff
- Retry only 5xx responses and network/timeout errors, a 400 or 403 will not change on retry, it needs a code fix.
- Use exponential backoff with jitter, for example
2^attempt * 250ms, capped at 5–6 attempts. - For POST actions, only retry after confirming the first attempt did not actually run, check
datafor a created record before firing again, since retries are not deduplicated server-side. - Set a client-side timeout (10–30s) on generation actions; they can take longer than simple reads.
Building a resilient integration
- Page with
offsetuntilhas_moreis false; do not assume one page holds everything. - Retry 500s with exponential backoff. A 400 or 403 means the request itself is wrong, fix the request before sending it again.
- Treat generation actions as expensive: queue them, and do not fire them in tight loops.
- Store the client IDs you resolved rather than listing clients on every run.
- Log the
errorstring verbatim; it is written to be actionable.
Action responses pass through
A POST returns the underlying result in data, with status and status_code reflecting whether the underlying work succeeded. Check both.
FAQ
Why did I get a 400 even though my JSON looks valid?
The 400 usually means an order or filter_field value outside the whitelist, or a missing required field for the action or resource. Read the error string, it lists the allowed values so you can fix the request without guessing.
Why do I get 403 on a client I can see in the app?
The client must be linked to your agency and your key must have the matching scope (read for GET, write for POST). If both look right, the key may have been created before the client was linked, regenerate the key or re-check its scopes.
Is there a hard rate limit?
There is no published fixed request-per-second number, but generation actions are inherently rate-limited by the underlying AI and data providers. Treat 500s and slow responses under load as a signal to back off, and avoid firing actions in tight loops.
Do failed actions still consume credits?
No, status: "error" on a POST means the underlying work did not complete, so it is not billed as a successful generation. Always check status in the body, not just the HTTP status code, since a 200 can still carry status: "error" from the underlying provider.
How do I avoid creating duplicate content if a request times out?
There is no idempotency key on this API. Before retrying a generation action, check whether the record already exists (for example, query blogs filtered by the keyword or category) rather than assuming the timeout meant nothing happened.
What should I do with a persistent 500?
Retry a handful of times with exponential backoff. If it keeps failing, capture the response body and timestamp and report it, a lasting 500 is a platform issue, not a request problem.