# GET /v1/scheduled-posts/:scheduledPostId (/docs/api/reference/publishing/get-scheduled-post)



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

Read a scheduled post's current state — whether it's queued, publishing right now, already published (with the external URL), or failed (with an error).

<Callout type="info">
  Polling cadence: every 30 seconds while the status is `queued`, every 5 seconds while `publishing`, then stop once it reaches a terminal state (`published`, `failed`, or `canceled`). Or subscribe to [webhooks](/docs/api/operational/webhooks) to skip polling.
</Callout>

<Parameters
  title="Path"
  rows="[
  { name: 'scheduledPostId', type: 'string', required: true, description: 'Id returned by schedule or publish.' },
]"
/>

## Example request [#example-request]

<Tabs items="['curl', 'TypeScript', 'Python']">
  <Tab value="curl">
    ```bash
    curl https://api.layers.com/v1/scheduled-posts/sp_01HXZN4K5M6P7QRS8TUV9WXYZA \
      -H "Authorization: Bearer lp_live_01HX9Y6K7EJ4T2_4QZpN..."
    ```
  </Tab>

  <Tab value="TypeScript">
    ```ts
    async function waitUntilPublished(id: string) {
      for (;;) {
        const post = await layers.publishing.getScheduledPost({ id });
        if (post.status === "published") return post;
        if (post.status === "failed") throw new Error(post.lastError?.message ?? "publish failed");
        if (post.status === "canceled") throw new Error("canceled");
        await new Promise((r) => setTimeout(r, post.status === "publishing" ? 5000 : 30000));
      }
    }
    ```
  </Tab>

  <Tab value="Python">
    ```python
    import time

    def wait_until_published(post_id: str) -> dict:
        while True:
            post = layers.publishing.get_scheduled_post(id=post_id)
            if post["status"] == "published":
                return post
            if post["status"] in ("failed", "canceled"):
                raise RuntimeError(post.get("lastError", {}).get("message", post["status"]))
            time.sleep(5 if post["status"] == "publishing" else 30)
    ```
  </Tab>
</Tabs>

## Response [#response]

<Response status="200" description="Published">
  ```json
  {
    "id": "sp_01HXZN4K5M6P7QRS8TUV9WXYZA",
    "containerId": "cnt_01HXZM3K4N5P6QRS7TUV8WXYZ9",
    "socialAccountId": "sa_01HXZ9P2M4N5KLM6TUV7WXYZ9A",
    "platform": "tiktok",
    "mode": "direct_publish",
    "status": "published",
    "externalId": "7385912341234567890",
    "externalUrl": "https://www.tiktok.com/@acmecoffee/video/7385912341234567890",
    "scheduledFor": "2026-04-19T14:00:00Z",
    "attemptedAt": "2026-04-19T14:00:12Z",
    "publishedAt": "2026-04-19T14:00:18Z",
    "canceledAt": null,
    "lastError": null,
    "createdAt": "2026-04-19T13:55:01Z",
    "updatedAt": "2026-04-19T14:00:18Z"
  }
  ```
</Response>

<Response status="200" description="Failed — read lastError">
  ```json
  {
    "id": "sp_01HXZN4K5M6P7QRS8TUV9WXYZB",
    "status": "failed",
    "attemptedAt": "2026-04-19T14:00:12Z",
    "publishedAt": null,
    "canceledAt": null,
    "lastError": {
      "code": "CREDENTIAL_INVALID",
      "message": "The social account's token was revoked upstream.",
      "data": { "platform": "instagram", "platformCode": "OAuthException" }
    },
    "createdAt": "2026-04-19T13:55:01Z",
    "updatedAt": "2026-04-19T14:00:25Z"
  }
  ```
</Response>

### Status values [#status-values]

| `status`         | Terminal? | Meaning                                                                                                                   |
| ---------------- | --------- | ------------------------------------------------------------------------------------------------------------------------- |
| `queued`         | no        | Waiting for `scheduledFor`, or waiting on approval.                                                                       |
| `publishing`     | no        | Layers is actively uploading media and calling the platform API.                                                          |
| `draft_in_inbox` | yes       | `mode: draft_to_device` — draft landed in the user's mobile app; they finish by tapping post. Terminal from Layers' side. |
| `published`      | yes       | `externalId` and `externalUrl` are populated.                                                                             |
| `failed`         | yes       | `lastError` is populated.                                                                                                 |
| `canceled`       | yes       | You or a token revocation canceled it.                                                                                    |

## Errors [#errors]

| Status | Code              | When                           |
| ------ | ----------------- | ------------------------------ |
| 401    | `UNAUTHENTICATED` | Missing or invalid key.        |
| 403    | `FORBIDDEN_SCOPE` | Key lacks `publish:write`.     |
| 404    | `NOT_FOUND`       | Post not in your organization. |

## See also [#see-also]

* [`GET /v1/projects/:id/scheduled-posts`](/docs/api/reference/publishing/list-scheduled-posts) — batch poll
* [`POST /v1/scheduled-posts/:id/reschedule`](/docs/api/reference/publishing/reschedule-post) — change `scheduledFor`
* [`DELETE /v1/scheduled-posts/:id`](/docs/api/reference/publishing/cancel-post) — cancel while queued
