# Post schema (/docs/schema/post) The unified SocialCrawl post schema. Every field, its type, per-platform availability, and a machine-readable JSON Schema, generated from the canonical Zod source. Every SocialCrawl endpoint that returns a post gives you this exact shape, whatever the source platform. Write your parser once and the same code reads post data from every platform below. That is the unified schema: one contract instead of a dozen raw upstream formats. ## Field reference | Field | Type | Nullable | Description | | ----- | ---- | -------- | ----------- | | `id` | `string` | No | Platform-specific post ID (always a string; numeric upstream IDs are stringified) | | `url` | `string` | Yes | Direct URL to the post on the source platform | | `content.text` | `string` | Yes | Post caption, description, or text content | | `content.media_urls` | `string` or `string[]` | Yes | URL(s) of the primary media. Single string for video/photo posts; array of strings for carousels. | | `content.thumbnail_url` | `string` | Yes | URL to thumbnail image | | `content.duration_seconds` | `number` | Yes | Video/clip duration in seconds (null for non-video posts) | | `author.username` | `string` | Yes | Author username | | `author.display_name` | `string` | Yes | Author display name | | `author.avatar_url` | `string` | Yes | URL to author profile picture | | `author.verified` | `boolean` | Yes | Whether the author account is verified | | `engagement.views` | `number` | Yes | View count (if available). For Instagram video/reels this is the play count: the headline 'Views' the IG app shows. Instagram removed per-post play counts from its public web pages in August 2026, so `GET /v1/instagram/post` now fills the count automatically from a second source within the same call: videos and reels keep a numeric `views` with no extra endpoint or workaround. Note: since mid-July 2026 Instagram's play count is Instagram-only. It no longer includes Facebook crosspost views (Meta-side change; the app UI changed identically). For combined reach, also fetch the Facebook crosspost via `/v1/facebook/post`. | | `engagement.likes` | `number` | Yes | Like / reaction count | | `engagement.comments` | `number` | Yes | Comment count. Note: on `GET /v1/instagram/post` this is Instagram's `edge_media_to_parent_comment.count` (top-level comments); the IG list endpoints report the mobile `comment_count` total (includes replies). Both land on this same field. | | `engagement.shares` | `number` | Yes | Share / repost / retweet count. On Instagram this is `reshare_count` (the paper-plane Share / Send count) and it exists only on Instagram's mobile surface, so it is returned by `/v1/instagram/post/stats`, `/v1/instagram/profile/reels/full`, and `/v1/instagram/profile/posts/full`. The web-sourced Instagram list and search endpoints return `null` (never fabricated). | | `engagement.saves` | `number` | Yes | Save / bookmark count. `null` on Instagram: the save count is platform-private and Instagram exposes no numeric save metric on any surface (never fabricated). | | `flags.nsfw` | `boolean` | Yes | NSFW flag (null when platform does not surface) | | `flags.spoiler` | `boolean` | Yes | Spoiler flag (null when platform does not surface) | | `flags.pinned` | `boolean` | Yes | Pinned-to-profile flag (null when platform does not surface) | | `flags.deleted` | `boolean` | No | Whether the post is tombstoned (always present) | | `flags.likes_hidden` | `boolean` | Yes | Present and `true` when the creator has hidden the like count. `engagement.likes` is `null` in that case (never the platform's decoy preview number). Absent on normal posts. | | `flags.comments_hidden` | `boolean` | Yes | Present and `true` when the upstream reports the comment count as hidden. `engagement.comments` is `null` in that case. Absent on normal posts. | | `flags.shares_hidden` | `boolean` | Yes | | | `flags.views_hidden` | `boolean` | Yes | | | `flags.saves_hidden` | `boolean` | Yes | | | `published_at` | `string` or `number` | Yes | Post creation timestamp as an ISO 8601 UTC string. When the upstream sent a Unix epoch it is converted here and the raw epoch is preserved under `post.ext.published_at_epoch` for one deprecation cycle. | ## Extension fields (`ext`) Platform-specific passthrough. Each field is present only on the platforms that expose it and is absent everywhere else, so treat every `ext.*` field as optional. These carry the richer, per-platform signals the unified leaves cannot hold, and the join keys that chain endpoints together. | Field | Type | Nullable | Description | | ----- | ---- | -------- | ----------- | | `ext.music_id` | `string` | Yes | TikTok music/clip id (exact string): pass to `/v1/tiktok/song/videos?clipId=` to find videos using the same sound | | `ext.matched_song_id` | `string` | Yes | TikTok only. The catalogue song TikTok matched the video's sound to, as an exact digit string. An official clip and the original sounds creators upload with it have different `music_id` values and the same `matched_song_id`, so group rows on it to count every use of one song. It is not a clipId: `/v1/tiktok/song` and `/v1/tiktok/song/videos` do not accept it. `/v1/tiktok/search/music` carries it on each sound, so a search on the song's title and artist, kept to the sounds with the same `matched_song_id`, gives the song's official sounds and their `video_count`. Absent when TikTok matched the sound to no song, and on rows served from a source that does not report the match. | | `ext.matched_song_title` | `string` | Yes | TikTok only. The title of the song in `matched_song_id`. Absent when there is no matched song. | | `ext.matched_song_artist` | `string` | Yes | TikTok only. The artist of the song in `matched_song_id`, as TikTok's catalogue names it. Absent when there is no matched song. | | `ext.music_title` | `string` | Yes | TikTok only. The title of the video's own sound (`music_id`). An uploaded sound is titled like `original sound - `; the song it plays, when TikTok recognised one, is `matched_song_title`. | | `ext.music_artist` | `string` | Yes | TikTok only. The artist TikTok shows for the video's own sound. On an original sound this is the uploader's display name, not the song's artist; use `matched_song_artist` for that. | | `ext.music_is_original` | `boolean` | Yes | TikTok only. `true` when the video's sound is an original sound a creator uploaded, `false` when it is a catalogue track. Absent when the source does not say. | | `ext.author_id` | `string` | Yes | The creator's platform-native numeric user id. On TikTok search and list items, pass to `/v1/tiktok/profile?user_id=` for the creator's current follower count (survives username changes). On Instagram `/v1/instagram/search/reels`, `/v1/instagram/search/hashtag` and `/v1/instagram/location/posts` items it is present on every row, accepted by `/v1/instagram/profile/country?user_id=` and `/v1/instagram/basic-profile?userId=`. On Facebook it appears when the upstream exposed a numeric actor id and no real handle. | | `ext.author_url` | `string` | Yes | The posting account's profile URL, so a matching post can be followed to its account. Present on `/v1/facebook/search/posts` rows: the vanity or `/people///` URL when Facebook sends one, otherwise `https://www.facebook.com/profile.php?id=` built from the account id. Pass it as `url` to `/v1/facebook/profile` (or to `/v1/prism/profiles` with `platform: facebook`). Null when the row names neither an account URL nor a numeric account id. Absent on other endpoints. | | `ext.author_followers` | `number` | Yes | The creator's follower count as embedded in the search payload itself, when the search source happens to carry one. On Instagram `search/reels` it is null on a plain call, because Instagram stopped sending follower counts in its search payload in August 2026; send `include=creator` (or `country`) and it is filled from the creator's profile, 2 credits per creator looked up. It stays null when that lookup does not resolve. | | `ext.author_following` | `number` | Yes | | | `ext.author_posts_count` | `number` | Yes | | | `ext.author_location` | `string` | Yes | The free text the author wrote in their profile's location field, exactly as written (for example `Johannesburg, South Africa`). It is not a country code and is not checked; discover reads a country from it into `geo.country` (`source: author_location`). Present on X tweet and reply rows; null or absent when the author left it blank. | | `ext.in_reply_to_id` | `string` | Yes | | | `ext.in_reply_to_username` | `string` | Yes | | | `ext.conversation_id` | `string` | Yes | | | `ext.author_country` | `string` | Yes | The creator's country. On Instagram it is the country the creator declares on the About this account panel, as a country name (for example `Spain`), and it is not where the post was filmed. It is present on `/v1/instagram/search/reels` when the request sends `include=creator`, `include=country` or `country`, and on `/v1/instagram/search/hashtag` and `/v1/instagram/location/posts` when it sends `include=country`, filled by looking the creator up. On YouTube rows joined with `include=channel` it is the channel's own country as an ISO 3166-1 alpha-2 code (for example `ZA`). Null when the platform publishes no country for the creator or the lookup did not resolve, and nothing is guessed; absent on a plain call. | | `ext.author_public_email` | `string` | Yes | The public contact email on the creator's profile. Present only on `/v1/instagram/search/reels` when the request sends `include=creator`, filled by looking the creator up. Null when the creator lists no public email or the lookup did not resolve; absent on a plain call. | | `ext.author_public_phone` | `string` | Yes | The public contact phone number on the creator's profile. Present only on `/v1/instagram/search/reels` when the request sends `include=creator`, filled by looking the creator up. Null when the creator lists no public phone or the lookup did not resolve; absent on a plain call. | | `ext.download_count` | `number` | Yes | How many times the video has been saved to a device. TikTok only, and distinct from `engagement.saves`: a save keeps the video in a private collection on the platform, a download takes a copy off it, and TikTok counts the two separately. Present on TikTok post, search and post-list responses; absent everywhere else. | | `ext.region` | `string` | Yes | TikTok only: the country TikTok registers the video to, as an ISO 3166-1 alpha-2 code (normally the creator's account country when they posted). It is not the viewer's country, not the `region` you requested, and not a language. On `/v1/tiktok/trending`, `/v1/tiktok/search`, `/v1/tiktok/search/top`, `/v1/tiktok/profile/videos`, `/v1/tiktok/search/hashtag` and `/v1/tiktok/song/videos` it is how you tell which rows are from a given country: filter on it when you need only that country. A row whose source omits the country stays null. The `region` request parameter still only sets the proxy. | | `ext.subreddit` | `string` | Yes | Reddit subreddit name (search/list items): pass to `/v1/reddit/subreddit/details?subreddit=` | | `ext.title` | `string` | Yes | | | `ext.selftext` | `string` | Yes | | | `ext.link_domain` | `string` | Yes | | | `ext.upvote_ratio` | `number` | Yes | Reddit only: the share of a post's votes that are upvotes, as a fraction from 0 to 1 and usually close to 1 (six live rows measured 1, 1, 1, 0.86, 0.75, 1). Fractional despite the integer type this schema emits for every numeric leaf, the same caveat as `author.ext.average_rating`. Populated on `/v1/reddit/search` rows whose source carries it, and null everywhere else on Reddit including `/v1/reddit/post` and `/v1/reddit/subreddit`. | | `ext.flair` | `string` | Yes | | | `ext.content_language` | `string` | Yes | The language the platform itself tags the post with, when it sends one: Reddit's own language tag on Reddit lanes, and TikTok's caption-language tag (for example `de`) on `/v1/tiktok/trending?feed=local`. Null when the platform could not tell (Reddit `und`, TikTok `un`, common on short or emoji-only captions); absent where the source sends no tag. Never inferred from the text by us: that is `post.computed.language`. | | `ext.type` | `string` | Yes | | | `ext.content_type` | `string` | Yes | | | `ext.ticker_symbols` | `string[]` | Yes | | | `ext.video_view_count` | `number` | Yes | Instagram's legacy 3-second-view count. Historical: Instagram stopped serving it in August 2026 (removed from its web post surface along with the web play count), so fresh `/v1/instagram/post` lookups no longer carry it and no source can restore it. Use `engagement.views` (the play count) instead. | | `ext.ig_play_count` | `number` | Yes | Instagram-only play count (`ig_play_count`). Since mid-July 2026 Instagram's headline play count (`engagement.views`) no longer includes Facebook crosspost views and equals this value; it is surfaced explicitly so you can tell the Instagram-only figure apart and detect any future re-divergence. For combined Instagram + Facebook reach, also fetch the Facebook crosspost via `/v1/facebook/post`. Present on `/v1/instagram/post/stats` and, since the August 2026 views fix, on `/v1/instagram/post` for video posts. | | `ext.repost_count` | `number` | Yes | | | `ext.media_type` | `string` | Yes | | | `ext.text_truncated` | `boolean` | Yes | | | `ext.ip_location` | `string` | Yes | | | `ext.carousel_count` | `number` | Yes | | | `ext.remix_count` | `number` | Yes | | | `ext.audio_cluster_id` | `string` | Yes | Instagram's audio cluster for a reel, as an exact digit string: the id Instagram uses to group different uploads of the same sound. Present on `/v1/instagram/audio/reels` rows and on `/v1/instagram/profile/reels` with `include=stats`; absent on a row when it is not available and on every other surface. | | `ext.facebook_likes` | `number` | Yes | Instagram only: the Facebook cross-post share that was EXCLUDED from `engagement.likes` on this row. A post shared to Facebook arrives from some sources with its Facebook likes already folded into the Instagram count, so the share is subtracted and published here, which keeps `engagement.likes` the Instagram-only figure instagram.com shows on the post. Add the two together for the combined number. Absent when the read carried no Facebook share, and absent on a post whose owner hides the like count, because nothing can be subtracted from a null. A response that excluded a share also carries a note in `data._warnings`. | | `ext.facebook_comments` | `number` | Yes | Instagram only: the Facebook cross-post share that was EXCLUDED from `engagement.comments` on this row, the comment counterpart of `post.ext.facebook_likes`. Each leaf appears only for the count it actually changed, so a post whose likes are hidden but whose comments were reconciled carries this one alone. | | `ext.instagram_views` | `number` | Yes | Instagram only: the Instagram-only play count of a video, the same figure on every Instagram endpoint. `engagement.views` keeps each endpoint's established meaning: on `/v1/instagram/profile/reels`, `/v1/instagram/audio/reels`, `/v1/instagram/search/reels` and `/v1/instagram/search/hashtag` it can include the post's Facebook cross-post views, while on `/v1/instagram/post` and `/v1/instagram/post/stats` it is Instagram-only. Read this leaf when you compare one post across endpoints. Absent on photos and when the source did not report the Instagram-only figure. | | `ext.facebook_views` | `number` | Yes | Instagram only: the Facebook cross-post part of a video's play count, the counterpart of `post.ext.instagram_views`. Present only when the source reported the Facebook part, or a combined total above the Instagram figure. Absent does not mean zero: some sources report the Instagram figure alone even for a cross-posted video. | | `ext.published_at_epoch` | `number` | Yes | Raw Unix epoch for `published_at` (seconds, or milliseconds when the upstream sent millis). Present only when the upstream sent a numeric epoch that was normalised to the ISO 8601 `published_at` string. Kept for one deprecation cycle for integrations pinned to the numeric form. | | `ext.usertags` | `any[]` | Yes | | | `ext.coauthors` | `any[]` | Yes | Instagram collaborative posts (the native "Collab" feature). The full list of co-author accounts on the post, as `{ id, username, full_name, is_verified, profile_pic_url }`. A collab post has ONE producer and appears in every co-author's grid, so `post.author` is whichever account created it, which is not necessarily the profile you queried. The complete set of accounts on a post is `post.author.username` plus every `username` in this array. An empty array means Instagram reports the post as NOT a collab; the field is absent on surfaces that carry no co-author signal, including `/v1/instagram/post` (its web source ships the field permanently empty, so use `/v1/instagram/post/stats` for a single post). | | `ext.music` | `object` | Yes | | | `ext.sponsor_tags` | `any[]` | Yes | Instagram only: the brand accounts the post tags as its paid partner, as usernames (`["rolex"]`). `[]` on a post with no partner tagged. Present on `/v1/instagram/post/stats`; absent on every other endpoint. | | `ext.sponsored_disclosed` | `boolean` | Yes | The platform's own disclosure that the post is paid or promotional: on Instagram the paid-partnership label (`is_paid_partnership`) or a tagged brand partner, on TikTok the label TikTok shows viewers ("Paid partnership", "Commission paid", "Promotional content"). `false` when the post carries the flag unset, null when it carries none. Present on `/v1/instagram/post/stats`, `/v1/instagram/profile/posts`, `/v1/instagram/profile/reels`, `/v1/instagram/search/reels`, `/v1/tiktok/profile/videos` and `/v1/tiktok/search`; absent on every other endpoint. | | `ext.ai_label` | `string` | Yes | Instagram only: Instagram's AI-content label on the post, as the method Instagram reports: `classifier_score_high` (Instagram detected it, shown as "Likely made with AI"), `ai_created` or `ai_edited` (declared or detected as made or edited with AI). Null when the post carries no AI label. Present on `/v1/instagram/post/stats`; absent on every other endpoint. | | `ext.story_mentions` | `string[]` | Yes | Instagram stories only: the accounts the story mentions with a mention sticker, as usernames in alphabetical order. `[]` when it mentions nobody. Present on `/v1/instagram/stories`; absent on every other endpoint. | | `ext.story_links` | `string[]` | Yes | Instagram stories only: where the story's link stickers lead, as URLs in alphabetical order. Instagram wraps each link in its own redirect with a per-view click id; both are removed, so this is the destination itself. `[]` when the story has no link sticker. Present on `/v1/instagram/stories` and `/v1/instagram/highlight/detail`; absent on every other endpoint. | | `ext.story_reshared_posts` | `string[]` | Yes | Instagram stories only: the feed posts the story reshares, as post URLs (`https://www.instagram.com/p/{shortcode}/`, which `/v1/instagram/post` takes). `[]` when it reshares none. Present on `/v1/instagram/stories`; absent on every other endpoint. | | `ext.location` | `object` | Yes | | | `ext.media` | `object[]` | Yes | | | `ext.top_comments` | `object[]` | Yes | | | `ext.hashtags` | `string[]` | Yes | | | `ext.mentions` | `string[]` | Yes | | | `ext.mentioned_user_ids` | `string[]` | Yes | | | `ext.quoted_post` | `object` | Yes | Threads quote posts: the post this one quotes, as `{ id, url, author: { id, username }, text, media_urls, thumbnail_url }`. A quote post usually carries no caption or media of its own, and the text and video you see on the post's page belong to this attachment, by a different author. It is returned here rather than merged into `post.content`, so `content.*` always stays the outer post's own content and one account's media is never attributed to another. Absent on posts that are not quote posts. | | `ext.retweeted_post` | `object` | Yes | | | `ext.quote_count` | `number` | Yes | | | `ext.all_media_urls` | `string[]` | Yes | | | `ext.reaction_counts` | `any[]` | Yes | | | `ext.share_urn` | `string` | Yes | | | `ext.post_type` | `string` | Yes | | | `ext.activity_id` | `string` | Yes | | | `ext.published_at_precision` | `string` | Yes | | | `ext.author_urn` | `string` | Yes | | | `ext.author_headline` | `string` | Yes | | | `ext.author_type` | `string` | Yes | | | `ext.is_repost_quote` | `boolean` | Yes | | | `ext.article` | `object` | Yes | | | `ext.reaction_type` | `string` | Yes | | | `ext.download_media_urls` | `object[]` | Yes | | | `ext.tags` | `string[]` | Yes | | | `ext.categoryId` | `string` | Yes | | | `ext.categoryTitle` | `string` | Yes | | | `ext.topicCategories` | `string[]` | Yes | | | `ext.duration` | `string` | Yes | | | `ext.license` | `string` | Yes | | | `ext.madeForKids` | `boolean` | Yes | | | `ext.defaultAudioLanguage` | `string` | Yes | | | `ext.hasPaidProductPlacement` | `boolean` | Yes | | | `ext.caption` | `string` | Yes | | | `ext.position` | `number` | Yes | | | `ext.playlistId` | `string` | Yes | | | `ext.videoOwnerChannelId` | `string` | Yes | | | `ext.videoPublishedAt` | `string` | Yes | | | `ext.description` | `string` | Yes | | | `ext.default_language` | `string` | Yes | | | `ext.localizations` | `object` | Yes | | | `ext.playlist_item_id` | `string` | Yes | | | `ext.playlist_owner_channel_id` | `string` | Yes | | | `ext.playlist_owner_title` | `string` | Yes | | | `ext.channel_id` | `string` | Yes | | | `ext.published_label` | `string` | Yes | | | `ext.published_precision` | `string` | Yes | | | `ext.title_maybe_translated` | `boolean` | Yes | | | `ext.video_count` | `number` | Yes | | | `ext.posts_count` | `number` | Yes | `/v1/instagram/hashtag` only: the exact number of public posts Instagram counts under the hashtag. Live: it moves between calls minutes apart. | | `ext.commerce` | `object` | Yes | | | `ext.on_screen_texts` | `string[]` | Yes | | | `ext.topic_tag` | `string` | Yes | | | `ext.reshare_count` | `number` | Yes | | | `ext.dsp_ids` | `object` | Yes | | | `ext.topic_tag_id` | `string` | Yes | | | `ext.amazon_shop_lists` | `object[]` | Yes | | | `ext.amazon_shop_trending_picks` | `object[]` | Yes | | | `ext.amazon_shop_curations` | `object[]` | Yes | | | `ext.amazon_shop_socials` | `string[]` | Yes | | | `ext.ad` | `object` | Yes | Ad Library envelope (Facebook `adlibrary/ad` and `adlibrary/company/ads` items): page_id, currency, spend, reach_estimate, publisher_platforms, categories, targeted_or_reached_countries, cta_text, cta_type, link_url, is_active, end_date_iso, display_format, title, video_hd_url, video_sd_url. Absent on every non-ad surface. | | `ext.apple_music` | `object` | Yes | | | `ext.feedback_id` | `string` | Yes | | | `ext.question_id` | `string` | Yes | Naver KnowledgeiN (`/v1/naver/kin/search`) only: the question's id (Naver's `docId`), read from the row's link. Kin returns one row per answer, so several rows can share it; send `group=question` for one row per question. | | `ext.answer_no` | `number` | Yes | Naver KnowledgeiN only: which answer of the question this row is (Naver's `answerNo`), read from the row's link. | | `ext.answer_nos` | `number[]` | Yes | Naver KnowledgeiN with `group=question` only: every answer number of the question that was on the page, best-ranked first. | | `ext.published_at_est` | `string` | Yes | Naver KnowledgeiN only: the question's date ESTIMATED from its id (`YYYY-MM-DD`, Korea time), never a published date, so `published_at` stays null. Absent for questions older than the calibration table. | | `ext.date_basis` | `string` | Yes | How `post.ext.published_at_est` was derived. `kin_docid_estimate`: interpolated from the question id against question pages whose posted date was read. | | `ext.event` | `object` | Yes | | | `ext.trend` | `object` | Yes | Trend-board envelope: what TikTok's own trend board says about the row. On `/v1/tiktok/hashtags/popular`: `rank`, `country_code`, `period_days`, `posts` and `views` for the window (not lifetime totals), `industry` / `industry_id` / `industry_label` for the first board the hashtag was read from (null for the overall board), `boards` listing EVERY board it ranks on as `{ industry, industry_id, industry_label, rank }` in board order (so a hashtag in the top 3 overall and on an industry board shows both), `popularity_curve` as `{ date, value }` with value 0 to 100 relative to the window's peak, and `top_creators`. On `/v1/tiktok/videos/popular`: `rank`, `country_code`, `period_days`, `order_by`, `period_views`, `organic_views`, `engagement_rate`, `six_second_view_through_rate`, `content_tags`. Absent on every non-board surface. | | `ext.updated_at` | `string` | Yes | | | `ext.alt_text` | `string` | Yes | | | `ext.board_name` | `string` | Yes | | | `ext.numeric_id` | `number` | Yes | | | `ext.outbound_url` | `string` | Yes | | | `ext.group` | `object` | Yes | | ## Platform availability 28 platforms return the `Post` shape. `id`, `flags.deleted` are never null on any platform. The fields below vary: **yes** means the platform populates it (the value may still be null); a blank means the platform never provides it, so it is always null.
| Platform | `author.verified` | `engagement.saves` | `content.duration_seconds` | `engagement.shares` | `engagement.views` | `author.avatar_url` | `content.media_urls` | `engagement.comments` | `url` | `content.thumbnail_url` | `engagement.likes` | `flags.pinned` | | -------- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | | Amazon | yes | | | | | yes | | | | yes | | | | Apple Music | | | yes | | | | yes | | yes | yes | | | | Bluesky | | | | yes | | yes | | yes | | | yes | | | Douyin | yes | yes | yes | yes | | yes | yes | yes | yes | yes | yes | yes | | Facebook | yes | yes | yes | yes | yes | yes | yes | yes | yes | yes | yes | | | Gab | yes | | | yes | | yes | | yes | yes | | yes | | | GitHub | | | | yes | | yes | yes | yes | yes | | yes | | | Google | | | | | yes | | yes | | yes | yes | | | | Hacker News | | | | | | | yes | yes | | | yes | | | Instagram | yes | yes | yes | yes | yes | yes | yes | yes | yes | yes | yes | | | Kick | yes | yes | yes | yes | yes | yes | yes | yes | | yes | yes | | | Kwai | yes | yes | yes | yes | yes | yes | yes | yes | yes | yes | yes | | | LinkedIn | | | yes | yes | yes | yes | yes | yes | yes | yes | yes | | | Naver | | | | yes | yes | | yes | yes | yes | yes | yes | | | Pinterest | yes | yes | yes | yes | yes | yes | yes | yes | yes | yes | yes | | | Product Hunt | | | | | | | | | yes | | | | | Quora | | | | yes | yes | | | yes | yes | | yes | | | Reddit | yes | yes | yes | yes | yes | yes | yes | yes | yes | yes | yes | yes | | Rumble | | | yes | | yes | | | | yes | yes | yes | | | Spotify | | | yes | | yes | yes | yes | | | yes | | | | Telegram | | | yes | | yes | | | | yes | yes | yes | | | Threads | yes | | | yes | yes | yes | yes | yes | yes | yes | yes | | | TikTok | yes | yes | yes | yes | yes | yes | yes | yes | yes | yes | yes | yes | | Truth Social | yes | yes | yes | yes | yes | yes | | yes | yes | yes | yes | | | Twitch | yes | yes | yes | yes | yes | yes | yes | yes | | yes | yes | | | Twitter/X | yes | yes | yes | yes | yes | yes | yes | yes | | yes | yes | | | Xiaohongshu | | yes | yes | yes | | yes | yes | yes | yes | yes | yes | yes | | YouTube | | | yes | | yes | yes | yes | yes | yes | yes | yes | |
## Machine-readable schema Validate responses programmatically against the JSON Schema (2020-12): [`/schemas/post.json`](/schemas/post.json) Point a validator (Ajv, `jsonschema`, or your framework's) at that URL, or hand it to an agent so it can check the shape without a live call. ## Returned by Endpoints with the `Post` / `PostList` archetype return this shape: [Amazon](/platforms/amazon) · [Apple Music](/platforms/apple_music) · [Bluesky](/platforms/bluesky) · [Douyin](/platforms/douyin) · [Facebook](/platforms/facebook) · [Gab](/platforms/gab) · [GitHub](/platforms/github) · [Google](/platforms/google) · [Hacker News](/platforms/hackernews) · [Instagram](/platforms/instagram) · [Kick](/platforms/kick) · [Kwai](/platforms/kwai) · [LinkedIn](/platforms/linkedin) · [Naver](/platforms/naver) · [Pinterest](/platforms/pinterest) · [Product Hunt](/platforms/producthunt) · [Quora](/platforms/quora) · [Reddit](/platforms/reddit) · [Rumble](/platforms/rumble) · [Spotify](/platforms/spotify) · [Telegram](/platforms/telegram) · [Threads](/platforms/threads) · [TikTok](/platforms/tiktok) · [Truth Social](/platforms/truthsocial) · [Twitch](/platforms/twitch) · [Twitter/X](/platforms/twitter) · [Xiaohongshu](/platforms/xiaohongshu) · [YouTube](/platforms/youtube) See how the same fields map to each platform's raw upstream names in the [cross-platform field equivalence table](/docs/schema/field-equivalence.md).