---
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](/developers/references/apps-api/sections/virality#scheduled-posts) that hasn't published yet. Send only the fields you want to change. An omitted field keeps its current value.

A post can only be edited while its status is [`proposal` or `scheduled`](/developers/references/apps-api/sections/virality#scheduled-posts). To publish elsewhere, create a new post instead. An existing post's `platform` isn't editable in any state.

Only the fields documented here are accepted, `platform` included. Don't read a post and send the whole object back. Base44 owns `id`, `app_id`, `status`, `workflow_id`, and the rest of the response, so a round-trip like that is rejected rather than partly applied. Send only the fields you're changing.

Only `image_url` and `image_prompt` can be cleared, by sending `null`. Any other field rejects an explicit `null`.

A post generated from a [content plan](/developers/references/apps-api/sections/virality#content-plans) normally stays linked to it. Using [Refine a post](/api-reference/refine-a-post), [Update post content](/api-reference/update-post-content), or [Generate a post image](/api-reference/generate-a-post-image) on that post also updates the matching row on the calendar. Editing it here breaks that link, so those endpoints no longer touch it afterward.

Editing `scheduled_at` moves the post's publish time only before it has a `workflow_id`, the ID of the automation [Start scheduling posts](/api-reference/start-scheduling-posts) creates to publish it. Once that automation exists, it publishes at the time it was given, even if you later send a different `scheduled_at`. The calendar shows your new value, but the post still goes out at the original time. To actually move a post that's already reached this point, delete it and create it again at the new time.

Content changes work differently. Because the publisher reads a post's current content at publish time, an edit to `title`, `body`, or the other content fields always takes effect, even after the post has a `workflow_id`.

## 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.
  - `title` string, nullable — New title for the post. Omit it to keep the current one.
  - `body` string, nullable — New body text. Omit it to keep the current one, or send an empty string to clear it.
  - `scheduled_at` string, date-time, nullable — New publish time, as an ISO 8601 timestamp between the years 2000 and 2100. Omit it to keep the post's current time. 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.
  - `scheduled_timezone` string, nullable — New IANA timezone for `scheduled_local_at`. Omit it to keep the current one. It never moves the instant the post publishes.
  - `hook` string, nullable — New angle for the post. Omit it to keep the current one, or send an empty string to clear it.
  - `best_time_reason` string, nullable — New reason shown alongside the post's time. Omit it to keep the current one, or send an empty string to clear it.
  - `hashtags` string[], nullable — Replacement list of up to 30 hashtags, without the leading `#`. Omit it to keep the current list, or send `[]` to publish none.
  - `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`, `linkedin` and `facebook`. A post generated from a content plan can also name `x`, `tiktok` or `reddit`, 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, either `pain_point`, `feature_demo`, `social_proof`, `trending_hook`, `user_story`, or `before_after`. 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. Display only.
  - `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. Either `proposal`, `scheduled`, `publishing`, `posted`, `failed`, `publish_outcome_unknown`, `needs_reconnect`, or `not_materialized_plan_limit`. See [Scheduled posts](/developers/references/apps-api/sections/virality#scheduled-posts) for what each one means.
  - `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 isn't `proposal` or `scheduled`, the only editable states. See [Scheduled posts](/developers/references/apps-api/sections/virality#scheduled-posts) for what the other states mean.
- `422` — The request body sends a field this endpoint doesn't accept, sends `null` for a field other than `image_url` or `image_prompt`, violates a field's length or type constraint, or fails one of these checks: - `image_url` isn't an HTTPS URL. - `scheduled_timezone` isn't a real IANA timezone name. - `scheduled_at` is outside the years 2000 to 2100.
- `429` — Rate limit exceeded (20 requests per minute), shared across creating, editing, deleting, and approving posts. See [Rate limits](/developers/references/apps-api/get-started/rate-limits).

## Changes

> 18 revisions in range; 1 not diffed.

- **2026-09-03** `9f4b5dac6451` — 1 info
  - endpoint added

[Change history](https://skmtc.dev/adexad/apis/base44-app-management-api/changes/api/apps/:app_id/social-calendar/posts/:post_id/patch.md)

---

[API](https://skmtc.dev/adexad/apis/base44-app-management-api.md) · [All operations](https://skmtc.dev/adexad/apis/base44-app-management-api/llms.txt) · [OpenAPI document](https://skmtc.dev/adexad/apis/base44-app-management-api/revisions/28fc82924122?raw)
