Sandbox
@OneInterface/stormy-cookbook

Stormy Social Data API and MCP recipes

This cookbook shows how to connect an agent to Stormy’s REST API or MCP server for social data work. It gives copy-paste examples for search, profile lookup, verified email finding, and durable jobs, with the same contract across six networks.

46 stars1 forksUpdated 1mo ago
Who it's for

Builders who want their agent to search social platforms, resolve profiles, and find verified emails without juggling separate APIs.

What it delivers

You can use one key and one tool contract to research creators and enrich leads across six social networks.

What it does

MCP quickstart

Shows how to connect Claude Code, Codex, Cursor, Windsurf, and ChatGPT-style MCP clients to `https://stormy.ai/mcp`.

REST examples

Provides `curl`, Python, and TypeScript examples for `/search`, `/profile`, `/emails`, and `/jobs`.

Recipe library

Includes step-by-step guides for influencer discovery, outreach lists, CRM enrichment, competitor analysis, topic listening, and durable jobs.

Error and billing guidance

Explains rate limits, retries, idempotency keys, top-ups, and billing by outcome.

Capability matrix

Lists which fields and actions are available on TikTok, YouTube, Instagram, X, LinkedIn, and Reddit.

How to get it

  1. 1The Stormy MCP server speaks Streamable HTTP at https://stormy.ai/mcp and authenticates…
    export STORMY_API_KEY="stm_live_..."   # never commit this
  2. 2Run
    claude mcp add --transport http stormy https://stormy.ai/mcp \
      --header "Authorization: Bearer $STORMY_API_KEY"
  3. 3Run
    Name: Stormy Social Data
    MCP URL: https://stormy.ai/mcp
    Authentication: OAuth

README

Stormy AI Social Data Cookbook — one REST API and one MCP server for Instagram, YouTube, TikTok, X, LinkedIn and Reddit

Stormy Cookbook — TikTok, YouTube, Instagram, LinkedIn, X and Reddit API recipes for AI agents

Open-source, copy-pasteable recipes for the Stormy Social Data API and the Stormy MCP server (Model Context Protocol, Streamable HTTP).

One HTTP contract — search, profile, emails, jobs — across six social networks. No proxy pool, no six vendor SDKs, no scraper to babysit. Point your agent at https://stormy.ai/mcp, or curl the REST base at https://stormy.ai/api/v1.

License: MIT Link check MCP Networks Docs

Jump to: Recipes · MCP quickstart · REST quickstart · Endpoints · Pricing · Errors · FAQ


Why this exists

Every "get social data" project starts the same way: six different APIs, six auth schemes, six rate limits, six response shapes, and a scraper that breaks on a Tuesday. Then you bolt an LLM on top and discover none of it is shaped for an agent — no cost signal, no idempotency, no durable jobs, no machine-readable capability list.

Stormy is that layer, already built. This cookbook is how you use it.

Request flow: your agent calls Stormy over MCP or REST; Stormy handles auth, cache-first routing, durable jobs, shared provider rate limits and per-call metering, then reads public data from six social networks


Quickstart A: connect the MCP server

The Stormy MCP server speaks Streamable HTTP at https://stormy.ai/mcp and authenticates with an HTTP bearer token. Get a key at stormy.ai/account and export it:

export STORMY_API_KEY="stm_live_..."   # never commit this

Claude Code

claude mcp add --transport http stormy https://stormy.ai/mcp \
  --header "Authorization: Bearer $STORMY_API_KEY"

Codex CLI (~/.codex/config.toml)

[mcp_servers.stormy]
url = "https://stormy.ai/mcp"
bearer_token_env_var = "STORMY_API_KEY"

Cursor / Windsurf / any mcp.json client

{
  "mcpServers": {
    "stormy": {
      "url": "https://stormy.ai/mcp",
      "headers": {
        "Authorization": "Bearer ${STORMY_API_KEY}"
      }
    }
  }
}

ChatGPT custom connector

Name: Stormy Social Data
MCP URL: https://stormy.ai/mcp
Authentication: OAuth

The ten MCP tools you get

ToolWhat it does
search_people(platform, query, limit=10, fresh=false)Search one network from a natural-language query
lookup_profile(target, platform=null, fresh=false, include_posts=false)Resolve a URL / @handle / channel ID to a normalized profile
find_emails(platform, targets)Verified contact emails for 1–25 Instagram, TikTok or YouTube profiles
estimate_price(quantity=100, include_email=false)Rate card + a maximum estimate, spends nothing
account_status()Plan, remaining prepaid usage, top-up URL
describe_social_data()The machine-readable platform / field / pricing / workflow contract
start_social_job(operation, arguments, idempotency_key, ...)Queue fresh, bulk or email work durably
get_social_job(job_id)Status, progress, poll_after_seconds, result, full timeline
list_social_jobs(status=null, limit=20)Recover prior work instead of resubmitting
cancel_social_job(job_id)Cancel queued / scheduled / throttled / retrying work

