> ## Documentation Index
> Fetch the complete documentation index at: https://docs.superx.so/llms.txt
> Use this file to discover all available pages before exploring further.

# Read an audience list

> A page of the account's followers, following, repliers or reposters
from SuperX's synced snapshot.

These four are the system lists in the app's Contacts tab. They live
in SuperX's own audience store rather than in the contact lists you
create, which is why `/v1/contact-lists/{id}/members` will not read
them and this endpoint exists.

Paging is by CURSOR, not page number: pass `pagination.next_cursor`
back as `cursor` to continue. A cursor points at the last row of the
page you were given, so new rows arriving mid-walk never shift the
pages you already read. There is no `total`; `meta.synced_count` is
the size of the whole list.

`followers` and `following` come from the follow graph SuperX syncs
for the account, so `meta` reports the sync `status`, the plan's
`backfill_cap` and whether the account is deeper than that cap.
`repliers` and `reposters` are a rolling 90-day window
(`meta.window_days`), so someone whose last reply ages past 90 days
drops out and reappears on their next reply.

`engaged_count` is replies plus reposts in the last 90 days for the
follow lists, and this list's own action count for `repliers` and
`reposters`. `icp_score` and `icp_rationale` are always null here:
scoring belongs to signal-agent deposits, not to the snapshot.




## OpenAPI

````yaml /api-reference/openapi.yaml get /v1/audience/{kind}
openapi: 3.1.0
info:
  title: SuperX API
  version: 1.0.0
  description: >
    The SuperX public API: your Twitter/X content, analytics, audience and

    scheduling data over REST.


    All endpoints require an API key (`Authorization: Bearer sxk_...`) except

    `GET /v1/docs`. Keys are created in the SuperX app under Account > API / MCP
    / CLI

    and are server-side secrets.


    Timestamps are UTC ISO-8601 in both directions; inputs must carry an
    explicit

    `Z` or numeric offset. Every authenticated response carries

    `X-RateLimit-Limit`, `X-RateLimit-Remaining` and `X-RateLimit-Reset`
    headers.
  contact:
    name: SuperX
    url: https://superx.so
servers:
  - url: https://api.superx.so
security:
  - apiKey: []
tags:
  - name: Identity
  - name: Content
  - name: Analytics
  - name: Inspiration
  - name: Audience
  - name: Contact Lists
  - name: Signals
  - name: Datasets
    description: |
      The audience collections Ask SuperX builds in the app: the repliers,
      quoters or reposters of a post, the members of an X list, your own
      posts or replies, or a research brief.

      Collect a new one with `POST /v1/datasets` (a big collection answers
      202 and finishes in the background), read it, export it, or copy the
      people in it into a contact list you created. Datasets are kept for 30
      days, and the ones Ask SuperX builds in the app show up here too.
  - name: Engage
    description: |
      The account's saved Engage feeds and the candidate posts in them, for
      an agent to score and a person to act on.

      Read-only by design. These endpoints return feed candidates for a
      person to review; replies are written and sent by a person in the
      SuperX app, which is why there is no reply endpoint here. Sending
      spammy, automated, or AI-generated replies that read as inauthentic
      may get your X account suspended under X's inauthentic-behavior
      rules and your SuperX account terminated. AI suggestions must be
      reviewed and meaningfully edited before they are sent, and you are
      solely responsible for what you post. Reply activity is logged and
      may be audited.
  - name: X Lookups
    description: |
      Read any public post, its top replies, any public profile, or an
      account's latest posts LIVE from X, rather than from SuperX's stored
      data.

      These are owner-scoped, so none of them take an `account_id`: nothing
      about a public lookup is per-X-account. They cost the tighter
      live-enrichment allowance and share a daily allowance of 300 live
      lookups with Ask SuperX inside the app, so use them for what you
      actually need rather than to sweep. Repeat lookups within 15 minutes
      may be served from a short-lived server-side cache.
  - name: Tools
    description: |
      The composer helpers from the SuperX app, over the API: rewrite a post,
      edit one selected piece of it, apply one preset rewrite, check a claim,
      or compare two versions.

      Every one of them returns TEXT and writes nothing. Nothing here is
      posted, scheduled or sent; save what you keep with
      `POST /v1/posts/draft` or `POST /v1/scheduled-posts`. They cost AI
      credits, measured from the models' real cost, and spend no live-data
      allowance.
  - name: Media
  - name: Workers
    description: |
      The posts the account's Workers have written, and the three things a
      person does with one: save it as a draft, schedule it, or dismiss it.

      A Worker is a scheduled AI writer set up in the SuperX app. Creating,
      editing and running one stays in the app, so there is no create or run
      endpoint here. What a run produces lands in the app's "To review" queue
      and is read with `GET /v1/workers/suggestions`.

      NOTHING HERE POSTS TO X. Drafting or scheduling a suggestion writes a
      post the user can see in the app and on `GET /v1/scheduled-posts`,
      exactly like the app's own buttons. AI output must be reviewed and
      meaningfully edited by a person before it goes out, so show the text to
      the user and confirm the time before you schedule anything.
  - name: Scheduling
  - name: Tags
  - name: Context
  - name: Queue
  - name: DMs
    description: |
      Queue direct messages into the account's own DM pipeline, and read or
      cancel what is waiting.

      NOTHING HERE SENDS A MESSAGE. `POST /v1/dm/campaigns` enqueues; the
      SuperX app's scheduler is what sends, within the account's daily and
      monthly DM limits, so the create response is counts, not deliveries.
      Unsent messages can be cancelled until the scheduler picks them up.

      You are responsible for the messages you queue. Unsolicited or
      automated bulk DMs may get an X account suspended under X's rules and
      a SuperX account terminated, so confirm the recipient list and the
      exact wording with the person on whose behalf you are queueing.
  - name: Articles
  - name: Meta
