---
title: "Update scheduled post"
method: PATCH
path: "/api/apps/{app_id}/social-calendar/posts/{post_id}"
---

# Update scheduled post

`PATCH /api/apps/{app_id}/social-calendar/posts/{post_id}`

<Info>This API is in beta. Endpoints, fields, and behavior may still change, so avoid depending on it in production.</Info>

Edits the content or the schedule of a post that hasn't published yet. Send only the fields you want to change: an omitted field keeps its current value, and an empty body fails with a 400.

`proposal` and `scheduled` are the only editable states. Every other one answers 409 naming the state that blocked the edit: `publishing` while the publisher has the post, `posted` and `failed` once it's over, `publish_outcome_unknown` when the platform's answer was lost, and the `needs_reconnect` and `not_materialized_plan_limit` a scheduling run can leave behind. `platform` isn't editable in any state, because publishing to a different account is a new post rather than an edit.

<Note>Only the fields documented here are accepted, `platform` included, and any other field in the body fails with a 422. So don't read a post and send the whole object back: `id`, `app_id`, `status`, `workflow_id` and the rest of the response are Base44's, and a round-trip like that is rejected rather than partly applied. Send only the fields you're changing.</Note>

`image_url` and `image_prompt` are the only fields you can clear by sending `null`. A `null` for any other field fails with a 422.

Editing a post also takes over its content. A post generated from a content plan stops tracking that plan once you edit it, so regenerating the plan no longer overwrites what you wrote.

Editing `scheduled_at` only moves a post you haven't scheduled yet. A post that already carries a `workflow_id` is bound to the instant it had when you ran [Start scheduling posts](/api-reference/start-scheduling-posts), and it publishes then even though the calendar reports your new time. Content edits always take effect, because the post is read again at publish time. To move a post that's already scheduled, delete it and create it again at the new time.

The social calendar endpoints share two rate limits: 20 requests per minute across creating, editing, deleting and approving posts, and 40 requests per minute across the rest. This endpoint counts against the 20.

<Note>This endpoint accepts a personal API key. Workspace API keys are not authorized for it and are rejected with a 403.</Note>

## Path parameters

- `post_id` string, required — ID of the post, as returned by [List scheduled posts](/api-reference/list-scheduled-posts).
- `app_id` string, required — ID of the app whose social calendar you want.

## Request body

- UpdateScheduledPostPayload — Editable content and schedule fields. ``platform`` is absent on purpose: switching the target account changes which connector must publish the post, which is a new post rather than an edit. Every field is optional so an omitted one stays untouched. That makes ``None`` ambiguous, so an explicit null is rejected for the fields ``ScheduledPost`` stores non-nullable — otherwise it would write a row the model cannot load. Only the image fields can genuinely be cleared.
  - `title` string, nullable — New title for the post. Omit it to keep the current one; an explicit `null` fails with a 422.
  - `body` string, nullable — New body text. Omit it to keep the current one; an explicit `null` fails with a 422.
  - `scheduled_at` string, date-time, nullable — New publish time, as an ISO 8601 timestamp between the years 2000 and 2100. This only moves a post that isn't scheduled yet: once the post has a `workflow_id` it publishes at the time it was handed over with. An explicit `null` fails with a 422.
  - `scheduled_timezone` string, nullable — New IANA timezone for `scheduled_local_at`. It never moves the instant the post publishes. An explicit `null` fails with a 422.
  - `hook` string, nullable — New angle for the post. An explicit `null` fails with a 422.
  - `best_time_reason` string, nullable — New reason shown alongside the post's time. An explicit `null` fails with a 422.
  - `hashtags` string[], nullable — Replacement list of up to 30 hashtags, without the leading `#`. Send `[]` to publish none; an explicit `null` fails with a 422.
  - `image_url` string, nullable — New HTTPS image URL, or `null` to remove the image. Removing it from an Instagram post means the post is rejected when it publishes.
  - `image_prompt` string, nullable — New image prompt, or `null` to clear it.

