---
title: "List Reddit post comments"
method: GET
path: "/reddit/post/comments"
tags: ["reddit"]
---

# List Reddit post comments

`GET /reddit/post/comments`

## Request

- Base URL: `https://www.socialcrawl.dev/v1`
- URL: `https://www.socialcrawl.dev/v1/reddit/post/comments`
- Auth: API key in header `x-api-key`

Returns the full threaded comment tree for a Reddit post. Nested replies are auto-expanded by following upstream pagination, so a single call returns the deep tree (not just top-level comments). Each comment includes the author, body, score, direct-reply count, creation timestamp, its nesting depth at `ext.depth`, and a recursive `replies[]` array. `items[]` holds only the top-level comments, so `items.length` and `pagination.page_size` count those alone; `data.comments_returned` counts every comment in the response, replies included, and is the number to compare with the post's comment count. Comment bodies are Reddit's own markdown source, so `comment.text` can contain markdown such as `**bold**` and `[label](url)`. Comment ids are unique within a response: cursor windows can re-offer a boundary node, and those are de-duplicated before the tree is returned. Very large threads are bounded, and `data.truncated` tells you whether more of the thread exists than the response carries. It is not simply a record of our own paging: a response that reached the source's end of the thread is still reported as `truncated: true` when it falls far short of the post's own comment count, because that end is the end of one ranking window rather than the end of the thread. So `truncated: true` can arrive with no `next_cursor`, which means the thread is incomplete and this endpoint cannot fetch you the rest. A whole thread pages from one top-level cursor, so `ext.replies_cursor` on an individual branch is rare. `truncated: false` means the response looks complete against the post's own count, which is normally still higher than the comments you receive because Reddit counts removed, deleted, and filtered replies that no listing returns to anyone. `items[]` can also contain a comment whose own parent was removed upstream: it sits at the top level beside the real roots, and `parent_id` is what separates them, because a root's `parent_id` equals its `post_id` and an orphan's does not.

## Query parameters

- `url` string, required
- `cursor` string
- `trim` boolean
- `label` string
- `exclude` string
- `judgments` 'on' | 'off'
- `dry_run` '1'
- `label_evidence` '1'
- `fit` 'goal'
- `goal` string
- `fit_tokens` integer
- `since` string
- `until` string

## Headers

- `Cache-Control` string
- `Idempotency-Key` string

## Response `200`

Successful response

