{
  "openapi": "3.0.1",
  "info": {
    "title": "Bluesky Posts, Threads, Feeds & Trending Topics (no login)",
    "description": "Public Bluesky data as rows: an account's posts, the replies and quote posts of any post, or any public custom feed - with text, language, engagement counts, hashtags and links. Plus today's trending topics with post counts, and bulk account profiles. Keyless AT Protocol API, UTC dates.",
    "version": "0.1",
    "x-build-id": "2cx25AvDTH6zkOC5Z"
  },
  "servers": [
    {
      "url": "https://api.apify.com/v2"
    }
  ],
  "paths": {
    "/acts/yadroo~bluesky-public-posts/run-sync-get-dataset-items": {
      "post": {
        "operationId": "run-sync-get-dataset-items-yadroo-bluesky-public-posts",
        "x-openai-isConsequential": false,
        "summary": "Executes an Actor, waits for its completion, and returns Actor's dataset items in response.",
        "tags": [
          "Run Actor"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/inputSchema"
              }
            }
          }
        },
        "parameters": [
          {
            "name": "token",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Enter your Apify token here"
          }
        ],
        "responses": {
          "200": {
            "description": "OK"
          }
        }
      }
    },
    "/acts/yadroo~bluesky-public-posts/runs": {
      "post": {
        "operationId": "runs-sync-yadroo-bluesky-public-posts",
        "x-openai-isConsequential": false,
        "summary": "Executes an Actor and returns information about the initiated run in response.",
        "tags": [
          "Run Actor"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/inputSchema"
              }
            }
          }
        },
        "parameters": [
          {
            "name": "token",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Enter your Apify token here"
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/runsResponseSchema"
                }
              }
            }
          }
        }
      }
    },
    "/acts/yadroo~bluesky-public-posts/run-sync": {
      "post": {
        "operationId": "run-sync-yadroo-bluesky-public-posts",
        "x-openai-isConsequential": false,
        "summary": "Executes an Actor, waits for completion, and returns the OUTPUT from Key-value store in response.",
        "tags": [
          "Run Actor"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/inputSchema"
              }
            }
          }
        },
        "parameters": [
          {
            "name": "token",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Enter your Apify token here"
          }
        ],
        "responses": {
          "200": {
            "description": "OK"
          }
        }
      }
    }
  },
  "components": {
    "schemas": {
      "inputSchema": {
        "type": "object",
        "properties": {
          "mode": {
            "title": "What to fetch",
            "enum": [
              "accountPosts",
              "threadReplies",
              "customFeed",
              "trendingTopics",
              "profiles"
            ],
            "type": "string",
            "description": "Five questions, one per run. `accountPosts` is the timeline export: everything the accounts you name have posted, newest first. `threadReplies` turns one post link into its discussion - the post plus its replies, and the posts quoting it when you ask for them. `customFeed` reads any public feed by its link, including the topic feed behind a trending topic, which is the closest thing to a keyword search here. `trendingTopics` answers \"what is Bluesky talking about right now\" with a post count per topic. `profiles` resolves a list of handles to follower, following and post counts. Each mode fills the dataset view with its name; the other views stay empty.",
            "default": "accountPosts"
          },
          "handles": {
            "title": "Bluesky accounts",
            "type": "array",
            "description": "Handles as they appear after the @ in a profile URL (`bsky.app/profile/nytimes.com` -> `nytimes.com`), or raw DIDs (`did:plc:...`). Used by `accountPosts` and `profiles`, ignored by the other modes. In `accountPosts` the row limit is split evenly over the accounts, so three handles with a limit of 60 give roughly the last 20 posts of each. An account that does not exist, was deleted or hides its posts from logged-out viewers yields a single row with `found: false` and the reason in `notFoundReason` - a typo in a long list never disappears silently.",
            "items": {
              "type": "string"
            }
          },
          "accountFilter": {
            "title": "Which posts of the account",
            "enum": [
              "posts_no_replies",
              "posts_with_replies",
              "posts_and_author_threads",
              "posts_with_media"
            ],
            "type": "string",
            "description": "Passed to the source as the author-feed filter, so posts outside it are never fetched or charged. `posts_no_replies` is the default because that is what \"what did this brand publish\" means; switch to `posts_with_replies` for support or community work, where the replies of the account are the interesting half.",
            "default": "posts_no_replies"
          },
          "postUrls": {
            "title": "Post links",
            "type": "array",
            "description": "Posts whose discussion you want, as web links (`bsky.app/profile/<handle>/post/<id>`) or as AT-URIs (`at://did:plc:.../app.bsky.feed.post/<id>`). Used by `threadReplies` only. Each post produces its own rows, all carrying `threadRootUri`, so several links can share one dataset. A deleted or unreachable post yields one row with `found: false`.",
            "items": {
              "type": "string"
            }
          },
          "threadDepth": {
            "title": "How deep into the reply tree",
            "minimum": 0,
            "maximum": 10,
            "type": "number",
            "description": "0 = the post alone (useful together with quote posts), 1 = direct replies, 3 = replies to replies to replies. Deeper trees cost more rows, not more requests: the source returns the whole branch in one call.",
            "default": 3
          },
          "includeQuotes": {
            "title": "Also fetch posts quoting the post",
            "type": "boolean",
            "description": "Add the posts that quote-post the given link, marked `isQuotePost: true` with `quotedPostUri` pointing back at it. That is the half of a reaction a reply tree does not show, and what PR teams look for after an announcement. Combine with `threadDepth: 0` to get the quotes only.",
            "default": false
          },
          "feedUrls": {
            "title": "Public feed links",
            "type": "array",
            "description": "Feeds to read, as web links (`bsky.app/profile/<handle-or-did>/feed/<id>`) or AT-URIs (`at://did:plc:.../app.bsky.feed.generator/<id>`). Used by `customFeed` only. The link of a trending topic from `trendingTopics` mode is such a feed link, so a two-step run (topics, then their feeds) gives you the posts behind a trend. Feeds built by third parties can be empty or slow for reasons outside this actor; the row count per feed is reported in the run summary.",
            "items": {
              "type": "string"
            }
          },
          "trendStatus": {
            "title": "Topic status",
            "enum": [
              "any",
              "trending",
              "cooling"
            ],
            "type": "string",
            "description": "Keep only topics the source currently marks with this status. `trending` is the live list for a newsroom; `cooling` shows what the network has just finished arguing about. Statuses other than these two are passed through untouched and kept when this is `any`.",
            "default": "any"
          },
          "languages": {
            "title": "Post languages",
            "type": "array",
            "description": "Keep only posts whose first declared language is one of these, compared against the `language` column. Empty = every language. The language is declared by the app that published the post, not detected by us, so a handful of posts carry none and are dropped by this filter when it is set. Applies to the three post modes.",
            "items": {
              "type": "string",
              "enum": [
                "en",
                "pt",
                "ja",
                "de",
                "es",
                "fr",
                "it",
                "nl",
                "tr",
                "ru",
                "uk",
                "pl",
                "ko",
                "zh",
                "id",
                "fa",
                "th",
                "ar"
              ],
              "enumTitles": [
                "English",
                "Portuguese",
                "Japanese",
                "German",
                "Spanish",
                "French",
                "Italian",
                "Dutch",
                "Turkish",
                "Russian",
                "Ukrainian",
                "Polish",
                "Korean",
                "Chinese",
                "Indonesian",
                "Persian",
                "Thai",
                "Arabic"
              ]
            }
          },
          "minLikes": {
            "title": "At least this many likes",
            "minimum": 0,
            "maximum": 1000000,
            "type": "number",
            "description": "Keep only posts with at least this many likes at fetch time - the quick way to get the posts of an account that actually travelled. Empty = no floor. Engagement counts are a snapshot: the same post re-fetched tomorrow has different numbers, which is why every row carries `fetchedAt`."
          },
          "sinceHours": {
            "title": "Posted in the last N hours",
            "minimum": 1,
            "maximum": 8760,
            "type": "number",
            "description": "Rolling window in hours, counted in UTC from the moment the run starts: 24 for a day, 168 for a week. This is the input to use on a schedule - it needs no date editing between runs. In `accountPosts` paging stops as soon as the account's feed reaches posts older than the window, so a narrow window is also a cheap run. In `threadReplies` and `customFeed` the window only filters the posts the source returns: a thread comes in one answer, and a custom feed is not ordered by time."
          },
          "onlyNew": {
            "title": "Skip posts seen in earlier runs",
            "type": "boolean",
            "description": "Remember the posts this run writes in a named key-value store of your account (`bluesky-seen`, or `bluesky-seen-<task id>` for a task) and, on the next run of the same actor or task, write only posts that were not written before. Made for monitoring: every run then holds just what is new, and an empty run means nothing was posted. The memory is kept per actor or task, so two tasks watching two accounts do not interfere. Only posts that were actually written are remembered: a run stopped by your maximum cost per run or by the timeout leaves the rest for the next run.",
            "default": false
          },
          "includeReposts": {
            "title": "Include reposts of other accounts",
            "type": "boolean",
            "description": "Author feeds mix in what the account reposted. They are dropped by default, so rows are the account's own words; switch this on to study what it amplifies. Kept rows are marked `isRepost: true` and keep the original author in `authorHandle`.",
            "default": false
          },
          "maxItems": {
            "title": "Maximum rows",
            "minimum": 1,
            "maximum": 1000,
            "type": "number",
            "description": "Hard cap on the rows this run writes, and therefore on what it costs. Paging stops as soon as the cap is reached. In `accountPosts` the cap is divided over the handles you named, in `customFeed` over the feeds and in `threadReplies` over the post links; in `profiles` it is the number of accounts read. The run also stops at your \"Maximum cost per run\" and ends with a status that says so.",
            "default": 50
          },
          "fields": {
            "title": "Only these columns",
            "type": "array",
            "description": "Keep only the named columns, in the order given - for example `authorHandle, text, likeCount, createdAt, url`. Empty = every column of the mode. Letter case is corrected (`AuthorHandle` -> `authorHandle`); a name that is not a column of the mode is left out and reported in the status message with the nearest column; a list in which no name is a column of the mode stops the run with the list of valid columns. The identifying columns stay in every row: `rowType`, `postUri`, `sourceRef`, `found` in the post modes, `rowType`, `topic` in `trendingTopics`, `rowType`, `handle`, `found` in `profiles`.",
            "items": {
              "type": "string"
            }
          }
        }
      },
      "runsResponseSchema": {
        "type": "object",
        "properties": {
          "data": {
            "type": "object",
            "properties": {
              "id": {
                "type": "string"
              },
              "actId": {
                "type": "string"
              },
              "userId": {
                "type": "string"
              },
              "startedAt": {
                "type": "string",
                "format": "date-time",
                "example": "2025-01-08T00:00:00.000Z"
              },
              "finishedAt": {
                "type": "string",
                "format": "date-time",
                "example": "2025-01-08T00:00:00.000Z"
              },
              "status": {
                "type": "string",
                "example": "READY"
              },
              "meta": {
                "type": "object",
                "properties": {
                  "origin": {
                    "type": "string",
                    "example": "API"
                  },
                  "userAgent": {
                    "type": "string"
                  }
                }
              },
              "stats": {
                "type": "object",
                "properties": {
                  "inputBodyLen": {
                    "type": "integer",
                    "example": 2000
                  },
                  "rebootCount": {
                    "type": "integer",
                    "example": 0
                  },
                  "restartCount": {
                    "type": "integer",
                    "example": 0
                  },
                  "resurrectCount": {
                    "type": "integer",
                    "example": 0
                  },
                  "computeUnits": {
                    "type": "integer",
                    "example": 0
                  }
                }
              },
              "options": {
                "type": "object",
                "properties": {
                  "build": {
                    "type": "string",
                    "example": "latest"
                  },
                  "timeoutSecs": {
                    "type": "integer",
                    "example": 300
                  },
                  "memoryMbytes": {
                    "type": "integer",
                    "example": 1024
                  },
                  "diskMbytes": {
                    "type": "integer",
                    "example": 2048
                  }
                }
              },
              "buildId": {
                "type": "string"
              },
              "defaultKeyValueStoreId": {
                "type": "string"
              },
              "defaultDatasetId": {
                "type": "string"
              },
              "defaultRequestQueueId": {
                "type": "string"
              },
              "buildNumber": {
                "type": "string",
                "example": "1.0.0"
              },
              "containerUrl": {
                "type": "string"
              },
              "usage": {
                "type": "object",
                "properties": {
                  "ACTOR_COMPUTE_UNITS": {
                    "type": "integer",
                    "example": 0
                  },
                  "DATASET_READS": {
                    "type": "integer",
                    "example": 0
                  },
                  "DATASET_WRITES": {
                    "type": "integer",
                    "example": 0
                  },
                  "KEY_VALUE_STORE_READS": {
                    "type": "integer",
                    "example": 0
                  },
                  "KEY_VALUE_STORE_WRITES": {
                    "type": "integer",
                    "example": 1
                  },
                  "KEY_VALUE_STORE_LISTS": {
                    "type": "integer",
                    "example": 0
                  },
                  "REQUEST_QUEUE_READS": {
                    "type": "integer",
                    "example": 0
                  },
                  "REQUEST_QUEUE_WRITES": {
                    "type": "integer",
                    "example": 0
                  },
                  "DATA_TRANSFER_INTERNAL_GBYTES": {
                    "type": "integer",
                    "example": 0
                  },
                  "DATA_TRANSFER_EXTERNAL_GBYTES": {
                    "type": "integer",
                    "example": 0
                  },
                  "PROXY_RESIDENTIAL_TRANSFER_GBYTES": {
                    "type": "integer",
                    "example": 0
                  },
                  "PROXY_SERPS": {
                    "type": "integer",
                    "example": 0
                  },
                  "PROXY_UNBLOCKER_UNITS": {
                    "type": "integer",
                    "example": 0
                  }
                }
              },
              "usageTotalUsd": {
                "type": "number",
                "example": 0.00005
              },
              "usageUsd": {
                "type": "object",
                "properties": {
                  "ACTOR_COMPUTE_UNITS": {
                    "type": "integer",
                    "example": 0
                  },
                  "DATASET_READS": {
                    "type": "integer",
                    "example": 0
                  },
                  "DATASET_WRITES": {
                    "type": "integer",
                    "example": 0
                  },
                  "KEY_VALUE_STORE_READS": {
                    "type": "integer",
                    "example": 0
                  },
                  "KEY_VALUE_STORE_WRITES": {
                    "type": "number",
                    "example": 0.00005
                  },
                  "KEY_VALUE_STORE_LISTS": {
                    "type": "integer",
                    "example": 0
                  },
                  "REQUEST_QUEUE_READS": {
                    "type": "integer",
                    "example": 0
                  },
                  "REQUEST_QUEUE_WRITES": {
                    "type": "integer",
                    "example": 0
                  },
                  "DATA_TRANSFER_INTERNAL_GBYTES": {
                    "type": "integer",
                    "example": 0
                  },
                  "DATA_TRANSFER_EXTERNAL_GBYTES": {
                    "type": "integer",
                    "example": 0
                  },
                  "PROXY_RESIDENTIAL_TRANSFER_GBYTES": {
                    "type": "integer",
                    "example": 0
                  },
                  "PROXY_SERPS": {
                    "type": "integer",
                    "example": 0
                  },
                  "PROXY_UNBLOCKER_UNITS": {
                    "type": "integer",
                    "example": 0
                  }
                }
              }
            }
          }
        }
      }
    }
  }
}