# GET /v1/projects/:projectId/scheduled-posts (/docs/api/reference/publishing/list-posts)



<Endpoint method="GET" path="/v1/projects/:projectId/scheduled-posts" auth="Bearer" scope="publish:read" phase="1" />

Enumerate scheduled posts on a project. Useful for populating a queue view in your UI, batch-polling terminal states after a bulk schedule, or reconciling against your own post ledger.

Paginates by `cursor`. Default sort is `scheduledFor` descending (most-recent-first), which matches a "recent activity" view - use `since`/`until` to window a queue.

<Parameters
  title="Path"
  rows="[
  { name: 'projectId', type: 'string', required: true, description: 'Project whose posts you want.' },
]"
/>

<Parameters
  title="Query"
  rows="[
  { name: 'status', type: 'string | string[]', description: 'One of queued, publishing, draft, published, failed, canceled. Repeat the parameter (e.g. `?status=queued&status=publishing`) to filter on multiple statuses.' },
  { name: 'socialAccountId', type: 'string', description: 'Scope to one connected account.' },
  { name: 'since', type: 'string (ISO 8601, UTC Z)', description: 'Inclusive lower bound on scheduledFor.' },
  { name: 'until', type: 'string (ISO 8601, UTC Z)', description: 'Inclusive upper bound on scheduledFor.' },
  { name: 'cursor', type: 'string', description: 'Opaque pagination cursor from a previous response.' },
  { name: 'limit', type: 'integer', description: 'Page size, 1–100.', default: '50' },
]"
/>

## Example request [#example-request]

<Tabs items="['curl', 'TypeScript', 'Python']">
  <Tab value="curl">
    ```bash
    curl "https://api.layers.com/v1/projects/prj_254a4ce1-f4ca-42b1-9e36-17ca45ef3d39/scheduled-posts?status=queued&status=publishing&limit=100" \
      -H "Authorization: Bearer lp_..."
    ```
  </Tab>

  <Tab value="TypeScript">
    ```ts
    async function* walkAllPending(projectId: string) {
      let cursor: string | undefined;
      do {
        const page = await layers.publishing.listScheduledPosts({
          projectId,
          status: ["queued", "publishing"],
          limit: 100,
          cursor,
        });
        yield* page.items;
        cursor = page.nextCursor ?? undefined;
      } while (cursor);
    }
    ```
  </Tab>

  <Tab value="Python">
    ```python
    def walk_all_pending(project_id: str):
        cursor = None
        while True:
            page = layers.publishing.list_scheduled_posts(
                project_id=project_id,
                status=["queued", "publishing"],
                limit=100,
                cursor=cursor,
            )
            yield from page["items"]
            cursor = page.get("nextCursor")
            if not cursor:
                return
    ```
  </Tab>
</Tabs>

## Response [#response]

<Response status="200" description="Page of posts">
  ```json
  {
    "items": [
      {
        "id": "sp_4c8e7d2f-9a1b-4c3d-8e7f-2a1b3c4d5e60",
        "containerId": "cnt_8f1d6c3e-4b2a-4a18-9e4f-c2d7a1b0e999",
        "socialAccountId": "sa_71b2a4e5-8c3f-4d1a-9e7b-2c5d8f0a1b22",
        "platform": "tiktok",
        "mode": "publish",
        "status": "queued",
        "scheduledFor": "2026-04-19T14:00:00Z",
        "attemptedAt": null,
        "publishedAt": null,
        "externalUrl": null
      },
      {
        "id": "sp_7061bc99-4b63-4afb-96ad-408140f4187e",
        "containerId": "cnt_9a102945-52bb-4e92-aee3-96ebc7bf09b7",
        "socialAccountId": "sa_67857146-69a8-4e23-94cb-499e34ae43e5",
        "platform": "instagram",
        "mode": "publish",
        "status": "published",
        "scheduledFor": "2026-04-18T16:00:00Z",
        "attemptedAt": "2026-04-18T16:00:11Z",
        "publishedAt": "2026-04-18T16:00:29Z",
        "externalUrl": "https://www.instagram.com/p/DYgPEhiCeSU/"
      }
    ],
    "nextCursor": "cur_01HXZP8K9M4N5P6QRSTU"
  }
  ```
</Response>

<Callout type="info">
  **`externalUrl` for Instagram rows.** When `platform: "instagram"` and
  `status: "published"`, `externalUrl` carries the Graph API permalink
  (`instagram.com/p/<shortcode>` or `instagram.com/reel/<shortcode>`).
  In rare network-blip cases the publisher's optional `?fields=permalink`
  follow-up fetch fails and `externalUrl` lands `null` even though
  `externalId` + `publishedAt` are populated. TikTok rows always have
  `externalUrl` populated when `externalId` is — no equivalent edge case.
  See [`GET /v1/scheduled-posts/:id`](/docs/api/reference/publishing/get-post#status-values).
</Callout>

## Errors [#errors]

| Status | Code              | When                                                         |
| ------ | ----------------- | ------------------------------------------------------------ |
| 422    | `VALIDATION`      | `since` > `until`, `limit` out of range, bad `status` value. |
| 401    | `UNAUTHENTICATED` | Missing or invalid key.                                      |
| 403    | `FORBIDDEN_SCOPE` | Key lacks `publish:read`.                                    |
| 404    | `NOT_FOUND`       | Project not in your organization.                            |

## See also [#see-also]

* [`POST /v1/content/:id/publish`](/docs/api/reference/publishing/publish-content) - publish now
* [`POST /v1/content/:id/schedule`](/docs/api/reference/publishing/schedule-content) - queue for later
* [`GET /v1/scheduled-posts/:id`](/docs/api/reference/publishing/get-post) - full status for one post
* [`POST /v1/scheduled-posts/:id/reschedule`](/docs/api/reference/publishing/reschedule-post) - reschedule
* [`DELETE /v1/scheduled-posts/:id`](/docs/api/reference/publishing/cancel-post) - cancel while queued
