> ## Documentation Index
> Fetch the complete documentation index at: https://grow-hub.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# Posts and lifecycle

> The five post statuses and the transitions between them.

A post is one piece of content plus the platforms it targets. It moves through
five statuses:

| Status      | Meaning                                                         |
| ----------- | --------------------------------------------------------------- |
| `draft`     | Being written. Fully editable.                                  |
| `scheduled` | Has a future `scheduledAt` and a resolved `scheduledPlatform`.  |
| `queued`    | Claimed by the scheduler and handed to the dispatch queue.      |
| `posted`    | Live on the platform. `externalPostId` holds the platform's id. |
| `failed`    | Dispatch gave up. `failureReason` says why.                     |

```
create_draft ──▶ draft ──schedule_post──▶ scheduled ──cron──▶ queued ──▶ posted
                   │                          │                  │
                   └──────publish_post────────┘                  └──▶ failed
                                                                       │
                              unschedule_post ◀─────────────────────────┘
```

## What's editable when

| Action                 | Allowed from                                         |
| ---------------------- | ---------------------------------------------------- |
| Edit `content`         | `draft`, `scheduled`                                 |
| Edit `targetPlatforms` | `draft` only — unschedule first                      |
| `delete_draft`         | Any status except `queued`                           |
| `publish_post`         | `draft` only                                         |
| `schedule_post`        | `draft`, `scheduled` (re-schedule), `failed` (retry) |
| `unschedule_post`      | `scheduled`, `failed` — returns it to `draft`        |

<Note>
  Editing the content of a **scheduled** post re-checks the length limit for the
  platform it is already aimed at, so an edit can't silently break dispatch.
  Retargeting is draft-only because the resolved `scheduledPlatform` would go
  stale.
</Note>

## Fields

<ResponseField name="id" type="string">Post id.</ResponseField>

<ResponseField name="url" type="string">
  Deep link into the web studio (`{WEB_ORIGIN}/posts/{id}`). Share this with the
  user instead of a bare id. Requires them to be signed in — it is not a public
  share link.
</ResponseField>

<ResponseField name="content" type="string">Body text, up to 10,000 characters at draft time.</ResponseField>
<ResponseField name="status" type="string">One of the five statuses above.</ResponseField>
<ResponseField name="targetPlatforms" type="string[]">Platforms this post may go to, e.g. `["linkedin"]`.</ResponseField>
<ResponseField name="scheduledAt" type="string | null">ISO timestamp of the pending dispatch.</ResponseField>
<ResponseField name="scheduledPlatform" type="string | null">The single platform a scheduled post will publish to.</ResponseField>
<ResponseField name="externalPostId" type="string | null">Platform-side id, set once posted.</ResponseField>
<ResponseField name="postedAt" type="string | null">When it went live.</ResponseField>
<ResponseField name="failureReason" type="string | null">Platform and message from the last failed dispatch.</ResponseField>
<ResponseField name="dispatchAttempts" type="number">Delivery attempts made by the scheduler.</ResponseField>
<ResponseField name="assets" type="object[]">Attached assets — `{ id, postId, kind, mimeType, filename, bytes, status }`.</ResponseField>
<ResponseField name="organizationId" type="string">The studio that owns the post.</ResponseField>
<ResponseField name="authorId" type="string">User who created it.</ResponseField>
<ResponseField name="createdAt" type="string">Creation timestamp.</ResponseField>
<ResponseField name="updatedAt" type="string">Last modification timestamp.</ResponseField>

## Targets vs. the publish target

`targetPlatforms` is a *list of candidates*. Publishing is always single-target:

* One target → `publish_post` and `schedule_post` resolve it automatically.
* Several targets → pass `platform` explicitly, or you get `specify_platform`.
* A `platform` outside the list is rejected with `post_does_not_target_<id>`.

Creating a draft with no `targetPlatforms` (or an empty array) targets **every**
supported platform.
