Errors
Error envelopes, request IDs, outcome handling, and common retry decisions
Social Fetch uses two response shapes: { data, meta } for successes and { error } for failures. HTTP 200 can still carry not_found or private inside data — check both the status code and the outcome fields.
Success envelope
Successful JSON responses use a { data, meta } envelope.
data— endpoint-specific payloadmeta— response metadata, including a support-friendly request ID
Example (200):
{
"data": {
"lookupStatus": "found",
"profile": {
"platform": "tiktok",
"handle": "charlidamelio",
"displayName": "charli",
"bio": "hey",
"avatarUrl": "https://example.com/avatar-large.jpg",
"verified": true,
"profileUrl": "https://www.tiktok.com/@charlidamelio",
"privateAccount": false
},
"metrics": {
"followers": 150000000,
"following": 123,
"likes": 12345678901,
"posts": 456
}
},
"meta": {
"requestId": "req_01example",
"creditsCharged": 1,
"version": "v1"
}
}The exact data shape varies by endpoint — see the operation's 200 schema in the API reference.
Outcome semantics
Some endpoints report domain outcomes inside a 200 rather than as a 4xx. Example — profile lookupStatus: "not_found":
{
"data": {
"lookupStatus": "not_found",
"profile": null,
"metrics": null
},
"meta": {
"requestId": "req_01example",
"creditsCharged": 1,
"version": "v1"
}
}Instagram post lookup returns lookupStatus: "restricted" when the URL is valid but the media isn't publicly accessible (for example, age-gated):
{
"data": {
"lookupStatus": "restricted",
"post": null,
"owner": null,
"metrics": null,
"media": null,
"downloads": []
},
"meta": {
"requestId": "req_01example",
"creditsCharged": 1,
"version": "v1"
}
}Rule of thumb:
- HTTP
200— parse the success envelope and check outcome fields (likedata.lookupStatus). - Non-
200— parse the error envelope below.
Outcome values
found— target resolved; expected data is present.not_found— target doesn't exist or couldn't be resolved.private— target exists, but data isn't public.restricted— target reachable but can't be returned (age-gated posts, bot-protected pages, etc.).
Web extraction routes (GET /v1/web/markdown, /html, and /ask) return lookupStatus: "restricted" with HTTP 200 when a page can't be fetched because of access protection. Content fields (markdown, html, answer) come back null. Don't retry these as transient failures.
Confirm the exact response shape on the endpoint page in the API reference.
Empty result vs. not found
An empty collection doesn't always mean "not found." It can mean the profile has no media, the target is private, a post is restricted, or the target is missing. Keep these cases distinct.
Disambiguating list routes
Some list routes return HTTP 200 with an empty collection for more than one reason and don't expose data.lookupStatus. When that distinction matters:
- Call the platform profile route for the same handle (
GET /v1/{platform}/profiles/{handle}). - Read
data.lookupStatusfrom that response. - Call the list route only if you still need feed items.
If you only need "posts or nothing," skip the profile preflight.
Client logic
- Check the HTTP status.
- On
200, inspect outcome fields. - Fall into error handling only on non-
200.
With the TypeScript SDK, that maps to result.ok and result.value.data.
Credits and outcomes
Metered endpoints can still charge when a lookup completes — including not_found, private, or restricted. See Credits.
Error body
Error responses use a shared { error } envelope:
{
"error": {
"code": "unauthorized",
"message": "Missing API key.",
"requestId": "req_01example"
}
}error.code
error.code is machine-readable. Stable values:
bad_requestunauthorizedinsufficient_creditspayment_requiredpayment_settlement_failedlookup_failedtranscript_target_not_videovideo_too_long_for_transcriptiontemporarily_unavailableinternal_error
Check the API reference for the exact codes each route returns per HTTP status (for example 400, 401, 402, 502, 503).
Request ID
Every response carries a request ID — meta.requestId on success, error.requestId on failure. Log it on failures and quote it in support requests.
Status codes at a glance
Retrying safely
On 503, honor Retry-After when present; otherwise use exponential backoff. Don't blindly retry 4xx errors — fix the request first.
HTTP 402 has credits, x402 challenge, and settle-failure meanings — classify before retrying.
400bad_request— invalid request, or a known limitation such astranscript_target_not_videoorvideo_too_long_for_transcription.401unauthorized— missing or invalid API key.402— three related meanings: (1) JSONinsufficient_creditswhen using an API key without enough credits (optionalcheckoutUrl); (2) x402 payment required when no API key is sent — JSONpayment_requiredplus thePAYMENT-REQUIREDheader; (3) JSONpayment_settlement_failedwhen payment verified and the handler succeeded but USDC settle failed (resource body withheld). See x402. Do not treat every402as credits exhaustion.429temporarily_unavailable— free routes only (whoami,balance); per-key rate limit. Paid metered saturation uses503, not429.500internal_error— unexpected server error.502lookup_failed— the lookup couldn't be completed.503temporarily_unavailable— service briefly unavailable (including queue/capacity saturation under extreme concurrency). Safe to retry; honorRetry-Afterwhen present. Not charged on metered lookup routes — see Credits.