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

# List Content Items

> Returns every content item in a website's Content Hub, published or not: in-flight drafts, briefs, snipes, optimize and slice runs, scheduled and failed items, plus tracked pages. This is the enumeration path from a `sheet_id` to its unpublished rows. `POST /api/v1/content` lists only finished pipeline rows, with citation and impression metrics, so a sheet full of generated drafts appears empty there; use this endpoint to see them.

Returns identity fields only (id, title, type, stage, sheet, URL, timestamps, target prompt ids), no metrics. Reads from the primary store and is uncached, so an item is listable the moment `POST /api/v1/content/generate` returns its `content_id`. Read a row's text with `GET /api/v1/content/{content_id}`.

`stage` is the raw pipeline workflow state, not a publication flag: `null` means no pipeline record (most external and imported tracked pages), and manual editor items carry `generated`. Treat an item as published only when its stage is `done` (or it is an external or imported page) and it has a `url`; `done` without a `url` is an unpublished orphan.

Passing the `sheet_id` of a view-type tab (see `sheet_type` on `GET /api/v1/content/sheets`) lists the shared main pool without the view's saved filters. Hidden content (`is_hidden = true`) is excluded. Pagination uses `page_size + 1` lookahead: `pagination.has_more === true` means the next page exists; there is no total-count field. Pass an unknown `sheet_id` or `prompt_id` (or one from another website) and the endpoint returns 403.

Also exposed as the MCP tool `list_content`.



## OpenAPI

````yaml /api-reference/openapi.json get /api/v1/content/items
openapi: 3.1.0
info:
  title: AthenaHQ API
  description: >-
    AthenaHQ API provides programmatic access to manage your websites and
    prompts for AI-powered content optimization.
  version: 1.0.0
  contact:
    email: support@athenahq.ai
servers:
  - url: https://api.athenahq.ai
    description: Production server
security:
  - apiKey: []
tags:
  - name: Basics
    description: Core API operations for managing websites and prompts
  - name: Metrics
    description: Metrics and analytics endpoints for tracking AI visibility
  - name: Billing
    description: Billing and credits endpoints for managing usage
  - name: Team Management
    description: Endpoints for managing team members and invitations
  - name: Groups
    description: Endpoints for managing groups of websites
  - name: Content
    description: >-
      Endpoints for accessing Content Hub data — tabs, tracked URLs, and per-URL
      prompt breakdowns.
  - name: Pitch Workspace
    description: >-
      Endpoints for accessing pitch workspace reports — org-scoped pitch runs
      with competitors, prompts, attributes, and aggregate metrics.
  - name: Knowledge Base
    description: >-
      Endpoints for reading the brand Knowledge Base — approved brand facts and
      the pillars that organize them.
