---
title: "List posts"
method: GET
path: "/posts"
---

# List posts

`GET /posts`

## Request

- Base URL: `https://app.voteship.app/api/v1`
- URL: `https://app.voteship.app/api/v1/posts`
- Auth: HTTP bearer

Stable cursor scans sort by descending creation time (millisecond precision), then ID, and retain the first request time bound. Later inserts outside the initial millisecond are excluded. Boundary deletion and vote changes do not shift pages. This is not a historical snapshot: deletions and changes in filter membership remain live. Offset pages may shift under writes.

## Query parameters

- `status` 'PENDING' | 'APPROVED' | 'IN_PROGRESS' | 'COMPLETE' | 'CLOSED' | 'ARCHIVED'
- `sort` 'votes' | 'date'
- `page` integer
- `limit` integer
- `cursor` string
- `updated_since` string, date-time

## Response `200`

Paginated list of posts

- object
  - `data` PostWithTags[]
    - `id` string
    - `projectId` string
    - `title` string
    - `description` string, nullable
    - `status` 'PENDING' | 'APPROVED' | 'IN_PROGRESS' | 'COMPLETE' | 'CLOSED' | 'ARCHIVED'
    - `voteCount` integer
    - `metadata` object, nullable: Private context. Replaces the object; null clears it. Omitted from public responses; available to secret-key APIs and trusted admin webhooks.
    - `createdAt` string, date-time
    - `updatedAt` string, date-time
    - `tags` Tag[]
      - `id` string
      - `label` string
      - `theme` string
      - `createdAt` string, date-time
  - `pagination` Pagination
    - `page` integer
    - `limit` integer
    - `total` integer
    - `totalPages` integer
    - `hasMore` boolean: Cursor mode only.
    - `nextCursor` string, nullable: Cursor mode only; null when finished. Use this instead of page/totalPages to advance.

---

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