API

Errors, limits and reliability

Status codes, error bodies and how to build an integration that survives them.

Status codes

CodeMeaningWhat to do
200Success-
400Missing or invalid parameterRead error; it names what is wrong and lists valid values
401Invalid, missing or expired API keyCheck the header format and the key's expiry
403Scope or client access deniedConfirm the key's scopes and that the client is linked to your agency
405Wrong methodUse GET to read and POST to act
500Server errorRetry with backoff; if it persists, report it with the timestamp
Error body
{ "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

bash
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
fi

Retry 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 data for 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

  1. Page with offset until has_more is false; do not assume one page holds everything.
  2. Retry 500s with exponential backoff. A 400 or 403 means the request itself is wrong, fix the request before sending it again.
  3. Treat generation actions as expensive: queue them, and do not fire them in tight loops.
  4. Store the client IDs you resolved rather than listing clients on every run.
  5. Log the error string 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.

Was this page helpful?