InsightSocial API

Errors

Every InsightSocial API error type with its status, what to do about it, and copy-paste retry loops.

Every failure returns the same error body, not the success envelope: success: false, an error object with a type to branch on, a readable message and, when one parameter is at fault, param, plus the usual request_id and credit fields. A failed call is never charged.

Response
{
  "success": false,
  "error": {
    "type": "INSUFFICIENT_CREDITS",
    "message": "This call needs up to 170 credits and 120 remain. Top up at https://www.insightsocial.app/pricing"
  },
  "request_id": "req_1a2b3c4d5e6f",
  "credits_used": 0,
  "credits_remaining": 120
}
  • error.type is what your code should branch on.
  • error.param names the query parameter at fault, when there is one (for example cursor on a cursor error). It is absent otherwise.
  • error.message explains the failure in a sentence and often names what to change. Show it or log it, but do not parse it.
  • credits_used is 0 on every error.
  • credits_remaining is your balance when we know it, and null when we do not (authentication failures, for example).
  • request_id matches the X-Request-Id header. Include it when you contact support.

That is the whole error body. It carries no schema_version, data or unavailable, so check success before reading anything else.

Refusals made before a call reaches a platform (UNSUPPORTED_PARAMETER, CURSOR_INVALID, CURSOR_EXPIRED, authentication, rate-limit and idempotency errors, INSUFFICIENT_CREDITS) do not appear in the dashboard's Activity Log. Other errors, including the 400 parameter errors a platform returns, do.

Error types