paths:
  /api/v1/content/items:
    get:
      tags:
        - Content
      summary: List Content Items
      description: >-
        Returns every content item in a website's Content Hub, published or not:
        in-flight drafts, briefs, snipes, optimize and slice runs, scheduled and
        failed items, plus tracked pages. This is the enumeration path from a
        `sheet_id` to its unpublished rows. `POST /api/v1/content` lists only
        finished pipeline rows, with citation and impression metrics, so a sheet
        full of generated drafts appears empty there; use this endpoint to see
        them.


        Returns identity fields only (id, title, type, stage, sheet, URL,
        timestamps, target prompt ids), no metrics. Reads from the primary store
        and is uncached, so an item is listable the moment `POST
        /api/v1/content/generate` returns its `content_id`. Read a row's text
        with `GET /api/v1/content/{content_id}`.


        `stage` is the raw pipeline workflow state, not a publication flag:
        `null` means no pipeline record (most external and imported tracked
        pages), and manual editor items carry `generated`. Treat an item as
        published only when its stage is `done` (or it is an external or
        imported page) and it has a `url`; `done` without a `url` is an
        unpublished orphan.


        Passing the `sheet_id` of a view-type tab (see `sheet_type` on `GET
        /api/v1/content/sheets`) lists the shared main pool without the view's
        saved filters. Hidden content (`is_hidden = true`) is excluded.
        Pagination uses `page_size + 1` lookahead: `pagination.has_more ===
        true` means the next page exists; there is no total-count field. Pass an
        unknown `sheet_id` or `prompt_id` (or one from another website) and the
        endpoint returns 403.


        Also exposed as the MCP tool `list_content`.
      operationId: listContentItems
      parameters:
        - name: website_id
          in: query
          description: The website whose Content Hub to enumerate.
          required: true
          schema:
            type: string
            format: uuid
        - name: sheet_id
          in: query
          description: >-
            Restrict to a single Content Hub tab. Use `GET
            /api/v1/content/sheets` to discover IDs. A view-type tab resolves to
            the shared main pool. Omit to span every tab.
          required: false
          schema:
            type: string
            format: uuid
        - name: content_type
          in: query
          description: >-
            Restrict to a single content type. `athena_created` is a shortcut
            for the four Athena-generated subtypes (draft, snipe, optimize,
            slice). Omit to span every type.
          required: false
          schema:
            type: string
            enum:
              - external
              - imported
              - athena_created
              - draft
              - snipe
              - optimize
              - slice
              - manual
        - name: stage
          in: query
          description: >-
            Restrict to a single pipeline stage. Matches the pipeline record
            only, so it can never match rows without one (most external and
            imported pages). Omit to span every stage.
          required: false
          schema:
            type: string
            enum:
              - scheduled
              - pending
              - pending_brief
              - generated_brief
              - pending_article
              - generated
              - done
              - failed
        - name: prompt_id
          in: query
          description: >-
            Restrict to items written for this prompt (their targeting, the same
            prompt ids `POST /api/v1/content/generate` takes). Soft-deleted
            prompts still match.
          required: false
          schema:
            type: string
            format: uuid
        - name: page_num
          in: query
          description: Zero-indexed page number.
          required: false
          schema:
            type: integer
            minimum: 0
            default: 0
        - name: page_size
          in: query
          description: Number of items per page (1-100).
          required: false
          schema:
            type: integer
            minimum: 1
            maximum: 100
            default: 50
      responses:
        '200':
          description: Successful response with the page of content items.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ContentItemsListResponse'
              example:
                content:
                  - content_id: 11111111-2222-3333-4444-555555555555
                    title: How to Apply Foundation on Mature Skin
                    type: draft
                    stage: generated
                    url: null
                    normalized_url: null
                    sheet_id: 00000000-0000-4000-8000-000000000001
                    sheet_name: Drafts - sprint 1
                    topic_name: Makeup for Mature Skin
                    prompt_ids:
                      - aaaaaaaa-bbbb-4ccc-8ddd-eeeeeeeeeeee
                    prompt_count: 1
                    mark_as_done_time: null
                    created_at: '2026-09-01T20:59:53.000Z'
                    updated_at: '2026-09-01T21:09:04.000Z'
                pagination:
                  page_num: 0
                  page_size: 50
                  has_more: false
        '400':
          description: Bad request, invalid parameters.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              examples:
                missing_website_id:
                  value:
                    error: website_id is required
                invalid_stage:
                  value:
                    error: >-
                      stage: Invalid option: expected one of
                      "scheduled"|"pending"|"pending_brief"|"generated_brief"|"pending_article"|"generated"|"done"|"failed"
        '401':
          description: Unauthorized, invalid or missing API key.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '403':
          description: >-
            Forbidden, you don't have access to this website, or the `sheet_id`
            / `prompt_id` belongs to another website.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              examples:
                website:
                  value:
                    error: Unauthorized access to this website
                sheet:
                  value:
                    error: Unauthorized access to this sheet
                prompt:
                  value:
                    error: Unauthorized access to this prompt
        '500':
          description: Internal server error.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
      security:
        - apiKey: []