Then just ask:

Find 25 TikTok creators posting about home espresso, pull their follower counts, and tell me what it cost.


Quickstart B: call the REST API directly

Base URL: https://stormy.ai/api/v1 (also reachable at https://api.stormy.ai/api/v1). Auth: Authorization: Bearer <key> or X-API-Key: <key>. Never put a key in a URL, a JSON body, a prompt, or an MCP tool argument.

curl

curl -X POST 'https://stormy.ai/api/v1/search' \
  -H "Authorization: Bearer $STORMY_API_KEY" \
  -H 'Content-Type: application/json' \
  -H 'Idempotency-Key: espresso-tiktok-2026-07' \
  -d '{
    "platform": "tiktok",
    "query": "home espresso and coffee gear creators",
    "limit": 25,
    "fresh": true
  }'

Python

import os

import requests

response = requests.post(
    "https://stormy.ai/api/v1/search",
    headers={
        "Authorization": f"Bearer {os.environ['STORMY_API_KEY']}",
        "Idempotency-Key": "espresso-tiktok-2026-07",
    },
    json={
        "platform": "tiktok",
        "query": "home espresso and coffee gear creators",
        "limit": 25,
        "fresh": True,
    },
    timeout=90,
)
response.raise_for_status()
payload = response.json()

for creator in payload["results"]:
    print(creator["handle"], creator["follower_count"])

print("cost:", payload["usage"]["cost_usd"], "USD")

TypeScript

const response = await fetch("https://stormy.ai/api/v1/search", {
  method: "POST",
  headers: {
    Authorization: `Bearer ${process.env.STORMY_API_KEY}`,
    "Content-Type": "application/json",
    "Idempotency-Key": "espresso-tiktok-2026-07",
  },
  body: JSON.stringify({
    platform: "tiktok",
    query: "home espresso and coffee gear creators",
    limit: 25,
    fresh: true,
  }),
});

if (!response.ok) throw new Error(await response.text());
const { results, usage } = await response.json();
console.log(results.length, "creators for", usage.cost_usd, "USD");

What comes back

{
  "ok": true,
  "platform": "tiktok",
  "query": "home espresso and coffee gear creators",
  "fresh": true,
  "results": [
    {
      "id": "6812...",
      "handle": "@homebarista",
      "nickname": "Home Barista",
      "url": "https://tiktok.com/@homebarista",
      "signature": "Espresso at home, no snobbery.",
      "verified": false,
      "follower_count": 184000,
      "following_count": 312,
      "likes_count": 4210000,
      "video_count": 612
    }
  ],
  "usage": {
    "operation": "fresh_discovery",
    "metered_results": 25,
    "billed_results": 25,
    "cost_usd": "2.00",
    "credits": 200,
    "plan": "paid",
    "remaining_usage_usd": "23.00"
  }
}

Every successful response carries a usage receipt. You are billed for outcomes, not requests.


What you can do on each network

Capability matrix: which Stormy endpoints work on each network, plus the four usage rates

NetworkPOST /searchPOST /profileinclude_postsPOST /emailsPublic fields
TikTok APICreators by niche@handle or URLVideos, views, shares, saves, music, hashtags✅ verified email27
YouTube APIChannels by topicHandle or channel IDVideos, transcripts, captions✅ verified email25
Instagram APICreators by nicheUsername or URLPosts, captions, engagement, location✅ verified email23
X (Twitter) APIAccounts and posts@handle or URLPosts, views, bookmarks, conversation ID26
LinkedIn APIPeople and companiesProfile URLPosts, reaction breakdowns, cadence31
Reddit APIThreads by topicAuthor karma and ageScore, upvote ratio, comment count17

Field lists are authoritative in GET /api/v1/capabilitiesfields_by_platform. Treat every platform-specific field as nullable — you get it when it is public and the source supplied it.

Per-network field lists (click to expand)

TikTok — profile: id, sec_uid, handle, nickname, url, signature, avatar_url, verified, follower_count, following_count, likes_count, video_count · posts: video_id, url, description, create_time, duration, views, likes, comments, shares, saves, image_url, is_pinned, music, hashtags, caption_url