- object
  - `success` boolean, required: Whether the request succeeded
  - `platform` string, required: Platform name
  - `endpoint` string, required: API endpoint path
  - `data` object, required: Platform-specific response data
    - `items` object[]: Array of canonical comment wrappers ({ comment })
      - `comment` object: Canonical Comment object (unified across all platforms)
        - `id` string: Platform-specific comment ID (always a string)
        - `url` string, nullable: Direct URL to the comment on the source platform
        - `parent_id` string, nullable: Parent comment ID for nested replies, or null for top-level comments
        - `post_id` string, nullable: ID of the post this comment belongs to
        - `text` string, nullable: Comment body. Tombstone sentinels ([deleted] / [removed]) are collapsed to null upstream: customers never see them.
        - `author` object: Subset of Author fields for the comment author
          - `username` string, nullable: Comment author username (null when tombstoned)
          - `display_name` string, nullable: Comment author display name
          - `avatar_url` string, nullable: URL to comment author profile picture
          - `verified` boolean, nullable: Whether the comment author is verified
        - `engagement` object: Engagement counts on the comment
          - `likes` integer, nullable: Like / upvote count
          - `replies` integer, nullable: Reply / child-comment count. `0` when the upstream structurally reports the count and the comment has no replies; `null` only when the upstream does not surface a reply count at all.
        - `flags` object: Boolean flags on the comment
          - `pinned` boolean, nullable: Pinned flag (null when platform does not surface)
          - `deleted` boolean: Whether the comment is tombstoned (always present, even when false)
        - `published_at` union: Comment 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 `comment.ext.published_at_epoch` for one deprecation cycle.
          - string
          - integer
        - `ext` object, nullable: Platform-specific passthrough tokens for reply expansion (present only on platforms that surface them)
          - `replies_token` string, nullable: YouTube reply continuation token: pass to `/v1/youtube/video/comment/replies?continuationToken=`
          - `replies_cursor` string, nullable: Reddit reply-branch continuation cursor. Present when this comment's reply tree is truncated upstream: pass it back as `?cursor=` on `/v1/reddit/post/comments` to load the rest of the branch.
          - `depth` integer, nullable: Reddit comment nesting depth as the source reports it: 0 on a top-level comment, 1 on a direct reply, and so on. Present when the thread arrived flat and was re-nested into `replies[]`, so you can verify that nesting independently.
          - `published_at_epoch` integer, nullable: Raw Unix epoch for `published_at` (present only when the upstream sent a numeric epoch that was normalised to the ISO 8601 string).
          - `feedback_id` string, nullable: Facebook comment feedback id: feeds `/v1/facebook/post/comment/replies`
          - `expansion_token` string, nullable: Facebook comment expansion/paginator token: feeds `/v1/facebook/post/comment/replies`
          - `author_id` string, nullable: The commenter's platform-native numeric user id, where the upstream exposes one.
          - `ip_location` string, nullable: String at comment.ext.ip_location
          - `urn` string, nullable: String at comment.ext.urn
          - `reaction_counts` string[], nullable: Array at comment.ext.reaction_counts
          - `is_edited` boolean, nullable: Boolean at comment.ext.is_edited
          - `previous_replies_token` string, nullable: String at comment.ext.previous_replies_token
          - `author_headline` string, nullable: String at comment.ext.author_headline
          - `updated_at` string, nullable: String at comment.ext.updated_at
          - `author_channel_id` string, nullable: String at comment.ext.author_channel_id
          - `author_url` string, nullable: String at comment.ext.author_url
          - `viewer_rating` string, nullable: String at comment.ext.viewer_rating
          - `text_original` string, nullable: String at comment.ext.text_original
          - `preview_replies` string[], nullable: Array at comment.ext.preview_replies
          - `lookup` string, nullable: Leaf at comment.ext.lookup
          - `post_title` string, nullable: String at comment.ext.post_title
          - `post_url` string, nullable: String at comment.ext.post_url
          - `subreddit` string, nullable: String at comment.ext.subreddit
          - `subreddit_subscribers` integer, nullable: Numeric at comment.ext.subreddit_subscribers
          - `post_score` integer, nullable: Numeric at comment.ext.post_score
          - `post_comment_count` integer, nullable: Numeric at comment.ext.post_comment_count
          - `post_author` string, nullable: String at comment.ext.post_author
          - `post_published_at` string, nullable: String at comment.ext.post_published_at
          - `post_flair` string, nullable: String at comment.ext.post_flair
          - `is_submitter` boolean, nullable: Boolean at comment.ext.is_submitter
          - `edited_at` string, nullable: String at comment.ext.edited_at
          - `controversiality` integer, nullable: Numeric at comment.ext.controversiality
          - `content_language` string, nullable: ISO 639-1 language tag for this comment, when the source reports one. X writes `zxx` / `und` for no linguistic content; those collapse to null.
          - `author_followers` integer, nullable: The commenter's follower count as embedded in this row. Snapshot as of whenever the replies source saw the account, not a live figure. On X this is present on every `tweet/replies` row.
          - `author_following` integer, nullable: The commenter's following count as embedded in this row. Same snapshot caveat as `author_followers`.
          - `author_posts_count` integer, nullable: The commenter's post count as embedded in this row. Same snapshot caveat as `author_followers`.
          - `quote_count` integer, nullable: How many quote-posts this comment has, when the source reports it. On X a reply is a tweet, so this is the same figure `post.ext.quote_count` carries on tweet lanes.
          - `views` integer, nullable: View count for this comment, when the source reports it. On X a reply is a tweet and the count is public on posts from ~2022 onward.
          - `saves` integer, nullable: Bookmark / save count for this comment, when the source reports it. On X this is `legacy.bookmark_count`.
        - `replies` object[], nullable: Nested reply tree: array of child comments, each itself a full Comment object with its own `replies`. Populated on threaded platforms (Reddit); absent on flat-comment platforms, which thread only via `parent_id`.
    - `next_cursor` string, nullable: Opaque cursor for the next page. Pass it back as a query parameter on endpoints that support pagination. Present only when the upstream reports more results.
    - `total` integer, nullable: Total number of matching results, when the upstream provides a count. Omitted otherwise.
    - `dropped` integer, required: Number of upstream list items dropped because they could not be repaired to the endpoint schema. Valid list responses include 0.
    - `truncated` boolean: Whether the thread holds more comments than this response carries. `true` can arrive with `next_cursor: null`, which means the thread is incomplete and this endpoint cannot fetch you the rest: the source reached the end of one ranking window rather than the end of the thread. Do not infer this from `pagination.has_more`, which reports only whether a cursor exists. Absent means no completeness verdict was computed.
    - `comments_returned` integer: How many comments this response carries, counting every nested reply. `items[]` holds only the top-level comments (each reply sits under its parent's `comment.replies[]`), so `items.length` and `pagination.page_size` count those alone. Compare this number, not `items.length`, with the post's comment count, which also counts removed and deleted replies that no listing returns.
    - `_warnings` string[]: Non-fatal notices about this response (field-map drift, clamped computed values). Advisory only: its presence never means the request failed. Omitted entirely when there is nothing to report, so treat absent as 'no warnings'.
  - `credits_used` integer, required: Number of credits consumed
  - `credits_remaining` integer, nullable, required: Current account balance, or null when this response could not establish one. Free cache hits always return null because they do not establish an authoritative post-request balance. An idempotency replay also returns null when its current-balance lookup fails. It is never a fabricated zero, so a zero here means the account really is empty. The authoritative reading is the one on a billed response, which comes straight from the deduction.
  - `request_id` string, required: Unique request identifier for support
  - `cached` boolean, required: Whether the response was served from cache
  - `idempotent_replay` boolean: True only when this response is an idempotency replay
  - `meta` object: Optional. Present only when this call completed a pattern that one other call does more cheaply or in one step, at most once per pattern per API key per day. Send the header `X-SocialCrawl-Hints: off` to never receive it.
    - `hint` object: One suggestion: what to call instead and why, with the price when the suggested call costs more than the calls it replaces.
      - `code` string: creator_card | batch_profiles | search_multi | incremental_sync | comment_labels | search_repeat
      - `message` string: One sentence for a person or an agent to read.
      - `method` string: GET or POST.
      - `path` string: The call the hint points to.
  - `pagination` object, required: Cursor state for this page. Present on every list response.
    - `next_cursor` string, nullable, required: Opaque token to send back as `cursor` for the next page, or null at end-of-list. Pass it back verbatim; never decode or trim it.
    - `has_more` boolean, required: Explicit stop signal. Prefer this over inspecting next_cursor or comparing against total.
    - `page_size` integer, required: Number of items in THIS page.
    - `stopped_at` 'since' | 'known_id' | 'end' | 'null', nullable: Present only when the request sent `since` or `stop_at_id`. Why the walk stopped: `since` (this page reached a post older than the date), `known_id` (this page reached the post you already hold), `end` (the list ran out first), or null (not yet, keep walking with `next_cursor`).

## Other responses

- `400`: Invalid request - missing or malformed parameters
- `401`: Unauthorized - missing or invalid API key
- `402`: Payment required - the account balance is too low, or the calling key has spent its own per-key credit limit
- `404`: Not found - the endpoint does not exist, or the requested resource was not found upstream
- `405`: Method not allowed - wrong HTTP verb for this endpoint
- `409`: Conflict - an idempotent request is still in flight, its completed body exceeded the replay limit, or the cohort resource is not in a state that allows this operation
- `410`: Gone - the discover run's retention passed and its rows were deleted; start a new run
- `413`: Payload too large: the JSON request body exceeds the 1 MB size limit and is rejected before parsing, or a single cohort result cannot fit beneath the 1 MB response-page ceiling
- `422`: Idempotency payload mismatch - this Idempotency-Key was already used with a different request payload; or a discover request with async=false is over what one call can answer (NEEDS_ASYNC)
- `429`: Rate or concurrency limit exceeded. `RATE_LIMITED`: more than 600 requests in a 1-minute sliding window on this API key (headers `X-RateLimit-Limit`/`Remaining`/`Reset`; `Retry-After` is seconds until the window resets). `CONCURRENCY_LIMIT`: more than 50 simultaneous in-flight requests (headers `X-Concurrency-Limit`/`Remaining`; short static `Retry-After`). Both are unbilled. Honor `Retry-After`, then back off with jitter. See /docs/rate-limits.
- `500`: Internal server error - an immediate refund is attempted; credits_used reports the committed net charge and exact compensation is queued if that refund cannot commit
- `502`: Upstream error - the platform returned an error; an immediate refund is attempted and credits_used reports the committed net charge
- `503`: Service unavailable - the request is unbilled when rejected before deduction, otherwise an immediate refund is attempted and credits_used reports the committed net charge
- `504`: Gateway timeout - the request was still running close to the platform time limit and is answered as UPSTREAM_ERROR, the same code as 502. An immediate refund is attempted and credits_used reports the committed net charge. When details.retry_with is set, retryable is false and there is no Retry-After

---

[API](https://skmtc.dev/socialcrawl/apis/socialcrawl-api.md) · [All operations](https://skmtc.dev/socialcrawl/apis/socialcrawl-api/llms.txt) · [OpenAPI document](https://skmtc.dev/socialcrawl/apis/socialcrawl-api/revisions/a0ad2511004a?raw)
