{"openapi":"3.1.0","info":{"title":"Pulse","version":"0.7.0","summary":"Social-post metrics API for AI agents.","description":"Give a public post URL (YouTube, X/Twitter, TikTok, Bluesky, Instagram, Threads, LinkedIn) and get back normalized views, likes, comments, and publish date as JSON. Free, no signup, no API key. Agent-first: discoverable via OpenAPI + llms.txt and payable per call in USDC over x402.","x-payment":{"protocol":"x402","network":"base-sepolia","price":"$0.002","enabled":false}},"servers":[{"url":"https://pulse.walls.sh"}],"paths":{"/metrics":{"get":{"operationId":"getMetrics","summary":"Get a public post's metrics","description":"Returns normalized {platform, views, likes, comments, shares, viewsEstimated, publishedAt, title, author, thumbnail} for a social post URL. Free unless billing is enabled, in which case an unpaid request returns 402 with x402 payment terms a client pays and retries automatically. A deleted/private post returns 404 content_unavailable.","parameters":[{"name":"url","in":"query","required":true,"schema":{"type":"string","format":"uri"},"description":"The public post URL. Share-style short links (vm.tiktok.com/…, tiktok.com/t/…, t.co/…) are resolved automatically; the response's url is the canonical post URL.","example":"https://www.tiktok.com/@khaby.lame/video/6967348974688816390"}],"responses":{"200":{"description":"Normalized metrics.","content":{"application/json":{"example":{"url":"https://www.tiktok.com/@khaby.lame/video/6967348974688816390","platform":"tiktok","views":39600000,"likes":5500000,"comments":39500,"shares":22300,"viewsEstimated":false,"publishedAt":"2021-05-28T14:32:30.000Z","title":"Boss.. one shot - 3 points","author":"@khaby.lame","thumbnail":"https://p16-sign.tiktokcdn.com/..."}}}},"400":{"description":"Missing/malformed/unsupported URL (url_required | bad_url | unsupported_url)."},"402":{"description":"Payment required (x402), only when billing is enabled. Pay and retry."},"404":{"description":"content_unavailable — the post is deleted, private, or region-locked."},"422":{"description":"login_required — the platform (Instagram/Threads/LinkedIn) only serves a logged-out wall; needs a session."},"429":{"description":"rate_limited — too many lookups from your IP this minute; respect Retry-After."},"502":{"description":"fetch_failed — upstream platform fetch failed; retry-safe."}}}},"/profile":{"get":{"operationId":"getProfile","summary":"Get account-level metrics for a profile URL","description":"A profile URL → { platform, handle, name, followers, following, posts, likes, verified, avatar }. Live: YouTube (subscribers abbreviated by the platform, parsed to a number), TikTok (exact + total hearts), Instagram (exact), X (followers/following/posts), Bluesky (exact). Threads/LinkedIn profiles are login-walled → 422 login_required.","parameters":[{"name":"url","in":"query","required":true,"schema":{"type":"string","format":"uri"},"description":"The profile URL (e.g. youtube.com/@handle, tiktok.com/@user, instagram.com/user).","example":"https://www.tiktok.com/@khaby.lame"}],"responses":{"200":{"description":"Normalized profile metrics.","content":{"application/json":{"example":{"url":"https://www.tiktok.com/@khaby.lame","platform":"tiktok","handle":"khaby.lame","name":"Khabane lame","followers":161900000,"following":80,"posts":1330,"likes":2600000000,"verified":true}}}},"400":{"description":"url_required | unsupported_url."},"404":{"description":"content_unavailable — no such account."},"422":{"description":"login_required — X/Threads/LinkedIn profiles need a session."}}}},"/history":{"get":{"operationId":"getHistory","summary":"Get a post's recorded metrics history","description":"Returns the snapshots recorded for a post or a profile — every fresh /metrics fetch appends { t, views, likes, comments }, every fresh /profile fetch appends { t, followers, posts } — so repeat callers get the growth curve, not just the latest numbers. An empty series means the URL hasn't been fetched yet: call /metrics (or /profile) on it to start the series.","parameters":[{"name":"url","in":"query","required":true,"schema":{"type":"string","format":"uri"},"description":"The public post URL."},{"name":"since","in":"query","required":false,"schema":{"type":"string"},"description":"ISO-8601 date or unix milliseconds — return only points AFTER this moment (the polling delta)."}],"responses":{"200":{"description":"The recorded series (oldest first).","content":{"application/json":{"example":{"url":"https://www.tiktok.com/@khaby.lame/video/6967348974688816390","platform":"tiktok","contentId":"6967348974688816390","count":2,"points":[{"t":"2026-06-09T18:00:00.000Z","views":39600000,"likes":5500000,"comments":39500},{"t":"2026-06-09T21:30:00.000Z","views":39600100,"likes":5500010,"comments":39501}]}}}},"400":{"description":"url_required | bad_url | unsupported_url."}}}},"/metrics/batch":{"get":{"operationId":"getMetricsBatch","summary":"Get metrics for many posts in one request","description":"Fetch up to 50 URLs at once — posts and profiles can mix in one batch (post URLs return post metrics, profile URLs return profile metrics). Pass repeated `url` params or a comma-separated `urls` list. Returns { count, results }, order preserved; each result is a metrics object or { url, error } — a single bad URL never fails the batch.","parameters":[{"name":"url","in":"query","required":false,"style":"form","explode":true,"schema":{"type":"array","items":{"type":"string","format":"uri"},"maxItems":50},"description":"Repeat for each post URL (or use `urls`)."},{"name":"urls","in":"query","required":false,"schema":{"type":"string"},"description":"Comma-separated post URLs (alternative to repeating `url`)."}],"responses":{"200":{"description":"Per-URL metrics (or per-URL error).","content":{"application/json":{"example":{"count":2,"results":[{"url":"https://www.youtube.com/watch?v=xWnqY2Mav4s","platform":"youtube","views":25275,"likes":850},{"url":"https://www.tiktok.com/@x/video/0","error":"content_unavailable","detail":"content unavailable: item doesn't exist"}]}}}},"400":{"description":"url_required (none given) or too_many_urls (more than 50)."}}}}}}