Bluesky
GET /v1/bluesky/user-posts

Bluesky User Posts API

Author feed — posts and reposts (isRepost marked), quote/external/images embeds, opaque cursor.

~3 credits (0.1/result) per request
TL;DR
Author feed — posts and reposts (isRepost marked), quote/external/images embeds, opaque cursor. The Bluesky User Posts API (Bluesky) is a single authenticated GET request to /v1/bluesky/user-posts that responds with clean JSON and costs ~3 credits (0.1/result). Pass cache=true for a free 24h cache hit; default is always fresh. Start with 100 free credits — no credit card.

What is the Bluesky User Posts API?

Send a Bluesky profile URL, @handle, or handle and get that account's public author feed (app.bsky.feed.getAuthorFeed) as clean JSON — original posts and reposts. Reposts keep the original author{} and engagement; they are marked isRepost=true with repostedBy{handle,displayName,did,avatar} and repostedAt so analytics do not credit someone else's likes to the profile you queried. Pass includeReposts=false to drop reposts. Optional filter maps to Bluesky's feed filter (posts_with_replies | posts_no_replies | posts_with_media | posts_and_author_threads | posts_with_video) — that controls replies/media/threads, not reposts. Each row: uri/url/cid, text, publishedAt, indexedAt, author{}, engagement{likes,reposts,replies,quotes}, and embed as one of type external | images | video | quote (quotes include uri/url/text/author — never a raw lexicon NSID). Rows are ordered by effective timestamp — repostedAt for reposts, publishedAt otherwise — matching Bluesky's author-feed order; re-sorting by publishedAt alone yields a different feed. nextCursor is Bluesky's opaque cursor (do not derive it from publishedAt). Billed ~0.1 credits per returned row (limit max 100). Pass cache=true for the 24h shared cache.

What you get

  • Author feed: originals + reposts with isRepost / repostedBy / repostedAt
  • includeReposts=false and Bluesky filter= for replies/media/threads
  • Normalized embeds: external | images | video | quote (with text/author/url)
  • Opaque nextCursor from AppView (not publishedAt)
  • ~0.1 credits/row; limit up to 100

Platform limits

Honest ceilings from the upstream platform surface — not Captapi bugs. Unexpected truncation here is usually the platform, not us.

  • getAuthorFeed includes reposts by default — check isRepost before averaging engagement on author.handle.
  • filter does not exclude reposts; use includeReposts=false for that.
  • Ordered by effective timestamp (repostedAt for reposts, else publishedAt) — Bluesky author-feed order; re-sorting by publishedAt alone changes the feed.
  • Always pass nextCursor through — do not invent a cursor from publishedAt.

Try it

Open in Playground

Fill in the parameters below and copy a ready-to-run request, or open the live Playground to run it against your account (no API key paste).

Parameters

Sign in to run live
curl "https://api.captapi.com/v1/bluesky/user-posts?url=https%3A%2F%2Fbsky.app%2Fprofile%2Fbsky.app" \
  -H "Authorization: Bearer capt_live_..."
# or: -H "x-api-key: capt_live_..."

Edit the parameters and the code updates instantly. Switch languages and hit copy.

Example response

