Response Schema
The unified SocialCrawl response envelope, headers, and partial-data warnings
Response Schema
Every SocialCrawl response — success or error — uses the same envelope. Write one parser, handle every platform.
Successful Response
{
"success": true,
"platform": "tiktok",
"endpoint": "/v1/tiktok/profile",
"data": {
"author": { "username": "charlidamelio", "followers": 156800000 },
"computed": {
"engagement_rate": 0.082,
"language": "en",
"content_category": "entertainment",
"estimated_reach": 12857600
}
},
"credits_used": 1,
"credits_remaining": 4999,
"request_id": "req-XXXXX",
"cached": false
}Envelope Fields
| Field | Type | Description |
|---|---|---|
success | boolean | true for successful responses, false for errors |
platform | string | Platform identifier (tiktok, instagram, etc.) — meta for account endpoints like /v1/credits/balance |
endpoint | string | The full endpoint path that was called |
data | object | Platform-specific, normalised payload. Lists are returned as { items, next_cursor?, total? } |
credits_used | integer | Credits consumed by this request (0 on cache hits and idempotent replays) |
credits_remaining | integer | Your balance after this request |
request_id | string | Unique identifier (req-XXXXX) for debugging and log lookup |
cached | boolean | true when served from cache — cache hits cost 0 credits |
data._warnings[] — Partial-data channel
When the field-map or computed-field pipeline hits ambiguous upstream data, it attaches a human-readable notice to data._warnings: string[]:
{
"data": {
"author": { "username": "..." },
"computed": { "engagement_rate": 1.0 },
"_warnings": ["engagement_rate clamped from 1.42 to 1.0"]
}
}Treat entries as advisory — the response is still valid. Empty arrays are omitted from the envelope, so _warnings is only present when there is something to report.
Error Response
{
"success": false,
"error": {
"type": "INSUFFICIENT_CREDITS",
"message": "Your account has 0 credits remaining. This endpoint requires 1 credits.",
"status": 402,
"doc_url": "https://www.socialcrawl.dev/docs/errors/insufficient-credits"
},
"credits_remaining": 0,
"request_id": "req-abc123"
}See Error Handling for the full error-code table and refund rules.
Response Headers
| Header | Value |
|---|---|
X-Request-Id | Matches request_id in the body — use it to correlate logs |
X-Credits-Used | Credits consumed (0 on cache hits, empty-upstream 404s, 405/409/422, and idempotent replays) |
X-Credits-Remaining | Balance after this request |
X-Cache | HIT or MISS |
X-Idempotent-Replay | "true" on idempotent replays (only present when the response was replayed). See Idempotent requests |
Retry-After | "30" (seconds) — only on 503 circuit-breaker responses |
Allow | "GET" — only on 405 METHOD_NOT_ALLOWED responses |
List endpoints
List archetypes (PostList, CommentList, SearchResult) are normalised to a consistent shape regardless of upstream key names:
{
"data": {
"items": [
/* ... */
],
"next_cursor": "eyJwYWdlIjoyfQ==",
"total": 1247
}
}next_cursor and total are only included when upstream provides them. Pagination semantics match upstream — pass next_cursor as a query parameter where supported.
Idempotent requests
Any /v1/* request can be made safely retriable by sending an Idempotency-Key header (UUIDv4 recommended):
GET /v1/tiktok/profile?handle=charlidamelio HTTP/1.1
x-api-key: sc_...
Idempotency-Key: 7a5e1b4c-2d8f-4a3b-9c1e-6e8b4d2a1f3cReplayed calls return the original response verbatim, deduct 0 new credits, and add X-Idempotent-Replay: true. Keys are scoped per account with a 24-hour TTL. See the Error Handling page for the 409/422 outcomes when a key is reused incorrectly.
