Documentation

Pulse API

One endpoint. Give it a public post URL, get normalized engagement metrics as JSON. No signup, no API key.

Quickstart

Pulse is free right now — /metrics needs no payment, no key, no account. (Pulse also speaks x402, so an agent can pay per call in USDC if billing is ever enabled — but it's off.)

curl "https://pulse.walls.sh/metrics?url=https://www.youtube.com/watch?v=xWnqY2Mav4s"
{
  "url": "https://www.youtube.com/watch?v=xWnqY2Mav4s",
  "platform": "youtube",
  "contentId": "xWnqY2Mav4s",
  "postType": "youtube",
  "views": 35707,
  "likes": 1072,
  "comments": null,
  "shares": null,
  "quotes": null,
  "bookmarks": null,
  "viewsEstimated": false,
  "publishedAt": "2026-06-07T17:00:38.000Z",
  "title": "I Built Two Apps That Make $120K/Month",
  "author": "Starter Story",
  "thumbnail": "https://i.ytimg.com/vi_webp/xWnqY2Mav4s/maxresdefault.webp",
  "fetchedAt": "2026-06-10T13:00:43.347Z",
  "history_url": "https://pulse.walls.sh/history?url=https%3A%2F%2Fwww.youtube.com%2F..."
}

GET /metrics

GET https://pulse.walls.sh/metrics?url=<post url>

Query parameters

NameRequiredDescription
urlyesA public post URL on a supported platform — or a profile URL, which auto-routes to /profile and returns follower counts (so you can hand /metrics any 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 they pointed at.

Response fields

FieldTypeNotes
platformstringyoutube · x · tiktok · bluesky · mastodon · instagram · threads · linkedin
viewsnumber | nullReal where the platform exposes it; otherwise estimated (see viewsEstimated) or null.
likesnumber | nullNull when the platform hides it.
commentsnumber | nullNull when the platform hides it. For YouTube this is an abbreviated count (see commentsEstimated).
sharesnumber | nullReshares — X retweets, TikTok shares, Bluesky reposts. Null where the platform doesn't expose it.
quotesnumber | nullQuote posts — X quote tweets, Bluesky quotes. Null where the concept doesn't exist.
bookmarksnumber | nullSaves — X bookmarks. No other platform exposes saves publicly.
viewsEstimatedbooleanTrue when views was estimated from likes rather than read directly.
commentsEstimatedbooleanTrue when comments is an abbreviated/approximate count — YouTube only publishes "2.4M", never the exact integer. False (exact) everywhere else.
publishedAtstring | nullISO-8601 publish date.
titlestring | nullPost title / caption (truncated).
authorstring | nullChannel / handle (e.g. @nasa).
thumbnailstring | nullA representative image URL for the post.
history_urlstringDirect link to /history for this URL — every call records a snapshot, so this link immediately shows the growth curve after a second fetch.

Errors

HTTPerrorMeaning
400url_required / bad_url / unsupported_urlMissing, malformed, or unrecognized URL.
402Payment required (x402), only if billing is on. Pay and retry; clients do this automatically.
404content_unavailableThe post is deleted, private, or region-locked — not a server error.
422login_requiredPlatform returns a login wall on our residential reader — Instagram & Threads post metrics, LinkedIn profiles (always), and Instagram/Threads profile metrics when even the logged-out public page is gated. The account exists; reading it just needs a session we don't have (≠ 404, which means deleted/private).
429rate_limitedOver 120 lookups/min (free tier). Respect Retry-After and retry. Every response carries RateLimit-Limit / -Remaining / -Reset so you can self-throttle. Pro ($19/mo) raises this to 1,200/min and includes commercial-use terms.
502fetch_failedUpstream platform fetch failed; safe to retry.

GET /profile

Account-level metrics from a profile URL — followers, following, post count, verified, avatar. Live for YouTube (subscribers come abbreviated, e.g. "29.8M" → parsed), TikTok (exact counts + total hearts), Instagram (exact counts), X (followers, following, post count), Bluesky (exact counts), and Threads (followers, following, verified — via the public Barcelona API, no auth). LinkedIn profiles are login-walled → login_required.

GET https://pulse.walls.sh/profile?url=<profile url>

GET /profile/batch

Up to 50 profile URLs in one request — mixed platforms welcome. Same URL conventions as /metrics/batch. Order preserved; each item is a profile object or { url, error }. Add &format=csv for a spreadsheet of follower counts (url,platform,handle,name,followers,following,posts,verified,error) — capture many accounts straight into Sheets.

GET https://pulse.walls.sh/profile/batch?url=<a>&url=<b>
{ "count": 2, "results": [
  { "platform": "youtube", "handle": "@mkbhd", "followers": 21000000 … },
  { "platform": "instagram", "handle": "nasa", "followers": 104395242 … }
] }

GET /history

The growth curve of a post or a profile. Every fresh /metrics fetch records a { t, views, likes, comments } snapshot, and every fresh /profile fetch records { t, followers, posts } — so repeat lookups build a series over time. Returns { url, platform, kind, count, points }. An empty series just means the URL hasn't been fetched yet. Polling? Add since=<ISO-8601 or unix ms> to get only the points after that moment — the delta, not the whole series. Add format=csv for a chart-ready spreadsheet (t,views,likes,comments,shares,followers, one row per snapshot) — drop it into Sheets and plot.

GET https://pulse.walls.sh/history?url=<post url>&since=<optional>&format=<json|csv>

GET /metrics/batch

Need a whole set at once? Pass repeated url params (or a comma-separated urls= list, max 50) and get them all in one request. Mixed batches welcome — post URLs return post metrics, profile URLs return profile metrics. Order is preserved; each item is either a metrics object or { url, error } — one bad URL never fails the batch.

GET https://pulse.walls.sh/metrics/batch?url=<a>&url=<b>
{ "count": 2, "results": [
  { "platform": "youtube", "views": 25275, … },
  { "url": "…", "error": "content_unavailable" }
] }

Add &format=csv for a spreadsheet instead of JSON — one row per URL (url,platform,views,likes,comments,shares,followers,publishedAt,error), posts and profiles in the same table. Drop it straight into Excel or Google Sheets.

curl "https://pulse.walls.sh/metrics/batch?format=csv&url=<a>&url=<b>"

GET /badge

Returns a live SVG badge you can embed in GitHub READMEs, documentation, or any page that renders images, in shields.io flat style. Give it a profile URL for a follower badge ("platform followers: count"), or a post URL for a metric badge ("platform views: count" — falls back to likes, then comments, for posts that don't expose views). Cache-Control is 1 hour so GitHub's CDN refreshes without hammering Pulse.

GET https://pulse.walls.sh/badge?url=<profile-or-post-url>
![YouTube Views](https://pulse.walls.sh/badge?url=https://www.youtube.com/watch?v=dQw4w9WgXcQ)
![X Followers](https://pulse.walls.sh/badge?url=https://twitter.com/yourhandle)
![Likes](https://pulse.walls.sh/badge?url=https://www.youtube.com/watch?v=dQw4w9WgXcQ&metric=likes&label=plays&color=red)

Optional params: metric (post URLs only — views, likes, or comments; defaults to whichever the platform exposes) · label (text on the left side) · color (right side fill; one of blue, green, gray, red, purple, or hex). See the badge guide for copy-paste Markdown.

Platform coverage

YouTube
views · likes · comments · date
Live
X / Twitter
views · likes · comments · shares · date
Live
TikTok
views · likes · comments · shares · date
Live
Bluesky
likes · comments · shares · date
Live
Mastodon
likes · boosts · replies · date
Live
Hacker News
points · comments · date · author
Live
Stack Overflow
views · score · answers · date
Live
Facebook
profiles: page followers · name (no public post API)
Live
Instagram
likes · comments · views
Beta
Threads
profiles: followers · name (public page, no login) · posts: needs login
Beta
LinkedIn
likes · comments · date
Live

Rate limits

Every response carries three headers so you can self-throttle before hitting a 429:

RateLimit-Limit: 120          # calls/min for your tier
RateLimit-Remaining: 87       # calls left in the current window
RateLimit-Reset: 34           # seconds until the window resets

Free tier: 120 calls/min. Pro ($19/mo) raises this to 1,200 calls/min (10×) and adds a commercial-use license. Get a key and upgrade at /account.

Machine discovery

Pulse is built to be found and used by agents:

  • /openapi.json — full OpenAPI 3.1 spec.
  • /llms.txt — a plain-text card describing what Pulse does and how to call it.
  • /stats — live usage JSON (requests, lookups, by platform/outcome); /status is the human view.
  • /health — service status JSON.
Wall № 002 · building autonomously · walls.sh