{
  "success": true,
  "data": {
    "handle": "jay.bsky.team",
    "totalReturned": 5,
    "nextCursor": "2026-06-26T14:25:33.024Z",
    "hasMore": true,
    "posts": [
      {
        "platform": "bluesky",
        "uri": "at://did:plc:fpruhuo22xkm5o7ttr2ktxdo/app.bsky.feed.post/3mqjnjafz2s2k",
        "url": "https://bsky.app/profile/danabra.mov/post/3mqjnjafz2s2k",
        "cid": "bafyreib46qdetrzwrcu35fqynwkiw6tscptkvlxcujk5f745jmzqox5jz4",
        "text": "i want to do a little ✨ ama about atproto ✨ in this thread. no question is too simple\n\nif you’ve been curious about atproto but don’t know much (anything?) about it, ask any question and i’ll try to explain it in my own words.\n\n(+ would love to hear from friends who aren’t very active on bsky)",
        "publishedAt": "2026-07-13T12:02:47.424Z",
        "indexedAt": "2026-07-13T12:02:47.867Z",
        "author": {
          "handle": "danabra.mov",
          "displayName": "dan",
          "did": "did:plc:fpruhuo22xkm5o7ttr2ktxdo",
          "avatar": "https://cdn.bsky.app/img/avatar/plain/did:plc:fpruhuo22xkm5o7ttr2ktxdo/bafkreif43mhqajnbnl62u3ezf37g6x22nd762im54thxbil4ga46eugcga"
        },
        "engagement": {
          "likes": 340,
          "reposts": 82,
          "replies": 104,
          "quotes": 9
        },
        "embed": null
      },
      {
        "platform": "bluesky",
        "uri": "at://did:plc:xtg6uhgsy2j7k2a6qtcood2w/app.bsky.feed.post/3mqsnmkorxc2l",
        "url": "https://bsky.app/profile/karlbode.com/post/3mqsnmkorxc2l",
        "cid": "bafyreih62va7pjdlbcij4nwp55hatyr73glrjr52eocvxkxwdd72i5phea",
        "text": "meanwhile...",
        "publishedAt": "2026-07-17T01:58:36.505Z",
        "indexedAt": "2026-07-17T01:58:38.070Z",
        "author": {
          "handle": "karlbode.com",
          "displayName": "Karl Bode",
          "did": "did:plc:xtg6uhgsy2j7k2a6qtcood2w",
          "avatar": "https://cdn.bsky.app/img/avatar/plain/did:plc:xtg6uhgsy2j7k2a6qtcood2w/bafkreigf276i3ejipydii2glvywuymqwj4usu5noz4rw7lirgxrtbbcibi"
        },
        "engagement": {
          "likes": 973,
          "reposts": 216,
          "replies": 41,
          "quotes": 107
        },
        "embed": {
          "type": "external",
          "url": "https://www.seattletimes.com/seattle-news/meet-jimothy-seattles-internet-famous-raccoon/?fbclid=Iwb21leATGa4ljbGNrBMZrgWV4dG4DYWVtAjExAHNydGMGYXBwX2lkDDM1MDY4NTUzMTcyOAABHnlF6kiFK1hm4n5G5_BMmAcqRVTUV6qoBX4qZCw1rworU3stQwUoZZFw3yXL_aem_eUBpvFSYXBAwVjchn5qVyA",
          "title": "Meet ‘Jimothy,’ Seattle’s internet-famous raccoon",
          "description": "The tiny beast has been spotted twice in Ballard this summer and appears to be doing well, despite a likely congenital deformity, an animal expert said.",
          "thumb": "https://cdn.bsky.app/img/feed_thumbnail/plain/did:plc:xtg6uhgsy2j7k2a6qtcood2w/bafkreidmxsn5szs7i4vpq7kpjbwh44kwnkwu5b2n44vjhtye4hfpqfhzxq"
        }
      }
    ]
  }
}

Billing metadata is returned in response headers: X-Captapi-Credits (credits charged), X-Captapi-Cache (hit or miss), and X-Captapi-Source. Failed requests (4xx/5xx) are never charged. See the full list of error codes in the error reference.

Response structure

A successful call returns success, cached, creditsUsed, and a data object with the following fields:

Top-level fields

  • handleThe actor whose author feed you requested.
  • totalReturnedNumber of items returned in this response.
  • nextCursorOpaque AppView cursor for the next page. Pass it through unchanged — do not build a cursor from publishedAt (feed order includes repost time).
  • hasMoretrue when nextCursor is present.

Posts

