Errors
Error envelopes, request IDs, outcome handling, and common retry decisions
Social Fetch uses two response shapes: a { data, meta } envelope for successes and an { error } envelope for failures. The catch most integrations miss is that a successful HTTP 200 can still carry a "not found" or "private" outcome inside data — so check both the status code and the outcome fields.
Success envelope
Successful JSON responses are wrapped in a { data, meta } envelope.
data— the endpoint-specific payloadmeta— response metadata, including a support-friendly request ID
Example (200 success):
{
"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 — check the operation's 200 schema in the API reference.
Outcome semantics
Some endpoints report domain outcomes inside a 200 response rather than as a 4xx error. For example, a profile lookup returns lookupStatus: "not_found" with HTTP 200:
{
"data": {
"lookupStatus": "not_found",
"profile": null,
"metrics": null
},
"meta": {
"requestId": "req_01example",
"creditsCharged": 1,
"version": "v1"
}
}A single Instagram post lookup returns lookupStatus: "restricted" when the URL is valid but the media isn't publicly accessible (for example, age-gated posts):
{
"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 the endpoint's outcome fields (likedata.lookupStatus). - Non-
200— parse the standard error envelope below.
Outcome values
Depending on the endpoint, a successful response can represent any of these outcomes:
found— the target was resolved and the expected data is present.not_found— the target doesn't exist or couldn't be resolved.private— the target exists, but its data isn't public.restricted— the target is reachable but can't be returned (for example, age-gated posts and reels, or pages behind bot protection).
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. The content fields (markdown, html, answer) come back null. These aren't transient failures — don't retry them.
Always 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." A response can be empty because:
- the profile exists but currently has no media,
- the target is valid but private,
- a post or reel URL is valid but
restricted, or - the target is genuinely missing.
Keep these cases distinct in your client instead of collapsing every miss into one.
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.lookupStatus(found,private, ornot_found) from that response. - Call the list route only if you still need feed items.
If you only need "posts or nothing," skip the profile preflight and accept the ambiguity.
Client logic
- Check the HTTP status.
- On
200, inspect the endpoint's outcome fields. - Only fall into your error-handling path on non-
200responses.
With the TypeScript SDK, the same steps map to result.ok and result.value.data.
Credits and outcomes
Metered endpoints can still charge credits when the lookup completes successfully — even if the outcome is not_found, private, or restricted. See Credits for the billing details.
Error body
Error responses return JSON with a shared { error } envelope:
{
"error": {
"code": "unauthorized",
"message": "Missing API key.",
"requestId": "req_01example"
}
}error.code
error.code is machine-readable and comes from a stable set of values:
bad_requestunauthorizedinsufficient_creditslookup_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 in your client and quote it when contacting support; it ties your trace to our server logs.
Status codes at a glance
Retrying safely
Retry 503 with exponential backoff. Don't blindly retry 4xx errors — fix the request first.
400bad_request— invalid request, or a known limitation such astranscript_target_not_videoorvideo_too_long_for_transcription.401unauthorized— missing or invalid API key.402insufficient_credits— not enough credits for that route.500internal_error— unexpected server error.502lookup_failed— the lookup couldn't be completed.503temporarily_unavailable— service briefly unavailable; safe to retry with backoff.