YouTube — profile: channel_id, handle, name, url, subscribers, description, videos_count, total_views, profile_image_url, banner_image_url, country, keywords, links · posts: video_id, url, title, description, published_at, duration, views, likes, comments, thumbnail_url, transcript, caption_url

Instagram — profile: username, full_name, biography, profile_pic_url, follower_count, following_count, posts_count, avg_engagement_rate, biolinks, country, is_verified, is_business_account, business_category_name · posts: media_id, post_url, caption, taken_at, like_count, comment_count, image_url, location, location_data, comments

X (Twitter) — profile: id, handle, name, url, description, profile_image_url, verified, location, website, followers, following, posts_count, joined_at · posts: id, url, text, created_at, language, likes, replies, reposts, quotes, views, bookmarks, conversation_id, author

LinkedIn — profile: id, name, linkedin_url, headline, country, country_iso_2, followers, total_posts, posts_last_6_months, posting_frequency, avg_likes, avg_comments, avg_reposts, avg_total_interactions, top_post_text, top_post_interactions, last_post_date, ai_summary, is_suitable_for_promotion, relevant_posts · posts: post_url, text, headline, posted_datetime, total_interactions, num_likes, num_comments, num_reposts, num_reactions_breakdown, poster_name, poster_linkedin_url

Reddit — profile: author, author_url, karma, account_created_at · posts: id, url, permalink, subreddit, author, title, text, created_at, score, upvote_ratio, comments_count, is_self, over_18


Recipes

Every recipe is a single runnable markdown file with real code and a real cost estimate. Full index with difficulty and pricing: recipes/README.md.

#RecipeNetworksWhat you get
01Find influencers by nicheTikTok, YouTube, InstagramA ranked shortlist of creators with follower counts and engagement
02Build an outreach list with verified emailsTikTok, YouTube, InstagramSearch → filter → /emails → CSV, paying only for hits
03Enrich a CRM from handlesAll sixHandles in, normalized profile rows out
04Competitor content analysisTikTok, YouTube, InstagramWhich of a rival's posts actually worked, and why
05Monitor a creator over timeAnyA daily snapshot job and a growth delta
06Cross-platform audience researchAll sixOne query fanned out across six networks, merged
07Reddit topic listeningReddit, XWhich threads are moving on a topic you care about
08Durable jobs for large collectionsAll six1,000+ results without holding an HTTP connection
09Use Stormy from an MCP agentAll sixPrompts + tool policy for Claude Code, Cursor, Codex
10Handle errors, rate limits and billing402 / 429 / 503 handling, headless top-up, idempotency

The whole API on one screen

Paid calls

MethodPathBodyNotes
POST/searchplatform, query, limit (1–100, default 10), fresh (default false)Cache-first. fresh=true calls a live provider
POST/profiletarget, platform?, fresh, include_postsReturns data, not results. platform is optional when target is a URL
POST/emailsplatform (instagram | tiktok | youtube), targets (1–25)The only endpoint that returns contact data
POST/jobsoperation, arguments, delay_seconds (0–604800), priority (−10…10), max_attempts (1–10)202 Accepted. operationsearch_people, lookup_profile, find_emails
GET/jobs/{job_id}?include_events=trueStatus, progress and the event timeline
GET/jobs?status=running&limit=20List recent jobs
DELETE/jobs/{job_id}Cancel non-terminal work

Free calls

MethodPathNotes
GET/pricing?quantity=100&include_email=trueAuthoritative rate card + a maximum estimate
GET/capabilitiesPlatforms, per-platform fields, endpoints, job statuses, agent policy
GET/accountPlan, usage_balance, scopes, top-up URL
POST/account/top-upamount_usd, note? → an instant Stripe checkout_url
GET POST DELETE/keys, /keys/{id}List, mint and revoke API keys

Legacy aliases /social/search, /social/profile and /social/emails still work; new clients should use the short paths.

Send an Idempotency-Key header on any paid call. Retrying with the same key never duplicates work or charges.

Machine-readable contract

ResourceURL
Capabilities JSONhttps://stormy.ai/api/v1/capabilities
OpenAPIhttps://stormy.ai/openapi.json
llms.txthttps://stormy.ai/llms.txt
Human docshttps://stormy.ai/docs

Pricing

One credit is one US cent. You are charged for successful outcomes only — a verified-email lookup that finds nothing costs $0.00.

OperationPriceWhen it applies
Cached result$0.01fresh=false on /search or /profile
Fresh profile$0.05/profile with fresh=true
Fresh discovery$0.08Per matching person returned by /search with fresh=true
Verified email$0.15Per email actually found by /emails
  • Free preview: 50 cached results per rolling 30 days. No fresh data, no emails.
  • Paid: $50 / month, including $25 (2,500 credits) of usage. Overage is metered at the rates above.

