# Stormy Social Data Stormy is a REST API and remote Streamable HTTP MCP server for public social data across Instagram, YouTube, TikTok, X, LinkedIn, and Reddit. Human documentation: https://stormy.ai/docs OpenAPI: https://stormy.ai/openapi.json Machine capabilities: https://stormy.ai/api/v1/capabilities MCP endpoint: https://stormy.ai/mcp REST base URL: https://stormy.ai/api/v1 ## Authentication Use either header: Authorization: Bearer YOUR_STORMY_API_KEY X-API-Key: YOUR_STORMY_API_KEY Never send an API key in a URL, JSON body, prompt, or MCP tool argument. ## Simple synchronous REST endpoints POST /search Body: {"platform":"youtube","query":"roofing creators in Ohio","limit":25,"fresh":true} Platforms: instagram, youtube, tiktok, x, linkedin, reddit. limit: 1-100. fresh defaults to false and reads cache. POST /profile Body: {"target":"https://tiktok.com/@creator","platform":"tiktok","fresh":true,"include_posts":true} target may be a URL, handle, username, public identifier, or channel ID. POST /emails Body: {"platform":"youtube","targets":["@creator_one","@creator_two"]} Supported for Instagram, TikTok, and YouTube. 1-25 targets. Only successful verified finds are billed. GET /pricing?quantity=100&include_email=true GET /capabilities Legacy aliases /social/search, /social/profile, and /social/emails remain accepted but new clients should use the shorter paths. ## Durable jobs Use jobs for fresh, bulk, email, or long-running work. POST /jobs Body: { "operation":"search_people", "arguments":{"platform":"youtube","query":"roofing creators","limit":100,"fresh":true}, "delay_seconds":0, "priority":0, "max_attempts":5 } GET /jobs/{job_id} GET /jobs?status=running&limit=20 DELETE /jobs/{job_id} Statuses: queued, scheduled, running, throttled, retrying, succeeded, failed, cancelled. Poll using poll_after_seconds and stop when terminal=true. Use an Idempotency-Key header so retries do not create duplicate work or charges. Provider quotas are shared across every API replica and worker. Synchronous requests return 429 with Retry-After when a vendor pool is unavailable. Durable jobs move to throttled, preserve their attempt budget, and resume after the shared Supabase cooldown. Transient non-rate-limit failures use bounded exponential backoff. ## MCP tools search_people(platform, query, limit=10, fresh=false) lookup_profile(target, platform=null, fresh=false, include_posts=false) find_emails(platform, targets) estimate_price(quantity=100, include_email=false) account_status() describe_social_data() start_social_job(operation, arguments, idempotency_key, delay_seconds=0, priority=0, max_attempts=5) get_social_job(job_id) list_social_jobs(status=null, limit=20) cancel_social_job(job_id) ## Agent decision policy Use direct search_people or lookup_profile with fresh=false for small ordinary requests. For fresh, bulk, or email work, use a durable job. Estimate first when the user asks about cost or requests 25 or more paid results. Give every new job a stable idempotency_key derived from the user's intent. Reuse it after transport errors and never start a replacement while terminal=false. Poll only after poll_after_seconds. throttled and retrying are waiting states, not failures. Call find_emails only when the user explicitly asks for emails or contacts. Email calls and jobs accept at most 25 targets. Split larger lists into batches of 25 or fewer with a distinct stable idempotency_key per batch. On upgrade_required or insufficient_balance, return upgrade_url. On rate_limit, wait retry_after_seconds. ## Usage receipt Successful responses include usage.operation, metered_results, billed_results, cost_usd, credits, plan, and remaining_usage_usd. Rates: cached result $0.01; fresh profile $0.05; fresh discovery $0.08 per returned result; verified email $0.15 only when found. ## Data availability Fields are returned when public and supplied by the selected source. Treat platform-specific fields as nullable. Common profile fields may include platform, id, handle, name, URL, description, profile image, verification, location, country, language, website, follower/following counts, post count, engagement rate, and posts. Instagram may include username, full name, biography, follower/following/post counts, average engagement, biolinks, country, business category, and posts with caption, URL, timestamp, likes, comments, image, and location. YouTube may include channel ID, handle, name, subscribers, description, video count, total views, images, country, keywords, links, and videos with title, description, publish time, duration, views, likes, comments, thumbnails, and transcript/caption data when available. TikTok may include ID, secUid, handle, nickname, signature, avatar, verification, follower/following/likes/video counts, and videos with description, duration, views, likes, comments, shares, saves, music, hashtags, and captions. X may include handle, display name, biography, verification, location, website, follower/following/post counts, join date, and posts with text, time, language, likes, replies, reposts, quotes, views, bookmarks, and conversation ID. LinkedIn may include name, URL, headline, country, followers, posting frequency, engagement averages, top post, AI summary, suitability signals, and posts with text, time, reactions, comments, reposts, and reaction breakdown. Reddit may include author, karma, account creation, subreddit, title, body, score, upvote ratio, comment count, permalink, time, and content flags. Public search and profile endpoints recursively remove email, business_email, contact_email, enriched email, phone, and phone_number fields. Use /emails explicitly for contact discovery. ## Errors 400 invalid_request: malformed or unsupported request. 401 invalid_token: missing, expired, revoked, or invalid API key. 402 upgrade_required: paid capability requires an active plan. 402 insufficient_balance: available usage is below the maximum request cost. 404 job_not_found: job missing or owned by another account. 429 rate_limit: honor the Retry-After header.