paths:
  /v1/audience/{kind}:
    get:
      tags:
        - Audience
      summary: Read an audience list
      description: |
        A page of the account's followers, following, repliers or reposters
        from SuperX's synced snapshot.

        These four are the system lists in the app's Contacts tab. They live
        in SuperX's own audience store rather than in the contact lists you
        create, which is why `/v1/contact-lists/{id}/members` will not read
        them and this endpoint exists.

        Paging is by CURSOR, not page number: pass `pagination.next_cursor`
        back as `cursor` to continue. A cursor points at the last row of the
        page you were given, so new rows arriving mid-walk never shift the
        pages you already read. There is no `total`; `meta.synced_count` is
        the size of the whole list.

        `followers` and `following` come from the follow graph SuperX syncs
        for the account, so `meta` reports the sync `status`, the plan's
        `backfill_cap` and whether the account is deeper than that cap.
        `repliers` and `reposters` are a rolling 90-day window
        (`meta.window_days`), so someone whose last reply ages past 90 days
        drops out and reappears on their next reply.

        `engaged_count` is replies plus reposts in the last 90 days for the
        follow lists, and this list's own action count for `repliers` and
        `reposters`. `icp_score` and `icp_rationale` are always null here:
        scoring belongs to signal-agent deposits, not to the snapshot.
      operationId: getAudience
      parameters:
        - name: kind
          in: path
          required: true
          schema:
            type: string
            enum:
              - followers
              - following
              - repliers
              - reposters
        - $ref: '#/components/parameters/AccountId'
        - name: cursor
          in: query
          description: next_cursor from the previous page. Omit for the first page.
          schema:
            type: string
        - name: limit
          in: query
          schema:
            type: integer
            minimum: 1
            maximum: 100
            default: 50
      responses:
        '200':
          description: A page of the audience.
          headers:
            X-RateLimit-Limit:
              $ref: '#/components/headers/X-RateLimit-Limit'
            X-RateLimit-Remaining:
              $ref: '#/components/headers/X-RateLimit-Remaining'
            X-RateLimit-Reset:
              $ref: '#/components/headers/X-RateLimit-Reset'
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    type: array
                    items:
                      $ref: '#/components/schemas/AudienceMember'
                  meta:
                    $ref: '#/components/schemas/AudienceMeta'
                  pagination:
                    $ref: '#/components/schemas/CursorPagination'
              example:
                data:
                  - id: '44196397001234567'
                    x_user_id: '44196397001234567'
                    username: activefan
                    name: Sam Porter
                    avatar_url: https://pbs.twimg.com/profile_images/example3.jpg
                    location: Lisbon
                    followers_count: 3120
                    following_count: 480
                    engaged_count: 12
                    source: followers
                    added_at: '2026-08-30T09:14:00.000Z'
                    icp_score: null
                    icp_rationale: null
                    can_dm: true
                meta:
                  kind: followers
                  account_id: 9HVHDe4WsJfJcR5SFauMD
                  x_account_id: '1178367350552305665'
                  synced_count: 13270
                  status: complete
                  backfill_cap: 25000
                  is_capped: false
                  window_days: null
                pagination:
                  limit: 50
                  has_more: true
                  next_cursor: MTc1NjU0NDA0MDAwMDo0NDE5NjM5NzAwMTIzNDU2Nw
        '400':
          $ref: '#/components/responses/InvalidParameter'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/SubscriptionRequired'
        '404':
          $ref: '#/components/responses/AccountNotFound'
        '429':
          $ref: '#/components/responses/RateLimited'
        '500':
          $ref: '#/components/responses/InternalError'
        '503':
          $ref: '#/components/responses/AccountsUnavailable'