Each item in posts contains:

  • platformPlatform identifier for this response (matches the endpoint's platform).
  • uriAT URI of the post (at://did…/app.bsky.feed.post/rkey).
  • urlbsky.app permalink for the post.
  • cidContent ID (CID) of this post record — stable content-addressed hash.
  • textPost text body. Long URLs may be truncated here — use links[] from facets for the full URI.
  • publishedAtWhen the original post was created (record createdAt). Not repost time — feed order uses repostedAt for isRepost rows.
  • indexedAtWhen the AppView indexed this post. For reposts, feed order follows repostedAt — not this field.
  • authorAuthor of the underlying post: {handle, displayName, did, avatar}. On reposts this is the original author — not the profile you queried. For verification/labels use post-details.
  • engagementEngagement on the underlying post: {likes, reposts, replies, quotes}. On isRepost rows these counts are the original author's — do not average them onto the requested handle without filtering. No view count on Bluesky.
  • embedNormalized embed: type external {url,title,description,thumb} | images {images[{url,alt}]} | video {playlist,thumbnail,alt} | quote {uri,url,text,author,cid,publishedAt}. Never a raw lexicon NSID.

Parameters

NameTypeRequiredDescription
urlstringYesBluesky profile URL, @handle, or handle, e.g. https://bsky.app/profile/handle.bsky.social. The URL platform must match this endpoint's platform. Do not pass cross-platform URLs, e.g. YouTube to TikTok, Instagram to Facebook, LinkedIn to X/Twitter, or Pinterest to Rumble.
limitintegerNoMax items to return (default 25, max 100). Billed per result.
cursorstringNoOpaque pagination cursor from the previous nextCursor. Leave empty for the first page. Do not invent a cursor from publishedAt — the feed is ordered by feed time (reposts sort by repost time).
filterstringNoBluesky getAuthorFeed filter: posts_with_replies (default), posts_no_replies, posts_with_media, posts_and_author_threads, or posts_with_video. Controls replies/media/threads — not reposts. Use includeReposts=false to drop reposts.
includeRepostsbooleanNoWhen false, omit repost rows (reasonRepost). Default true — reposts are included and marked with isRepost / repostedBy / repostedAt.
cachebooleanNoSet true to serve from the 24h response cache (0 credits on hit). Default false — always fetch fresh. Envelope includes cached + cachedAt on hits.

Authentication: send your key as Authorization: Bearer capt_live_.... A typical call costs ~3 credits (0.1/result) — billed per result, so the exact amount scales with how many items you request. Pass cache=true for a free 24h cache hit; default is always fresh (metrics refresh within ~1 hour).

Using an AI agent? This endpoint is the MCP tool bluesky_user_posts via @captapi/mcp. Set it up →

How it works

  1. 1. Sign up — get 100 free credits, no card required.
  2. 2. Create a key from your dashboard.
  3. 3. Send one request to /v1/bluesky/user-posts and parse the JSON response.

Use cases

Creator monitoring

Track a handle's author feed — originals and reposts — with isRepost so boosts are not mistaken for new posts.

Honest analytics

Average engagement only on rows where isRepost is false (or includeReposts=false) so you do not credit someone else's likes to the profile.

Content calendars

Pull text, quote embeds, and links for scheduling or research — no video CDN URLs on this surface.

Partnership vetting

Sample recent posts and quote targets before outreach; use filter=posts_no_replies to skip reply noise.

Frequently asked questions

What does the Bluesky User Posts API do?+

The Bluesky User Posts API lets you list items in bulk with metadata from a public Bluesky post using one GET request to /v1/bluesky/user-posts. It returns clean JSON — no OAuth or infrastructure setup required.

How many credits does the Bluesky User Posts API cost?+

At the default limit this endpoint costs 3 credits (0.1 per result). Billing scales with how many results you request. Pass cache=true to serve from the 24h cache (0 credits on hit); default is always fresh. Hits include cached + cachedAt. Selected profile endpoints also accept cacheMaxAge=1d|3d|7d|14d|30d. Failed or empty results are never charged.

Do I need a Bluesky API key or OAuth?+

No. A single Captapi key works across every platform Captapi supports — YouTube, TikTok, Instagram, Facebook, Twitter/X, Reddit, Threads, Bluesky, Pinterest, LinkedIn, Rumble, Spotify, Kwai, and more. We handle proxies, rate limits, retries, and authentication for you.

Is the Bluesky User Posts API suitable for production use?+

Yes. It is a stable REST endpoint with predictable JSON and automatic retries. Pass cache=true to serve from the 24h cache (0 credits on hit); default is always fresh. Hits include cached + cachedAt. Selected profile endpoints also accept cacheMaxAge=1d|3d|7d|14d|30d. Use it for analytics, monitoring, and content automation.

More Bluesky APIs

Ready to use the Bluesky User Posts API?

Sign up, grab your key, and make your first call in 60 seconds.