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

# List posts

`GET /v1/posts`

## Request

- Base URL: `https://api.postlake.dev`
- URL: `https://api.postlake.dev/v1/posts`
- Auth: `bearerAuth` (a scheme the document does not define)

List posts by creation time (default), or use state=scheduled and sort=scheduledAt to walk a scheduled calendar chronologically. The scheduled cursor remains valid if earlier posts are cancelled.

## Query parameters

- `sort` 'created' | 'scheduledAt'
- `q` string
- `campaign` string
- `targetCount` 'single' | 'shared'
- `state` 'draft' | 'awaiting_approval' | 'rejected' | 'queued' | 'scheduled' | 'processing' | 'partial' | 'published' | 'failed'
- `account` string
- `profile` string
- `network` 'bluesky' | 'threads' | 'x' | 'linkedin' | 'instagram' | 'tiktok' | 'facebook' | 'youtube' | 'pinterest'
- `agent` string
- `surface` 'dashboard' | 'api' | 'agent'
- `approval` 'pending' | 'approved' | 'rejected'
- `from` string, date-time
- `to` string, date-time
- `limit` integer
- `cursor` string

## Response `200`

Success

- object
  - `posts` Post[], required
    - `id` string, required
    - `sourceDraftId` string: Immutable original draft ID. New approvals preserve this as id; legacy audited approvals may resolve an older ID to a different canonical id.
    - `snapshot` string: Computed full-state approval fence returned by GET. Includes media, options and metadata.
    - `state` 'draft' | 'awaiting_approval' | 'rejected' | 'queued' | 'scheduled' | 'processing' | 'partial' | 'published' | 'failed', required
    - `createdAt` string, date-time, required
    - `clientId` string: Stable machine principal that created the post. Absent for human-created dashboard posts.
    - `surface` 'dashboard' | 'api' | 'agent': Where the post was created, independent of the principal identity.
    - `approval` object: Present for approval-gated agent work, including the owner's final decision when one has been made.
      - `requestedAt` string, date-time, required
      - `decision` 'approved' | 'rejected'
      - `decidedAt` string, date-time
      - `reason` string
    - `scheduledAt` string, date-time, nullable, required
    - `timezone` string: IANA timezone the caller scheduled in, when they named one.
    - `scheduledAtLocal` string: Wall-clock time in timezone, computed on read. Not stored.
    - `text` string, required
    - `campaign` string
    - `assetMetadata` object
    - `media` string[], required
    - `warnings` string[]: Advisory notes from create or edit, for example PNG converted to JPEG for TikTok.
    - `platformOptions` object, nullable, required
      - `pinterest` object
        - `boardId` string
        - `link` string
        - `altText` string
    - `targets` PostTarget[], required
      - `removal` object: Present after accepted network removal on a partial result. Retry skips accepted destinations; verified separately confirms absence.
        - `accepted` true, required
        - `verified` boolean, required
        - `at` string, date-time, required
      - `account` string, required
      - `platform` 'bluesky' | 'threads' | 'x' | 'linkedin' | 'instagram' | 'tiktok' | 'facebook' | 'youtube' | 'pinterest', required
      - `state` 'queued' | 'scheduled' | 'processing' | 'published' | 'failed', required
      - `profile` string: Username of the profile this channel belongs to. Resolved when the post is read, so it follows the channel if it moves. Absent once the channel is disconnected.
      - `channelName` string: The channel's handle at the time of reading, not the one frozen at publish. Absent once the channel is disconnected.
      - `connection` object: The native account or destination identity captured when this target was scheduled. It is used only to repair a disconnected channel safely.
        - `platformAccountId` string
        - `destinationId` string
        - `destinationName` string
        - `handle` string
      - `remoteId` string, nullable, required
      - `url` string, nullable, required
      - `publishedAt` string, date-time, nullable, required
      - `permalinkPending` boolean: True when publication succeeded but an exact public permalink is still being resolved.
      - `error` NormalisedError, required: `type` is the coarse category you route on and is deliberately small, so it cannot say WHICH input was wrong. `code`, `fix`, `docs` and `param` are what turn a rejection into something a caller can act on rather than guess at. They are optional only in the sense that not every error has all four.
        - `type` string, required: Coarse category to route on, e.g. rate_limited, auth_expired, platform_rejected.
        - `message` string, required
        - `platform` 'bluesky' | 'threads' | 'x' | 'linkedin' | 'instagram' | 'tiktok' | 'facebook' | 'youtube' | 'pinterest'
        - `retryable` boolean, required
        - `code` string: Stable, granular handle to branch on, e.g. text_too_long. Also the anchor in the error reference.
        - `fix` string: The next action, in plain words. Safe to show a person as-is.
        - `docs` string, uri: Where the rule is written down, so it is learned once rather than rediscovered.
        - `param` string: The request field at fault, so a form can mark the right input.
  - `nextCursor` string, nullable, required

## Other responses

- `401`: Unauthorized

---

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