# GET /v1/scheduled-posts/:scheduledPostId (/docs/api/reference/publishing/get-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">
  Poll until the post 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_4c8e7d2f-9a1b-4c3d-8e7f-2a1b3c4d5e60 \
      -H "Authorization: Bearer lp_..."
    ```
  </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 waitBeforeNextPoll();
      }
    }
    ```
  </Tab>

  <Tab value="Python">
    ```python
    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"]))
            wait_before_next_poll()
    ```
  </Tab>
</Tabs>

## Response [#response]

<Response status="200" description="Published">
  ```json
  {
    "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": "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_d6e8f3a1-7b2c-4d5e-9a8b-3c4d5e6f7080",
    "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`      | yes       | `mode: draft` — draft landed in the user's mobile app (TikTok inbox / IG SMS); they finish posting by hand. Terminal from Layers' side. The write-side mode and read-side status share the same string — no translation table needed. |
| `published`  | yes       | `externalId` is populated. `externalUrl` is populated on TikTok unconditionally and on Instagram when the publisher captured a `permalink` from the Graph API (see Instagram callout below).                                          |
| `failed`     | yes       | `lastError` is populated.                                                                                                                                                                                                             |
| `canceled`   | yes       | You or a token revocation canceled it.                                                                                                                                                                                                |

<Callout type="info">
  **`externalUrl` for Instagram.** Instagram permalinks use an opaque shortcode
  (`/p/<shortcode>` or `/reel/<shortcode>`) that can't be derived from the
  numeric `externalId`. The publisher fetches the permalink from the Graph
  API's `?fields=permalink` follow-up after a successful publish and
  surfaces it as `externalUrl`. In rare network-blip cases that fetch
  fails — the post is still live and `externalId` + `publishedAt`
  populate normally, but `externalUrl` stays `null`. Open the IG mobile
  app for the connected account to view the post manually. TikTok is
  always populated when `externalId` is — no equivalent edge case.
</Callout>

## Errors [#errors]

| Status | Code              | When                           |
| ------ | ----------------- | ------------------------------ |
| 401    | `UNAUTHENTICATED` | Missing or invalid key.        |
| 403    | `FORBIDDEN_SCOPE` | Key lacks `publish:read`.      |
| 404    | `NOT_FOUND`       | Post 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/projects/:id/scheduled-posts`](/docs/api/reference/publishing/list-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
