Utility API Quickstart API
Returns everything needed for a first call: how to authenticate, the base URL, the response shape, credit billing, error codes, rate limits, and a sample.
GET /v1/utility/quickstartLast updated November 2026Maintained by the SocialCrawl team
When to use the Utility API Quickstart API
Use it when you are setting up for the first time and want the rules of the API in one response. Free to call.
From the API reference
Everything needed for a first successful API call in one response: authentication, base URL, the response envelope, the credit billing model, the error taxonomy, rate limits, pagination rules, and a copy-paste first request. Pass platform to tailor the first-call example. Free to call.
Searching 69 platforms in parallel
What can you do with the API Quickstart API?
The API Quickstart endpoint gives you structured Utility data with computed fields in a single request. No scraping infrastructure to build or maintain.
Example Request
# GET /v1/utility/quickstart: Free: 0 credits per call.
# --max-time 10: this endpoint's measured p99 latency x 1.5.
# --retry 3: retries timeouts, 429 and 5xx, honoring Retry-After.
# -o response.json keeps only the final attempt's body.
# One Idempotency-Key per request, reused on every retry, so a retried call is never charged twice.
IDEMPOTENCY_KEY=$(od -An -N16 -tx1 /dev/urandom | tr -d ' \n')
curl -sS --max-time 10 --retry 3 -o response.json \
-H "x-api-key: YOUR_API_KEY" \
-H "Idempotency-Key: $IDEMPOTENCY_KEY" \
"https://www.socialcrawl.dev/v1/utility/quickstart?platform=tiktok" && cat response.json# GET /v1/utility/quickstart: Free: 0 credits per call.
import os
import random
import time
import uuid
import requests
API_KEY = os.environ.get("SOCIALCRAWL_API_KEY", "YOUR_API_KEY")
TIMEOUT_S = 10 # this endpoint's measured p99 latency x 1.5.
MAX_RETRIES = 3
URL = "https://www.socialcrawl.dev/v1/utility/quickstart"
def backoff(attempt):
# Exponential backoff with jitter: about 1 s, 2 s, then 4 s.
return 2 ** attempt * (0.5 + random.random() / 2)
def socialcrawl(params):
# One Idempotency-Key per request, reused on every retry, so a retried call is never charged twice.
idempotency_key = str(uuid.uuid4())
for attempt in range(MAX_RETRIES + 1):
try:
res = requests.get(
URL,
params=params,
headers={"x-api-key": API_KEY, "Idempotency-Key": idempotency_key},
timeout=TIMEOUT_S,
)
body = res.json()
except (requests.RequestException, ValueError):
# A timeout, a dropped connection or a non-JSON gateway page: retry with the same key.
if attempt == MAX_RETRIES:
raise
time.sleep(backoff(attempt))
continue
if body["success"]:
return body
error = body["error"]
# Branch on error["type"], never on the message text.
if error["type"] == "RESOURCE_NOT_FOUND":
return None # refunded: nothing to read
retry_after = res.headers.get("Retry-After")
# SERVICE_UNAVAILABLE without Retry-After is a withdrawn endpoint: permanent.
permanent = error["type"] == "SERVICE_UNAVAILABLE" and retry_after is None
if not error.get("retryable") or permanent or attempt == MAX_RETRIES:
raise RuntimeError(f"{error['type']}: {error['message']} (request_id {body['request_id']})")
# Retry-After (seconds) wins; otherwise back off.
time.sleep(float(retry_after) if retry_after else backoff(attempt))
params = {
"platform": "tiktok",
}
body = socialcrawl(params)
if body is not None:
print(body["data"])// GET /v1/utility/quickstart: Free: 0 credits per call.
const API_KEY = process.env.SOCIALCRAWL_API_KEY ?? "YOUR_API_KEY";
const TIMEOUT_MS = 10_000; // this endpoint's measured p99 latency x 1.5.
const MAX_RETRIES = 3;
type Page = { next_cursor: string | null; has_more: boolean };
type SocialCrawlResponse =
| { success: true; data: any; pagination?: Page; credits_used: number; request_id: string }
| { success: false; error: { type: string; message: string; retryable: boolean }; request_id: string };
const sleep = (ms: number) => new Promise((resolve) => setTimeout(resolve, ms));
// Exponential backoff with jitter: about 1 s, 2 s, then 4 s.
const backoffMs = (attempt: number) => 2 ** attempt * 1000 * (0.5 + Math.random() / 2);
async function socialcrawl(url: URL) {
// One Idempotency-Key per request, reused on every retry, so a retried call is never charged twice.
const idempotencyKey = crypto.randomUUID();
for (let attempt = 0; ; attempt++) {
let res: Response;
let body: SocialCrawlResponse;
try {
res = await fetch(url, {
headers: {
"x-api-key": API_KEY,
"Idempotency-Key": idempotencyKey,
},
signal: AbortSignal.timeout(TIMEOUT_MS),
});
body = (await res.json()) as SocialCrawlResponse;
} catch (error) {
// A timeout, a dropped connection or a non-JSON gateway page: retry with the same key.
if (attempt >= MAX_RETRIES) throw error;
await sleep(backoffMs(attempt));
continue;
}
if (body.success) return body;
// Branch on error.type, never on the message text.
if (body.error.type === "RESOURCE_NOT_FOUND") return null; // refunded: nothing to read
const retryAfter = res.headers.get("Retry-After");
// SERVICE_UNAVAILABLE without Retry-After is a withdrawn endpoint: permanent.
const permanent = body.error.type === "SERVICE_UNAVAILABLE" && retryAfter === null;
if (!body.error.retryable || permanent || attempt >= MAX_RETRIES) {
throw new Error(`${body.error.type}: ${body.error.message} (request_id ${body.request_id})`);
}
// Retry-After (seconds) wins; otherwise back off.
await sleep(retryAfter ? Number(retryAfter) * 1000 : backoffMs(attempt));
}
}
const url = new URL("https://www.socialcrawl.dev/v1/utility/quickstart");
url.searchParams.set("platform", "tiktok");
const body = await socialcrawl(url);
if (body) console.log(body.data);Parameters
| Parameter | Required | Description |
|---|---|---|
| platform | No | Tailor the first-call example and links to one platform slug |
What does the Utility API Quickstart API return?
This synthetic fixture shows the documented response shape and fields. Values are illustrative; this is not a live API response.
Example response
{
"success": true,
"platform": "utility",
"endpoint": "/v1/utility/quickstart",
"data": {
"kind": "quickstart",
"name": "SocialCrawl API",
"base_url": "https://www.socialcrawl.dev/v1",
"auth": {
"type": "api_key",
"header": "x-api-key",
"also_accepted": "Authorization: Bearer <key>",
"get_key_url": "https://www.socialcrawl.dev/dashboard/api"
},
"first_call": {
"description": "Get TikTok user profile",
"url": "https://www.socialcrawl.dev/v1/tiktok/profile?handle=charlidamelio",
"curl": "curl -H \"x-api-key: $SOCIALCRAWL_API_KEY\" \"https://www.socialcrawl.dev/v1/tiktok/profile?handle=charlidamelio\"",
"how_to_use": "/v1/utility/endpoint?id=tiktok/profile"
},
"envelope": {
"success": {
"success": true,
"platform": "tiktok",
"endpoint": "/v1/tiktok/profile",
"data": "... the endpoint's response object ...",
"credits_used": 1,
"request_id": "req-Ex4mpleRequest1d",
"cached": false,
"credits_remaining": 99
},
"success_list": {
"success": true,
"platform": "tiktok",
"endpoint": "/v1/tiktok/profile/videos",
"data": {
"items": [
"... one row per result ..."
],
"next_cursor": "... the source's own cursor; use pagination.next_cursor ...",
"dropped": 0
},
"credits_used": 1,
"request_id": "req-Ex4mpleRequest1d",
"cached": false,
"pagination": {
"next_cursor": "sc.eyJ2IjoyLCJjIjoiLi4uIHRoZSBzb3VyY2UncyBvd24gY3Vyc29yOyB1c2UgcGFnaW5hdGlvbi5uZXh0X2N1cnNvciAuLi4ifQ",
"has_more": true,
"page_size": 1,
"typical_page_size": 30,
"next_page_credits": 1
},
"credits_remaining": 99
},
"error": {
"success": false,
"error": {
"type": "INSUFFICIENT_CREDITS",
"message": "... human-readable cause ... Retrying this request will not succeed until your account balance changes.",
"status": 402,
"doc_url": "https://www.socialcrawl.dev/docs/errors#insufficient-credits",
"retryable": false,
"details": {
"reason": "balance_too_low",
"retry_will_succeed": false,
"next_step": "Top up your credits on the billing page (or turn on auto-recharge there), then send the request again.",
"top_up_url": "https://www.socialcrawl.dev/dashboard/billing/payments"
}
},
"credits_used": 0,
"request_id": "req-Ex4mpleRequest1d",
"credits_remaining": 0
}
},
"billing": {
"model": "credits",
"tiers": {
"standard": 1,
"advanced": 5,
"premium": 10
},
"rules": [
"Cache hits cost 0 credits",
"Failed calls and empty results are automatically refunded",
"Some endpoints have flat or metered pricing; each endpoint's exact cost is in /v1/utility/endpoints"
]
},
"errors": [
{
"code": "MISSING_API_KEY",
"http": 401,
"meaning": "No API key on the request: send x-api-key or Authorization: Bearer"
},
{
"code": "INVALID_API_KEY",
"http": 401,
"meaning": "API key is malformed, not found, revoked, or expired"
},
{
"code": "INSUFFICIENT_CREDITS",
"http": 402,
"meaning": "Credit balance is lower than the endpoint cost"
},
{
"code": "INVALID_REQUEST",
"http": 400,
"meaning": "A required parameter is missing, a value failed validation, or no one-of group member was provided"
},
{
"code": "ENDPOINT_NOT_FOUND",
"http": 404,
"meaning": "The platform or resource is not supported"
},
{
"code": "RESOURCE_NOT_FOUND",
"http": 404,
"meaning": "The requested item was not found on the platform; credits are refunded when triggered by an empty upstream result"
},
{
"code": "CONCURRENCY_LIMIT",
"http": 429,
"meaning": "More than 50 simultaneous requests on the same API key; honor Retry-After, then back off"
},
{
"code": "UPSTREAM_ERROR",
"http": 502,
"meaning": "The platform returned an error; credits are automatically refunded"
},
{
"code": "SERVICE_UNAVAILABLE",
"http": 503,
"meaning": "Temporarily unavailable for this platform after repeated failures; retry shortly, credits are refunded"
},
{
"code": "INTERNAL_ERROR",
"http": 500,
"meaning": "Unexpected server error; credits are automatically refunded"
},
{
"code": "METHOD_NOT_ALLOWED",
"http": 405,
"meaning": "Wrong HTTP method for this endpoint"
},
{
"code": "IDEMPOTENCY_IN_PROGRESS",
"http": 409,
"meaning": "Another request with the same key and payload is still running; not charged, retry after Retry-After"
},
{
"code": "IDEMPOTENCY_KEY_CONFLICT",
"http": 409,
"meaning": "The Idempotency-Key is already in use by another account"
},
{
"code": "IDEMPOTENCY_REPLAY_UNAVAILABLE",
"http": 409,
"meaning": "The completed response for this key exceeded the replay size limit; use a new key to make a new billable request"
},
{
"code": "IDEMPOTENCY_KEY_PAYLOAD_MISMATCH",
"http": 422,
"meaning": "The Idempotency-Key was reused with a different request payload"
},
{
"code": "PAYLOAD_TOO_LARGE",
"http": 413,
"meaning": "The JSON request body exceeds the 1 MB size limit"
},
{
"code": "RATE_LIMITED",
"http": 429,
"meaning": "More than 600 requests in a 1-minute window on the same API key; honor Retry-After, then back off"
},
{
"code": "KEY_BUDGET_EXCEEDED",
"http": 402,
"meaning": "This API key has spent its per-key credit limit; the account balance is unaffected. Raise or reset the key's limit in Dashboard → API Keys, or use a key with no limit"
},
{
"code": "COHORT_MEMBER_LIMIT_EXCEEDED",
"http": 400,
"meaning": "The member upload would push the cohort past its 10,000-member limit"
},
{
"code": "COHORT_LIMIT_EXCEEDED",
"http": 400,
"meaning": "The account already holds the maximum of 100 cohorts; delete one before creating another"
},
{
"code": "COHORT_IDENTITY_PLATFORM_UNSUPPORTED",
"http": 400,
"meaning": "That platform is not supported for cohort queries"
},
{
"code": "COHORT_IDENTITY_CONFLICT",
"http": 409,
"meaning": "Another external_id already claims that normalized identity in this cohort"
},
{
"code": "COHORT_QUERY_NOT_CANCELLABLE",
"http": 409,
"meaning": "The cohort query is already terminal and cannot be cancelled"
},
{
"code": "COHORT_QUERY_NOT_READY",
"http": 409,
"meaning": "The cohort query has not reached a terminal state, so its results are not available yet"
},
{
"code": "COHORT_RESULT_TOO_LARGE",
"http": 413,
"meaning": "A single stored cohort result cannot fit beneath the 1 MB response-page ceiling"
},
{
"code": "RUN_NOT_FOUND",
"http": 404,
"meaning": "No discover run with this id belongs to your account; start a run"
},
{
"code": "RUN_STATE_CONFLICT",
"http": 409,
"meaning": "The discover run is in a state that does not allow this call, such as resuming a completed run"
},
{
"code": "RUN_EXPIRED",
"http": 410,
"meaning": "The discover run's retention passed and its rows were deleted; start a new run"
},
{
"code": "NEEDS_ASYNC",
"http": 422,
"meaning": "The discover request is over what one call can answer and async=false forbids a background run"
},
{
"code": "SCHEDULE_NOT_FOUND",
"http": 404,
"meaning": "No discover schedule with this id belongs to your account; list yours at /v1/prism/discover/schedules"
},
{
"code": "STREAM_NOT_FOUND",
"http": 404,
"meaning": "No listener with this id belongs to this API key; list this key's listeners"
},
{
"code": "STREAM_STATE_CONFLICT",
"http": 409,
"meaning": "The listener's state does not allow this call, such as resuming a deleted listener"
},
{
"code": "CURSOR_EXPIRED",
"http": 410,
"meaning": "The events cursor is older than the event log's 30-day retention; restart from cursor=oldest"
}
],
"envelope_fields": {
"data.dropped": "List responses only. Count of upstream rows discarded because they could not be repaired to the schema; 0 means the page is complete. It sits INSIDE data, not at the envelope root, and is absent from single-object responses.",
"data._warnings": "Optional string[] of non-fatal notices (field-map drift, clamped computed values). Advisory only; never treat its presence as a failure.",
"data.next_cursor": "List responses only. The source's own cursor, kept for older clients; page with pagination.next_cursor instead.",
"data.empty_reason": "List responses with no rows only. Why the page is empty (no_matches, end_of_list, nothing_new_since, ...), with data.empty_reason_note saying what to do next.",
"pagination": "List responses only, at the envelope ROOT. Stop on has_more === false rather than on cursor absence.",
"pagination.typical_page_size": "Rows a full page of this endpoint holds for this request, or null when it is not verified. A shorter page is a short page, not an error.",
"pagination.next_page_credits": "Credits the next page holds up front, priced from the next request itself; null when there is no next page.",
"cached": "true when the response came from cache, in which case credits_used is 0.",
"age_s": "Cache hits only, beside cached. Whole seconds since the copy was fetched (also the X-Cache-Age header), or null when not recorded. Send max_age_s to choose how old a copy you accept: up to an hour on profile and post lanes, served for 0 credits; a lower value fetches fresh; 0 always fetches live.",
"credits_remaining_note": "Cache hits only. Says why credits_remaining is null there (a free hit does not read the balance) and where to read it.",
"error.retryable": "Errors only. true when the same request may succeed later (honor Retry-After); false means change the request instead.",
"error.details": "Errors only, optional. Structured context for the error, such as the credits a 402 needed and how to make the call fit."
},
"pagination": {
"how": "List endpoints return pagination.next_cursor; pass it back as ?cursor=... until has_more is false",
"params": [
"cursor"
]
},
"rate_limits": {
"requests_per_minute": 600,
"concurrent_requests": 50
},
"stats": {
"platforms": 69,
"endpoints": 679
},
"next_steps": {
"catalog": "/v1/utility/endpoints",
"endpoint_guide": "/v1/utility/endpoint?id=tiktok/profile",
"agent_context": "/v1/utility/llms",
"docs": "https://www.socialcrawl.dev/docs",
"openapi": "https://www.socialcrawl.dev/openapi.json",
"mcp_server": "npx -y socialcrawl-mcp",
"agent_skill": "npx skills add socialcrawl/skills"
}
},
"credits_used": 0,
"request_id": "req-Ex4mpleRequest1d",
"cached": false
}Synthetic fixture for the documented response shape. Values are illustrative, not a production capture.
How does the Utility API Quickstart API work?
Send a GET request with your API key and get back clean, structured JSON in our unified schema. Supported computed fields are populated when the source provides the required inputs.
Method
GET
Response
JSON
How do you scrape social media data in seconds?
The fastest social media scraping API for developers. Scrape profiles, posts, comments, and analytics from 69 platforms covering 10B+ monthly active users.
One schema, every platform
Query 69 platforms with identical response structures. Write your integration once.
Computed fields, not just scraped
When an endpoint supports these metrics and the source provides the required inputs, the normalized record includes engagement_rate, estimated_reach, content_category, and language. Ready to use.
See your data before you code
Visual Data Explorer. Paste any URL, get rich result cards, sortable tables, CSV export.
import requests
response = requests.get(
'https://www.socialcrawl.dev/v1/tiktok/profile',
params={'handle': 'charlidamelio'},
headers={'x-api-key': 'sc_YOUR_API_KEY'}
)
data = response.json(){
"success": true,
"platform": "tiktok",
"data": {
"author": {
"username": "charlidamelio",
"followers": 152400000
},
"engagement": {
"likes": 12400000000,
"engagement_rate": 0.087
},
"metadata": {
"language": "en",
"content_category": "lifestyle"
}
}
}Have a question? We got answers
Find answers to frequently asked questions about SocialCrawl's API, pricing, and capabilities.
Contact usWhat does the quickstart endpoint return?
How fast can I make my first SocialCrawl call?
Is the quickstart free to call?
Can the quickstart be tailored to one platform?
Why use a quickstart endpoint instead of reading the docs?
Ask AI about SocialCrawl
Ready to scrape Utility API Quickstart data?
Get your API key and start pulling Utility data in under 60 seconds.