Worked examples (straight from GET /pricing):

WorkloadCost
100 cached profiles$1.00
100 fresh profiles$5.00
100 fresh matching people$8.00
100 verified emails$15.00
100 fresh people + their verified emails$23.00

Ask before you spend — estimate_price / GET /pricing is free:

curl 'https://stormy.ai/api/v1/pricing?quantity=250&include_email=true'

Errors and retries

StatusCodeWhat to do
400invalid_requestFix the body. Unsupported platform, empty query, limit out of 1–100, more than 25 email targets
401invalid_tokenKey missing, expired, revoked or wrong
402upgrade_requiredReturn the upgrade_url to the user
402insufficient_balancePOST /account/top-up with error.recommended_topup_usd, hand back checkout_url, poll GET /account, retry
404job_not_foundJob missing or owned by another account
429rate_limitWait Retry-After seconds. Do not retry immediately
429provider cooldownThe shared upstream pool is cooling down — switch to a durable job
503provider_not_configuredOur deployment problem, not your request. Retry later

Durable jobs never fail on a rate limit: they move to throttled without consuming an attempt and resume after the cooldown. Job statuses are queued, scheduled, running, throttled, retrying, succeeded, failed, cancelled. Poll only after poll_after_seconds, and stop when terminal is true.

Full worked handling in recipe 10.


Privacy and scope

  • Stormy returns public social data only.
  • search and profile responses have email, business_email, contact_email, phone and phone_number recursively stripped at the API boundary. This is enforced server-side, not by convention.
  • POST /emails is the only path to contact data, it is opt-in, it is limited to Instagram / TikTok / YouTube, and it is billed only when a verified email is found.
  • Agents should call it only when a user explicitly asks for contact details.

FAQ

Is there a TikTok API I can call from an AI agent?

Yes — POST /api/v1/search with "platform": "tiktok", or the search_people MCP tool. You get creator search by niche, @handle → profile resolution, videos with views/likes/shares/saves/music/hashtags, and verified email enrichment. See recipe 01.

Can I get LinkedIn profile and post data without scraping?

Yes. platform: "linkedin" on /search and /profile returns headline, follower count, posting frequency, average likes/comments/reposts, top post and an AI summary; include_posts adds posts with a full reaction breakdown. LinkedIn does not support /emails.

What about a Reddit API for topic listening?

platform: "reddit" searches threads across subreddits and returns score, upvote_ratio, comments_count, permalink and author karma. See recipe 07.

Which networks support the influencer email finder?

Instagram, TikTok and YouTube. 1–25 targets per call. $0.15 per email actually found; misses are free. X, LinkedIn and Reddit are search/profile only.

Do I need six API keys?

No. One STORMY_API_KEY covers Instagram, YouTube, TikTok, X, LinkedIn and Reddit over both REST and MCP, with one rate card, one usage balance and one receipt format.

What is the difference between MCP and REST here?

None, functionally — they are two faces of the same service, entitlements and rate card. MCP is for agents that discover tools at runtime; REST is for your own code. Mix them freely; a job started over REST is visible over MCP and vice versa.

How do I avoid paying twice when my request times out?

Send a stable Idempotency-Key header (REST) or idempotency_key argument (MCP jobs) derived from the user's intent. Replaying the same key returns the original result and the original charge.


Contributing

Recipes, fixes and new language ports are welcome. Read CONTRIBUTING.md — the short version: one recipe per file, every snippet must run, no invented parameters, and never commit a key.

License

MIT. The recipes are yours to lift into production.


Built by Stormy · docs · capabilities · founders@stormy.ai

Files in the repo

Repository payload11 top-level entries
  • .github
  • assets
  • recipes
  • .env.example
  • .gitignore
  • authors.yaml
  • CONTRIBUTING.md
  • LICENSE
  • lychee.toml
  • README.md
  • registry.yaml

Discussion (0)

Ask about usage, or say what you built with it

Sign in to join the discussion.

No comments yet. Be the first to say what this is good for.

More tutorials & guides

shareAI-lab/
learn-claude-code

Bash is all you need - A nano claude code–like 「agent harness」, built from 0 to 1

77k
luongnv89/
claude-howto
luongnv89/claude-howtoTutorials & Guides

A visual, example-driven guide to Claude Code — from basic concepts to advanced agents, with copy-paste templates that bring immediate value.

41k
agentskills/
agentskills
agentskills/agentskillsTutorials & Guides

Specification and documentation for Agent Skills

25k