Docs menu

Errors

A failed request returns the failure envelope and charges nothing:

{
  "ok": false,
  "error": { "code": "upstream_blocked", "message": "The platform blocked this fetch; retry (a fresh exit is used).", "retryable": true },
  "credits_charged": 0,
  "request_id": "req_0123456789abcdef01234567"
}

Branch on error.code and error.retryable. Messages are for people and can change; codes are stable. There are 21 codes, each with one HTTP status.

Mistakes in the request#

CodeHTTPRetryMeaning
invalid_params400noA parameter is missing, unknown or has the wrong type.
unsupported_url400noThe URL is not one this endpoint accepts (wrong platform or form).
unauthorized401noThe x-api-key header is missing or not a valid key.
insufficient_credits402noThe team behind the key has too few credits for this request.
forbidden403noThe key or team is suspended or revoked.
rate_limited429yesToo many requests for this team's plan; wait for Retry-After.
conflict409noThis Idempotency-Key was already used with a different request.

The thing you asked for#

CodeHTTPRetryMeaning
not_found404noThe platform says this profile, post or item does not exist.
private403noThe content is private; only public, logged-out data is served.
age_restricted403noThe platform hides this content from logged-out visitors (age gate).
removed410noThe content existed but was deleted or taken down.
unavailable_in_region451noThe platform does not serve this content in the requested region.
transcript_unavailable404noNo captions exist and AI transcription is not possible for this media.

The platform failed#

CodeHTTPRetryMeaning
upstream_rate_limited503yesThe platform is rate limiting us; retry shortly.
upstream_blocked503yesThe platform blocked this fetch; retry (a fresh exit is used).
upstream_error502yesThe platform returned an error or the connection failed.
upstream_changed502noThe platform's response no longer parses; we are fixing it.
upstream_timeout504yesThe platform did not answer in time.

Our side#

CodeHTTPRetryMeaning
overloaded503yesThis endpoint's queue is full; retry with backoff.
not_implemented501noThis endpoint is declared but not built yet.
internal500yesSomething broke on our side; it is logged.

Retrying#

Retry when retryable is true: wait for the retry-after header if present, otherwise back off exponentially with some jitter. Do not retry the rest; the same request will fail the same way.

import random
import time

import requests


def get(url, headers, params, attempts=5):
    for attempt in range(attempts):
        res = requests.get(url, headers=headers, params=params, timeout=60)
        body = res.json()
        if body["ok"] or not body["error"]["retryable"]:
            return body
        wait = float(res.headers.get("retry-after", 2 ** attempt))
        time.sleep(wait + random.random())
    return body
async function get(url: string, headers: Record<string, string>, attempts = 5) {
  let body: any;
  for (let attempt = 0; attempt < attempts; attempt++) {
    const res = await fetch(url, { headers });
    body = await res.json();
    if (body.ok || !body.error.retryable) return body;
    const wait = Number(res.headers.get("retry-after") ?? 2 ** attempt);
    await new Promise((r) => setTimeout(r, (wait + Math.random()) * 1000));
  }
  return body;
}

Retrying a failure costs nothing. Retrying a POST that may have succeeded needs an Idempotency-Key; see Batch and jobs.

Where to look first#

  • not_found, private, removed: the item is not available to a logged-out visitor. Check the URL or handle in a browser, signed out.
  • unsupported_url: you passed a URL from the wrong platform or an unrecognised form. The endpoint page lists the accepted hosts.
  • upstream_changed: the platform changed and our parser no longer reads it. We are alerted automatically and fix it; it is not retryable until we do.
  • invalid_params: the message names the parameter.

When you write to support, include the request_id.