components:
  schemas:
    ContentItemsListResponse:
      type: object
      required:
        - content
        - pagination
      properties:
        content:
          type: array
          items:
            $ref: '#/components/schemas/ContentInventoryItem'
        pagination:
          $ref: '#/components/schemas/Pagination'
    Error:
      type: object
      description: Error response object
      required:
        - error
      properties:
        error:
          type: string
          description: Error message describing what went wrong
          example: Unauthorized
    ContentInventoryItem:
      type: object
      description: >-
        A Content Hub item as listed by `GET /api/v1/content/items`: identity
        and workflow fields only, no metrics. Published rows, unpublished drafts
        and tracked pages share this shape.
      required:
        - content_id
        - title
        - type
        - stage
        - url
        - normalized_url
        - sheet_id
        - sheet_name
        - topic_name
        - prompt_ids
        - prompt_count
        - mark_as_done_time
        - created_at
        - updated_at
      properties:
        content_id:
          type: string
          format: uuid
          description: >-
            Unique identifier for the content item. Pass it to `GET
            /api/v1/content/{content_id}` to read the brief and body.
          example: 11111111-2222-3333-4444-555555555555
        title:
          type: string
          nullable: true
          description: Page or post title (nullable for unscraped URLs).
          example: How to Apply Foundation on Mature Skin
        type:
          type: string
          nullable: true
          description: >-
            How the content entered the hub: `draft` (Athena-written article),
            `optimize` (rewrite of an existing page), `snipe`, `slice`, `manual`
            (authored in the editor), `external` (added manually), `imported`
            (via GA4). `null` for legacy rows.
          example: draft
        stage:
          type: string
          nullable: true
          enum:
            - scheduled
            - pending
            - pending_brief
            - generated_brief
            - pending_article
            - generated
            - done
            - failed
          description: >-
            Raw pipeline workflow state, not a publication flag. `null` when the
            item has no pipeline record (most external and imported tracked
            pages). `generated` means the text is ready but unpublished (manual
            editor items carry it too); `done` means published or marked done;
            `scheduled` means a publish is scheduled. An item counts as
            published only when its stage is `done` (or it is an external or
            imported page) and it has a `url`.
          example: generated
        url:
          type: string
          nullable: true
          description: >-
            Canonical URL (display form, may include `www.`). `null` until the
            item is published somewhere.
          example: null
        normalized_url:
          type: string
          nullable: true
          description: >-
            URL after protocol/trailing-slash normalization. Used to join with
            citation data.
          example: null
        sheet_id:
          type: string
          format: uuid
          nullable: true
          description: >-
            Content Hub tab the item is pinned to. `null` for content in the
            shared main pool.
        sheet_name:
          type: string
          nullable: true
          description: Human-readable name of the tab. `null` when `sheet_id` is null.
          example: Drafts - sprint 1
        topic_name:
          type: string
          nullable: true
          description: Topic the content is paired with (if any).
          example: Makeup for Mature Skin
        prompt_ids:
          type: array
          items:
            type: string
            format: uuid
          description: >-
            The prompts this item was written for (its targeting), capped at 25
            per row; `prompt_count` is the untruncated size. Includes
            soft-deleted prompts, which `GET /api/v1/prompts` does not list.
            Empty when no targeting was recorded, which is normal for imported
            or externally tracked pages. Not the prompts whose answers cited the
            page; see `POST /api/v1/content/prompts` for that.
        prompt_count:
          type: integer
          description: >-
            Total number of prompts this item targets, including any beyond the
            25 in `prompt_ids`. Read the rest through `GET
            /api/v1/content/{content_id}`.
          example: 1
        mark_as_done_time:
          type: string
          format: date-time
          nullable: true
          description: >-
            When the content was marked as published / done in Content Hub.
            `null` while unpublished.
          example: null
        created_at:
          type: string
          format: date-time
          description: When the content row was created (UTC).
          example: '2026-09-01T20:59:53.000Z'
        updated_at:
          type: string
          format: date-time
          description: >-
            The newer of the content row's and its pipeline record's last update
            (UTC), so generation progress bumps it.
          example: '2026-09-01T21:09:04.000Z'
    Pagination:
      type: object
      description: >-
        Pagination metadata. Uses `page_size + 1` lookahead — `has_more=true`
        means the next page is non-empty. No total-count field, by design
        (avoids the extra `COUNT(*)` round-trip).
      required:
        - page_num
        - page_size
        - has_more
      properties:
        page_num:
          type: integer
          description: Zero-indexed page number returned.
          example: 0
        page_size:
          type: integer
          description: Maximum items per page.
          example: 50
        has_more:
          type: boolean
          description: '`true` if another page is available.'
          example: true
  securitySchemes:
    apiKey:
      type: apiKey
      in: header
      name: x-api-key
      description: >-
        API key for authentication. You can create one
        [here](https://app.athenahq.ai/organization?tab=api).

````