## Response `200`

The post after the edit.

- ScheduledPostResponse
  - `id` string, required — ID of the post. Pass it as `post_id` to the other social calendar endpoints.
  - `app_id` string, required — ID of the app the post belongs to.
  - `plan_id` string, nullable, required — ID of the content plan the post was generated from, or `null` for a post created through [Create scheduled post](/api-reference/create-scheduled-post).
  - `source_post_id` string, nullable, required — ID this post has inside the content plan it came from, or `null` for a post created through the API.
  - `platform` string, required — Account the post publishes to. Base44 publishes to `instagram` and `linkedin`. A post generated from a content plan can also name `x`, `tiktok`, `reddit` or `facebook`, which Base44 plans for but can't publish, and scheduling such a post fails it.
  - `title` string, required — Title of the post. It labels the post on the calendar and isn't published as text, except on LinkedIn, where a post with an image sends it as the image's title.
  - `body` string, required — Body text of the post. Base44 publishes this followed by `hashtags`, so leave the tags out of it.
  - `hook` string, required — The angle the post leads with. A plan-generated post carries the angle the planner picked, such as `pain_point` or `social_proof`; a post you create carries whatever you sent, or an empty string.
  - `cover_index` integer, required — Zero-based position of the post in the series its content plan generated, which is how the calendar picks its cover image. Always `0` for a post created through the API.
  - `scheduled_at` string, date-time, required — When the post publishes, always in UTC. A post read back from the calendar carries no offset (`2026-09-15T14:00:00`), while the one [Create scheduled post](/api-reference/create-scheduled-post) returns carries `+00:00`. Read both as UTC.
  - `scheduled_local_at` string, required — The same instant as `scheduled_at`, rendered in `scheduled_timezone` as an ISO 8601 timestamp. Display only.
  - `scheduled_timezone` string, required — IANA timezone `scheduled_local_at` is rendered in. It never moves the instant the post publishes.
  - `best_time_reason` string, required — Why this time was picked, written by the planner for a plan-generated post. Empty unless something set it.
  - `hashtags` string[], required — Hashtags published after `body`, without the leading `#`. A leading `#` you send is stripped before publishing.
  - `image_url` string, nullable, required — HTTPS URL of the image published with the post, or `null` if it has none. An Instagram post needs one to publish.
  - `image_prompt` string, nullable, required — Prompt the post's image was generated from, or `null` if there is none. Kept for reference; this endpoint doesn't generate images from it.
  - `status` string, required — Where the post is in its lifecycle: `proposal` before you approve it, `scheduled` once approved, `publishing` while it's going out, then `posted`. `needs_reconnect` means the platform account has to be reconnected, `not_materialized_plan_limit` that the workspace plan doesn't cover publishing, `publish_outcome_unknown` that the platform may have accepted the post but Base44 couldn't confirm it, and `failed` that the post can't go out.
  - `workflow_id` string, nullable, required — ID of the automation that publishes this post, set once [Start scheduling posts](/api-reference/start-scheduling-posts) hands it over, and `null` before that. Its presence is what tells you the publish time is fixed.

## Other responses

- `400` — The body contains no fields to update.
- `401` — Missing or invalid credentials.
- `403` — You don't have editor access to this app, or you used a workspace API key.
- `404` — App not found, the post doesn't exist or is already deleted, or the social calendar is not enabled for your account.
- `409` — The post is publishing, or it's past the point where it can be edited.
- `422` — Validation Error
- `429` — Rate limit exceeded (20 requests per minute).

---

[API](https://skmtc.dev/base44/apis/base44-app-management-api.md) · [All operations](https://skmtc.dev/base44/apis/base44-app-management-api/llms.txt) · [OpenAPI document](https://skmtc-service-production.skmtc.workers.dev/v1/apis/base44/base44-app-management-api/revisions/173e4e9c63c2/schema)