error.typeStatusRetry?What it means
MISSING_API_KEY401NoNo x-api-key header on the request
INVALID_API_KEY401NoThe value is not an InsightSocial key, or no key matches it
API_KEY_REVOKED401NoThe key has been revoked
INSUFFICIENT_CREDITS402NoYour balance is below what this call needs to hold
UNKNOWN_PLATFORM404NoThe first path segment is not one of the platforms we serve
UNKNOWN_ENDPOINT404NoThe platform exists but that path does not
RESOURCE_NOT_FOUND404NoNothing exists at the identifier you sent
METHOD_NOT_SUPPORTED405NoEvery endpoint is a GET: any other method, and the three POST endpoints in the catalogue, answer 405
UNSUPPORTED_PARAMETER400NoA parameter this endpoint does not have, or one that asks for analysis schema 2 does not carry. error.param names it
CURSOR_INVALID400NoThe cursor was not issued by this API, was edited, or belongs to a different request
CURSOR_EXPIRED400NoThe cursor is more than 24 hours old
IDEMPOTENCY_IN_PROGRESS409Yes, after Retry-AfterA call with the same Idempotency-Key is still running
IDEMPOTENCY_KEY_REUSED409NoThe Idempotency-Key was already used for a different request
IDEMPOTENCY_REPLAY_UNAVAILABLE409NoThe original call succeeded, but its response is too large to replay
RATE_LIMITED429Yes, after Retry-AfterMore than 60 requests in 60 seconds on this key
CONCURRENCY_LIMIT429Yes, after Retry-AfterMore than 10 requests in flight on this key
CLIENT_CLOSED_REQUEST499Your callYour client disconnected before the response
INTERNAL_ERROR500Yes, with backoffSomething went wrong on our side
SERVICE_UNAVAILABLE503Yes, after Retry-After or backoffWe could not complete the call right now
UPSTREAM_ERROR (or the platform's own type)503Yes, after Retry-AfterThe platform did not answer in time
UPSTREAM_INVALID503Yes, after Retry-AfterThe platform answered with something we could not read
ENDPOINT_UNAVAILABLE503Not soon: Retry-After is an hourThis endpoint is switched off while its data source is broken
Parameter errors, such as INVALID_REQUEST or BAD_REQUEST400 (or another 4xx)NoA parameter is missing, invalid, or not accepted by this endpoint

Parameter errors can carry different types

When a request is rejected because of its parameters, the error.type is not drawn from a fixed list: you will usually see INVALID_REQUEST or BAD_REQUEST, but other values occur. Treat any 4xx you do not recognise as "fix the request", and read error.message, which says what was wrong.

Which errors to retry

Retry only RATE_LIMITED, CONCURRENCY_LIMIT, IDEMPOTENCY_IN_PROGRESS, SERVICE_UNAVAILABLE, UPSTREAM_ERROR, UPSTREAM_INVALID and INTERNAL_ERROR, plus any 429, 500 or 503 whatever its error.type: when a platform fails, the 503 can carry that platform's own error type. A 409 is retryable only when its type is IDEMPOTENCY_IN_PROGRESS. Everything else is deterministic: the same request fails the same way until you change the request, the key or your balance.

When a response carries Retry-After, wait at least that many seconds. Otherwise back off exponentially with jitter, and give up after a few attempts.

Error reference

MISSING_API_KEY

401. No x-api-key header reached the API. Send the header, and if you already do, make sure nothing between you and the API, such as a proxy or gateway, removes it. A key sent in Authorization is not read and also produces this error. See Authentication.

INVALID_API_KEY

401. Either the value does not look like an InsightSocial key (keys start isk_live_ or isk_test_), or it looks right but matches no key. Copy it again from API keys.

API_KEY_REVOKED

401. The key was revoked in the dashboard. Create a new one in the dashboard.

INSUFFICIENT_CREDITS

402. Before a call runs, we hold the most it can cost. If your balance is below that amount, the call is refused and nothing is charged. credits_remaining shows your balance, and the message states both numbers.

For a metered endpoint, the amount held is the most the call can cost with the parameters you sent, and on endpoints that accept max_pages it is multiplied by the number of pages. You can therefore get a 402 on a call that would have cost less in the end. A smaller limit, fewer include joins or fewer pages hold less; dry_run=1 shows the hold for free. Top up on the pricing page; retrying without a top-up fails the same way.

UNKNOWN_PLATFORM

404. The platform segment of the path is not one we serve. The 25 platforms are instagram, tiktok, facebook, linkedin, twitter, threads, youtube, reddit, pinterest, bluesky, truthsocial, snapchat, telegram, twitch, kick, rumble, kwai, douyin, xiaohongshu, quora, tiktokshop, weibo, zhihu, substack and nextdoor.

UNKNOWN_ENDPOINT

404. The path is not in the catalogue. Check it against GET /v1/endpoints or the API reference.

RESOURCE_NOT_FOUND

404. The endpoint exists, but nothing is there for the identifier you sent: a handle that does not exist, a deleted post, and so on. You are not charged. Retrying the same identifier returns the same answer, so record it and move on.

INVALID_REQUEST for a missing parameter

A required parameter left out is refused before anything is fetched: 400 INVALID_REQUEST, with error.param naming it and a message such as "url is required on this endpoint". Nothing is charged.

METHOD_NOT_SUPPORTED

405. This path is in the catalogue but cannot be called through the API. Pick another endpoint.

UNSUPPORTED_PARAMETER

400. You sent a parameter this endpoint does not have (a typo, or one that belongs to another endpoint), or one that asks for analysis: labels, relevance scoring, fit or brand judgments. Both are refused instead of being ignored, which would return unfiltered rows and still charge for them. error.param names the parameter; the endpoint's parameters are in GET /v1/endpoints. Nothing is charged.

Response
{
  "success": false,
  "error": {
    "type": "UNSUPPORTED_PARAMETER",
    "message": "`relevance` is not supported: it asks for analysis, which is not part of schema 2. Remove it and retry. Nothing was charged.",
    "param": "relevance"
  },
  "request_id": "req_80d197121a1e",
  "credits_used": 0,
  "credits_remaining": null
}

The refused parameters are label, label_evidence, relevance, relevance_threshold, relevant_to, judgments, fit, goal, fit_tokens, seen, brand, brand_description, offer, exclude (except on /v1/pinterest/trends, where it filters terms), brief, use, moments, and the value format=stationery.

Two more are refused on specific endpoints only, where they ask for analysis; elsewhere they are ordinary parameters:

ParameterRefused onWhat it asked for
q/v1/tiktok/post/transcript, /v1/youtube/video/transcriptA question answered about the video's transcript. On search endpoints q is the search query and works as before.
switch_from/v1/twitter/search/tweets, /v1/reddit/search/commentsPosts about switching away from a named brand.

Only the first refused parameter in your query is reported, so remove it and check the next. To filter rows by topic or language, do it on your side after the call; see Schema 2.

CURSOR_INVALID

400. The cursor cannot be used for this request. Either it was not issued by this API (a cursor from the previous schema starts is. or is2.), it was edited or truncated, it was sent under a name other than cursor, or it belongs to a different request: another endpoint, or the same endpoint with different parameters. error.param names the parameter that carried it. Nothing is charged.

Send pagination.next_cursor back unchanged, as cursor, with the same parameters as the first page. Only limit, max_pages, dry_run and fresh may change between pages. Otherwise start again without a cursor. See Pagination.

CURSOR_EXPIRED

400. The cursor is more than 24 hours old. Start the walk again without a cursor. Nothing is charged.

IDEMPOTENCY_IN_PROGRESS

409. An earlier call with the same Idempotency-Key has not finished. Wait for Retry-After, then send the same request with the same key. Once the original has finished, you get its result as a free replay, unless the original never completed (see below).

IDEMPOTENCY_KEY_REUSED

409. The Idempotency-Key was already used for a different request: another endpoint or other parameters. Use a new key. Nothing is charged.

IDEMPOTENCY_REPLAY_UNAVAILABLE

409. The original call with this Idempotency-Key succeeded, but its response is too large for us to replay. Send the request again with a new key to fetch it. Nothing is charged.

RATE_LIMITED

429. This key sent more than 60 requests in a sliding 60-second window. Retry-After is the number of seconds until the oldest request leaves the window. Nothing is charged. See Rate limits.

CONCURRENCY_LIMIT

429. This key already had 10 requests in flight. Retry-After is 1, since a slot frees as soon as any open request returns. Shrink your worker pool.

CLIENT_CLOSED_REQUEST

499. Your client closed the connection before we answered. You only see this in logs, since nobody was listening for the response. Give slow endpoints a generous client timeout.

INTERNAL_ERROR

500. An unexpected error on our side. Nothing was charged. Retry with backoff, and if it keeps happening, contact support with the request_id.

SERVICE_UNAVAILABLE

503. We could not complete the call right now. Causes include being unable to verify your key or read your balance for a moment, or temporarily running out of capacity. Nothing was charged. When Retry-After is present (often 30), wait that long; otherwise retry with backoff.

UPSTREAM_ERROR

503. The platform did not answer, even after our own retries and a second data source where one exists. Nothing was charged. Retry-After is at least 30, longer when the platform asked for more.

UPSTREAM_INVALID

503. The platform answered, but with something that does not fit the response schema, so we did not serve it. A page whose rows all lack an id is also refused this way, rather than charged as an empty page. Nothing was charged. Retry-After is 30. If it repeats on the same input, contact support with the request_id.

ENDPOINT_UNAVAILABLE

503. The endpoint exists but is switched off, because its data source stopped returning data for every input. It is left out of GET /v1/endpoints and the API reference until it works again. Nothing was charged. Retry-After is 3600: retrying sooner gets the same answer, so a generic retry loop should honour it or stop. We check these endpoints daily and put them back as soon as they answer.

Parameter errors

400, or another 4xx. A required parameter is missing, a value is in the wrong format, or the endpoint does not accept a parameter you sent. The message says what was rejected and usually names the parameter to fix. Check the endpoint's parameters on its API reference page or in GET /v1/endpoints. Nothing is charged.

Idempotency

Send an Idempotency-Key header, a fresh UUID per logical operation, to make any call safe to retry after a timeout or a dropped connection.

  • A retry with the same key returns the original result with idempotent_replay: true, charge_reason: "replay" and credits_used: 0.
  • A retry that arrives while the original is still running gets 409 IDEMPOTENCY_IN_PROGRESS. Wait for Retry-After and try again with the same key.
  • A key reused for a different request, or across schemas, gets 409 IDEMPOTENCY_KEY_REUSED. Use a new key.
  • Keys are scoped to your account.
  • A key longer than 255 characters, or with characters other than letters, digits, ., _, : and -, is ignored. The call then runs normally, with no replay protection.
  • If we never answered the original successfully (for example your client disconnected before it finished), the retry that delivers the data is charged as a normal call (charge_reason: "miss") at exactly the ceiling the call reserved: the listed price, or the top of the range for a metered endpoint, multiplied by max_pages if you sent it. Like any charged call, it can be covered by one of your free calls. It costs 0 if the replay returns nothing.

What is never charged

Every error on this page costs 0 credits, including a request refused for an unsupported parameter or a bad cursor. So do empty results, dry_run=1 calls and replays of a call we already answered. API credits are non-refundable, and a call that fails is simply never charged. See Credits.

Retry loops

Each loop retries only the transient statuses (429, 500, 503, and 409 when the type is IDEMPOTENCY_IN_PROGRESS), honors Retry-After when it is sent, otherwise backs off exponentially with jitter, and stops after five retries.

cURL
#!/usr/bin/env bash
url="https://api.insightsocial.app/v1/tiktok/profile?handle=khaby.lame"
max_retries=5
attempt=0

while :; do
  body=$(mktemp); headers=$(mktemp)
  status=$(curl -s -o "$body" -D "$headers" -w '%{http_code}' \
    -H "x-api-key: $INSIGHTSOCIAL_API_KEY" "$url")

  if [ "$status" -lt 400 ]; then
    cat "$body"; rm -f "$body" "$headers"; break
  fi

  retry_409=false
  if [ "$status" = "409" ] && grep -q '"IDEMPOTENCY_IN_PROGRESS"' "$body"; then retry_409=true; fi
  case "$status" in
    429|500|503) ;;
    409) $retry_409 || { echo "Not retryable: 409"; cat "$body"; rm -f "$body" "$headers"; exit 1; } ;;
    *) echo "Not retryable: $status"; cat "$body"; rm -f "$body" "$headers"; exit 1 ;;
  esac

  attempt=$((attempt + 1))
  if [ "$attempt" -gt "$max_retries" ]; then
    echo "Giving up after $max_retries retries (last status $status)"
    rm -f "$body" "$headers"; exit 1
  fi

  wait_s=$(grep -i '^retry-after:' "$headers" | tr -d '\r' | awk '{print $2}')
  if [ -z "$wait_s" ]; then
    wait_s=$(awk "BEGIN{srand(); print (2 ^ $attempt) * (0.5 + rand() / 2)}")
  fi
  rm -f "$body" "$headers"
  sleep "$wait_s"
done

Debugging tips

  • Log request_id (also sent as X-Request-Id) with every failure, so support can trace the exact call.
  • A 503 on an input that worked before is usually temporary. Retry after Retry-After.
  • A 400 that names error.param tells you exactly which parameter to remove or fix.
  • Some calls take a while to answer. Set a client timeout of a minute or more on heavy endpoints rather than aborting early.

Next steps

On this page