---
title: "List posts"
method: GET
path: "/api/v1/posts"
tags: ["Posts"]
---

# List posts

`GET /api/v1/posts`

## Request

- Base URL: `https://www.poster.ly`
- URL: `https://www.poster.ly/api/v1/posts`
- Auth: HTTP bearer

Returns posts across every workspace you belong to, teammates' posts included, per your role in each workspace. Pass `workspace_id` to scope to one workspace. A brand-locked seat only sees posts in its assigned brands. A draft any editor skipped in the Content Engine review queue is always excluded, even when you explicitly filter status=draft. Filter a calendar window with `scheduled_from` and `scheduled_to` (plain dates are read in `timezone`). Results are paged: `total` is the exact count for the filters, and `has_more` / `next_offset` tell you whether to call again. The order is total (sort field, then created_at, then id), so offset pages never skip or repeat a post. For per-day, per-account, or per-brand totals use `GET /api/v1/posts/counts`.

## Query parameters

- `status` string
- `platform` string
- `account_id` string
- `workspace_id` string
- `scheduled_from` string
- `scheduled_to` string
- `timezone` string
- `order` 'asc' | 'desc'
- `limit` integer
- `offset` integer
- `updated_since` string, date-time
- `created_since` string, date-time
- `sort_by` 'scheduled_at' | 'updated_at' | 'created_at'
- `approval_status` 'none' | 'pending_client' | 'approved' | 'changes_requested' | 'rejected'
- `approval_waiting_on` 'client' | 'team'
- `brand_id` string, uuid

## Response `200`

Posts fetched successfully

- PostsListResponse
  - `posts` Post[], required
    - `id` integer, required
    - `content` string, nullable
    - `scheduled_at` string, date-time, required
    - `social_account_id` integer, required
    - `media_url` string, nullable
    - `media_urls` string[], nullable
    - `status` string, required
    - `post_type` string, nullable
    - `platform_post_url` string, nullable
    - `published_at` string, date-time, nullable
    - `metadata` object, nullable
    - `reel_cover_url` string, nullable
    - `reel_cover_method` string, nullable
    - `reel_thumb_offset` number, nullable
    - `created_at` string, date-time, required: When the post was created (ISO 8601 with time zone). Read-only.
    - `updated_at` string, date-time, required
    - `created_by` object: Who or what created the post. Read-only. Any field is null when it was never recorded: posts created before the creation channel was tracked have a null source.
      - `user_id` string, uuid, nullable, required: The posterly account the post was created under.
      - `name` string, nullable, required: That account's full name, falling back to its username, then its email address. Filled in by GET /api/v1/posts, GET /api/v1/posts/{id}, and PATCH /api/v1/posts/{id}; null elsewhere or when unknown.
      - `source` string, nullable, required: How the post was created, for example dashboard, api_v1, mcp_http, mcp_stdio, bulk_upload, autopublisher, weekly_pack.
      - `source_label` string, nullable, required: A readable label for source, for example Dashboard, REST API, MCP.
    - `brand_id` string, uuid, nullable: The assigned brand/client, matching the id from GET /api/v1/brands. Read-only.
    - `content_plan_id` string, uuid, nullable: Read-only.
    - `workspace_id` string, uuid, nullable: The workspace this post belongs to. Read-only; null only for legacy posts created before workspaces.
    - `approval` object: Client review status. Cannot be set through POST or PATCH. Change it with POST /api/v1/posts/{id}/approval (workspace owner or admin only).
      - `status` 'none' | 'pending_client' | 'approved' | 'changes_requested' | 'rejected', required
      - `asset_status` 'none' | 'pending_client' | 'approved' | 'changes_requested' | 'rejected', required
      - `caption_status` 'none' | 'pending_client' | 'approved' | 'changes_requested' | 'rejected', required
      - `waiting_on` 'client' | 'team', nullable, required: 'client' when status is pending_client, 'team' when changes_requested or rejected, null otherwise.
      - `pending_client_approval` boolean, required: True only when status is pending_client.
      - `requested_at` string, date-time, nullable, required
      - `completed_at` string, date-time, nullable, required
  - `total` integer, required: Exact number of posts matching every filter, across all pages.
  - `limit` integer, required
  - `offset` integer, required
  - `has_more` boolean, required: True while offset + posts.length is below total. Keep paging until it is false before drawing conclusions about totals.
  - `next_offset` integer, nullable, required: The offset of the next page, or null on the last page.
  - `order` 'asc' | 'desc', required
  - `range` PostsScheduledRange: The resolved scheduled range, echoed when scheduled_from or scheduled_to was given. `from` is inclusive and `to` exclusive; a plain-date scheduled_to has already moved to the start of the next day in `timezone`.
    - `from` string, date-time, nullable, required
    - `to` string, date-time, nullable, required
    - `timezone` string, required

## Other responses

- `400`: Validation error
- `401`: Invalid or missing API key
- `429`: Too many requests

---

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