components:
  parameters:
    AccountId:
      name: account_id
      in: query
      required: false
      description: >-
        Account to act on, from `GET /v1/accounts`. Defaults to your main
        account. An id outside your accounts returns `404 account_not_found`.
      schema:
        type: string
  headers:
    X-RateLimit-Limit:
      description: The limit of the rate window closest to exhaustion.
      schema:
        type: integer
    X-RateLimit-Remaining:
      description: Requests remaining in that window.
      schema:
        type: integer
    X-RateLimit-Reset:
      description: Unix timestamp (seconds) when that window resets.
      schema:
        type: integer
  schemas:
    AudienceMember:
      type: object
      description: |
        One person in a system audience list. Field names match
        ContactListMember so one mapping covers both, but `id` here is the X
        user id rather than a membership id (there is nothing to remove).
      properties:
        id:
          type: string
          description: The person's X user id (same value as x_user_id).
        x_user_id:
          type: string
        username:
          type: string
          nullable: true
        name:
          type: string
          nullable: true
        avatar_url:
          type: string
          nullable: true
        location:
          type: string
          nullable: true
        followers_count:
          type: integer
          nullable: true
        following_count:
          type: integer
          nullable: true
        engaged_count:
          type: integer
          description: |
            Replies + reposts to the account in the last 90 days for
            followers/following; this list's own action count for
            repliers/reposters.
        source:
          type: string
          description: The audience kind this row came from.
        added_at:
          type: string
          format: date-time
          nullable: true
          description: |
            When SuperX first saw the follow edge, or the person's most
            recent reply or repost.
        icp_score:
          type: integer
          nullable: true
          description: Always null here; lead scoring belongs to signal-agent deposits.
        icp_rationale:
          type: string
          nullable: true
          description: Always null here.
        can_dm:
          type: boolean
          nullable: true
          description: Whether the person's DMs looked open when SuperX last saw them.
    AudienceMeta:
      type: object
      description: The state of the whole audience list, not of this page.
      properties:
        kind:
          type: string
          enum:
            - followers
            - following
            - repliers
            - reposters
        account_id:
          type: string
          description: |
            The account id you pass as `account_id`, echoed back. Same id
            space as every other /v1 surface.
        x_account_id:
          type: string
          description: The X user id the audience is stored under.
        synced_count:
          type: integer
          description: |
            How many people SuperX has synced for this list. For followers
            and following this counts synced edges rather than re-checking
            every one against X, so it may exceed the rows a full walk
            returns: edges that were later removed are still counted.
        status:
          type: string
          description: |
            Sync state: missing (never started), pending, running, complete
            or paused for the follow lists; missing, running or complete for
            repliers and reposters.
        backfill_cap:
          type: integer
          nullable: true
          description: |
            How deep the plan syncs the follow graph. Null for repliers and
            reposters.
        is_capped:
          type: boolean
          nullable: true
          description: |
            True when the account is deeper than backfill_cap, so the list is
            the most recent slice rather than everyone. Null for repliers and
            reposters.
        window_days:
          type: integer
          nullable: true
          description: |
            The rolling window repliers and reposters are measured over (90).
            Null for the follow lists, which are not windowed.
    CursorPagination:
      type: object
      description: |
        Keyset pagination. `next_cursor` is present only when `has_more` is
        true; pass it back as `cursor` to read the next page. Cursors are
        opaque and are not valid across different queries.
      required:
        - has_more
      properties:
        limit:
          type: integer
          description: Absent on endpoints whose page size is fixed upstream.
        has_more:
          type: boolean
        next_cursor:
          type: string
    ErrorEnvelope:
      type: object
      required:
        - error
      properties:
        error:
          type: object
          required:
            - code
            - message
          properties:
            code:
              type: string
              description: Stable machine-readable error code.
            message:
              type: string
            retry_after:
              type: integer
              description: Seconds to wait before retrying (rate-limit errors only).
    LegacyErrorEnvelope:
      type: object
      required:
        - error
      description: |
        Legacy shape used ONLY by the shared subscription middleware: a plain
        string `error` field. Seen on `403` when the subscription has lapsed
        (string starts with "subscription_required:") and on `500` when
        subscription verification fails (string starts with "internal_error:").
      properties:
        error:
          type: string
          example: >-
            subscription_required: The SuperX API requires an active
            subscription
  responses:
    InvalidParameter:
      description: A parameter is missing, malformed, or out of range.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorEnvelope'
          example:
            error:
              code: invalid_parameter
              message: since must be a UTC ISO-8601 timestamp
    Unauthorized:
      description: >-
        Missing/malformed Authorization header (`unauthorized`) or an
        unknown/revoked key (`invalid_api_key`).
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorEnvelope'
          example:
            error:
              code: invalid_api_key
              message: Unknown or revoked API key
    SubscriptionRequired:
      description: |
        Subscription lapsed. NOTE the legacy body shape: `error` is a plain
        string here, not the `{ code, message }` object. Read-only keys on
        write endpoints instead get the object envelope with code
        `insufficient_scope`.
      content:
        application/json:
          schema:
            oneOf:
              - $ref: '#/components/schemas/LegacyErrorEnvelope'
              - $ref: '#/components/schemas/ErrorEnvelope'
          example:
            error: >-
              subscription_required: The SuperX API requires an active
              subscription
    AccountNotFound:
      description: account_id is not one of your accounts.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorEnvelope'
          example:
            error:
              code: account_not_found
              message: No account with that id belongs to this key
    RateLimited:
      description: Rate limit exceeded (limits vary by plan). Honor Retry-After.
      headers:
        Retry-After:
          description: Seconds to wait before retrying.
          schema:
            type: integer
        X-RateLimit-Limit:
          $ref: '#/components/headers/X-RateLimit-Limit'
        X-RateLimit-Remaining:
          $ref: '#/components/headers/X-RateLimit-Remaining'
        X-RateLimit-Reset:
          $ref: '#/components/headers/X-RateLimit-Reset'
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorEnvelope'
          example:
            error:
              code: rate_limited
              message: >-
                Rate limit exceeded for the Pro plan (30 requests/min). Upgrade
                for higher limits.
              retry_after: 42
    InternalError:
      description: >-
        Unexpected server error. May also use the legacy string envelope when
        subscription verification fails.
      content:
        application/json:
          schema:
            oneOf:
              - $ref: '#/components/schemas/ErrorEnvelope'
              - $ref: '#/components/schemas/LegacyErrorEnvelope'
          example:
            error:
              code: internal_error
              message: Failed to fetch posts
    AccountsUnavailable:
      description: >-
        Linked-account verification is temporarily unavailable (fail closed).
        The main account keeps working.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorEnvelope'
          example:
            error:
              code: accounts_unavailable
              message: >-
                Account information is temporarily unavailable. Try again
                shortly.
  securitySchemes:
    apiKey:
      type: http
      scheme: bearer
      description: >-
        A SuperX API key ("sxk_..."), created in the SuperX app under Account >
        API / MCP / CLI. Keys are server-side secrets.

````