curl --request PATCH \
--url https://app.base44.com/api/apps/{app_id}/social-calendar/posts/{post_id} \
--header 'Content-Type: application/json' \
--header 'api_key: <api-key>' \
--data '
{
"title": "Ship a CRM in an afternoon",
"body": "We replaced our lead spreadsheet with an app we built in an afternoon.",
"scheduled_at": "2026-09-16T09:30:00Z",
"scheduled_timezone": "Asia/Jerusalem",
"hook": "social_proof",
"best_time_reason": "Our audience checks LinkedIn before lunch.",
"hashtags": [
"buildinpublic",
"crm"
],
"image_url": "https://cdn.example.com/posts/crm-launch-v2.png",
"image_prompt": "A freelancer closing a deal on a laptop, warm morning light"
}
'import requests
url = "https://app.base44.com/api/apps/{app_id}/social-calendar/posts/{post_id}"
payload = {
"title": "Ship a CRM in an afternoon",
"body": "We replaced our lead spreadsheet with an app we built in an afternoon.",
"scheduled_at": "2026-09-16T09:30:00Z",
"scheduled_timezone": "Asia/Jerusalem",
"hook": "social_proof",
"best_time_reason": "Our audience checks LinkedIn before lunch.",
"hashtags": ["buildinpublic", "crm"],
"image_url": "https://cdn.example.com/posts/crm-launch-v2.png",
"image_prompt": "A freelancer closing a deal on a laptop, warm morning light"
}
headers = {
"api_key": "<api-key>",
"Content-Type": "application/json"
}
response = requests.patch(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'PATCH',
headers: {api_key: '<api-key>', 'Content-Type': 'application/json'},
body: JSON.stringify({
title: 'Ship a CRM in an afternoon',
body: JSON.stringify('We replaced our lead spreadsheet with an app we built in an afternoon.'),
scheduled_at: '2026-09-16T09:30:00Z',
scheduled_timezone: 'Asia/Jerusalem',
hook: 'social_proof',
best_time_reason: 'Our audience checks LinkedIn before lunch.',
hashtags: ['buildinpublic', 'crm'],
image_url: 'https://cdn.example.com/posts/crm-launch-v2.png',
image_prompt: 'A freelancer closing a deal on a laptop, warm morning light'
})
};
fetch('https://app.base44.com/api/apps/{app_id}/social-calendar/posts/{post_id}', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://app.base44.com/api/apps/{app_id}/social-calendar/posts/{post_id}",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "PATCH",
CURLOPT_POSTFIELDS => json_encode([
'title' => 'Ship a CRM in an afternoon',
'body' => 'We replaced our lead spreadsheet with an app we built in an afternoon.',
'scheduled_at' => '2026-09-16T09:30:00Z',
'scheduled_timezone' => 'Asia/Jerusalem',
'hook' => 'social_proof',
'best_time_reason' => 'Our audience checks LinkedIn before lunch.',
'hashtags' => [
'buildinpublic',
'crm'
],
'image_url' => 'https://cdn.example.com/posts/crm-launch-v2.png',
'image_prompt' => 'A freelancer closing a deal on a laptop, warm morning light'
]),
CURLOPT_HTTPHEADER => [
"Content-Type: application/json",
"api_key: <api-key>"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://app.base44.com/api/apps/{app_id}/social-calendar/posts/{post_id}"
payload := strings.NewReader("{\n \"title\": \"Ship a CRM in an afternoon\",\n \"body\": \"We replaced our lead spreadsheet with an app we built in an afternoon.\",\n \"scheduled_at\": \"2026-09-16T09:30:00Z\",\n \"scheduled_timezone\": \"Asia/Jerusalem\",\n \"hook\": \"social_proof\",\n \"best_time_reason\": \"Our audience checks LinkedIn before lunch.\",\n \"hashtags\": [\n \"buildinpublic\",\n \"crm\"\n ],\n \"image_url\": \"https://cdn.example.com/posts/crm-launch-v2.png\",\n \"image_prompt\": \"A freelancer closing a deal on a laptop, warm morning light\"\n}")
req, _ := http.NewRequest("PATCH", url, payload)
req.Header.Add("api_key", "<api-key>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.patch("https://app.base44.com/api/apps/{app_id}/social-calendar/posts/{post_id}")
.header("api_key", "<api-key>")
.header("Content-Type", "application/json")
.body("{\n \"title\": \"Ship a CRM in an afternoon\",\n \"body\": \"We replaced our lead spreadsheet with an app we built in an afternoon.\",\n \"scheduled_at\": \"2026-09-16T09:30:00Z\",\n \"scheduled_timezone\": \"Asia/Jerusalem\",\n \"hook\": \"social_proof\",\n \"best_time_reason\": \"Our audience checks LinkedIn before lunch.\",\n \"hashtags\": [\n \"buildinpublic\",\n \"crm\"\n ],\n \"image_url\": \"https://cdn.example.com/posts/crm-launch-v2.png\",\n \"image_prompt\": \"A freelancer closing a deal on a laptop, warm morning light\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://app.base44.com/api/apps/{app_id}/social-calendar/posts/{post_id}")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Patch.new(url)
request["api_key"] = '<api-key>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"title\": \"Ship a CRM in an afternoon\",\n \"body\": \"We replaced our lead spreadsheet with an app we built in an afternoon.\",\n \"scheduled_at\": \"2026-09-16T09:30:00Z\",\n \"scheduled_timezone\": \"Asia/Jerusalem\",\n \"hook\": \"social_proof\",\n \"best_time_reason\": \"Our audience checks LinkedIn before lunch.\",\n \"hashtags\": [\n \"buildinpublic\",\n \"crm\"\n ],\n \"image_url\": \"https://cdn.example.com/posts/crm-launch-v2.png\",\n \"image_prompt\": \"A freelancer closing a deal on a laptop, warm morning light\"\n}"
response = http.request(request)
puts response.read_body{
"id": "6886b8d390dc7e2f4a2c91b3",
"app_id": "6820f3a4e7b91d003c45a1f2",
"plan_id": "8c1f9a2e-3b7d-4c5e-9f01-2a3b4c5d6e7f",
"source_post_id": "3f2504e0-4f89-11d3-9a0c-0305e82c3301",
"platform": "linkedin",
"title": "Ship a CRM in an afternoon",
"body": "We replaced our lead spreadsheet with an app we built in an afternoon. Here's what changed.",
"hook": "pain_point",
"cover_index": 0,
"scheduled_at": "2026-09-15T14:00:00",
"scheduled_local_at": "2026-09-15T17:00:00+03:00",
"scheduled_timezone": "Asia/Jerusalem",
"best_time_reason": "Weekday afternoons get the most engagement for this audience.",
"hashtags": [
"buildinpublic",
"crm"
],
"image_url": "https://cdn.example.com/posts/crm-launch.png",
"image_prompt": "A freelancer closing a deal on a laptop, warm morning light",
"status": "scheduled",
"workflow_id": "68a1c4f0d21b4e0a3c77e912"
}{
"detail": [
{
"loc": [
"<string>"
],
"msg": "<string>",
"type": "<string>"
}
]
}Update scheduled post
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.
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.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, 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.
curl --request PATCH \
--url https://app.base44.com/api/apps/{app_id}/social-calendar/posts/{post_id} \
--header 'Content-Type: application/json' \
--header 'api_key: <api-key>' \
--data '
{
"title": "Ship a CRM in an afternoon",
"body": "We replaced our lead spreadsheet with an app we built in an afternoon.",
"scheduled_at": "2026-09-16T09:30:00Z",
"scheduled_timezone": "Asia/Jerusalem",
"hook": "social_proof",
"best_time_reason": "Our audience checks LinkedIn before lunch.",
"hashtags": [
"buildinpublic",
"crm"
],
"image_url": "https://cdn.example.com/posts/crm-launch-v2.png",
"image_prompt": "A freelancer closing a deal on a laptop, warm morning light"
}
'import requests
url = "https://app.base44.com/api/apps/{app_id}/social-calendar/posts/{post_id}"
payload = {
"title": "Ship a CRM in an afternoon",
"body": "We replaced our lead spreadsheet with an app we built in an afternoon.",
"scheduled_at": "2026-09-16T09:30:00Z",
"scheduled_timezone": "Asia/Jerusalem",
"hook": "social_proof",
"best_time_reason": "Our audience checks LinkedIn before lunch.",
"hashtags": ["buildinpublic", "crm"],
"image_url": "https://cdn.example.com/posts/crm-launch-v2.png",
"image_prompt": "A freelancer closing a deal on a laptop, warm morning light"
}
headers = {
"api_key": "<api-key>",
"Content-Type": "application/json"
}
response = requests.patch(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'PATCH',
headers: {api_key: '<api-key>', 'Content-Type': 'application/json'},
body: JSON.stringify({
title: 'Ship a CRM in an afternoon',
body: JSON.stringify('We replaced our lead spreadsheet with an app we built in an afternoon.'),
scheduled_at: '2026-09-16T09:30:00Z',
scheduled_timezone: 'Asia/Jerusalem',
hook: 'social_proof',
best_time_reason: 'Our audience checks LinkedIn before lunch.',
hashtags: ['buildinpublic', 'crm'],
image_url: 'https://cdn.example.com/posts/crm-launch-v2.png',
image_prompt: 'A freelancer closing a deal on a laptop, warm morning light'
})
};
fetch('https://app.base44.com/api/apps/{app_id}/social-calendar/posts/{post_id}', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://app.base44.com/api/apps/{app_id}/social-calendar/posts/{post_id}",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "PATCH",
CURLOPT_POSTFIELDS => json_encode([
'title' => 'Ship a CRM in an afternoon',
'body' => 'We replaced our lead spreadsheet with an app we built in an afternoon.',
'scheduled_at' => '2026-09-16T09:30:00Z',
'scheduled_timezone' => 'Asia/Jerusalem',
'hook' => 'social_proof',
'best_time_reason' => 'Our audience checks LinkedIn before lunch.',
'hashtags' => [
'buildinpublic',
'crm'
],
'image_url' => 'https://cdn.example.com/posts/crm-launch-v2.png',
'image_prompt' => 'A freelancer closing a deal on a laptop, warm morning light'
]),
CURLOPT_HTTPHEADER => [
"Content-Type: application/json",
"api_key: <api-key>"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://app.base44.com/api/apps/{app_id}/social-calendar/posts/{post_id}"
payload := strings.NewReader("{\n \"title\": \"Ship a CRM in an afternoon\",\n \"body\": \"We replaced our lead spreadsheet with an app we built in an afternoon.\",\n \"scheduled_at\": \"2026-09-16T09:30:00Z\",\n \"scheduled_timezone\": \"Asia/Jerusalem\",\n \"hook\": \"social_proof\",\n \"best_time_reason\": \"Our audience checks LinkedIn before lunch.\",\n \"hashtags\": [\n \"buildinpublic\",\n \"crm\"\n ],\n \"image_url\": \"https://cdn.example.com/posts/crm-launch-v2.png\",\n \"image_prompt\": \"A freelancer closing a deal on a laptop, warm morning light\"\n}")
req, _ := http.NewRequest("PATCH", url, payload)
req.Header.Add("api_key", "<api-key>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.patch("https://app.base44.com/api/apps/{app_id}/social-calendar/posts/{post_id}")
.header("api_key", "<api-key>")
.header("Content-Type", "application/json")
.body("{\n \"title\": \"Ship a CRM in an afternoon\",\n \"body\": \"We replaced our lead spreadsheet with an app we built in an afternoon.\",\n \"scheduled_at\": \"2026-09-16T09:30:00Z\",\n \"scheduled_timezone\": \"Asia/Jerusalem\",\n \"hook\": \"social_proof\",\n \"best_time_reason\": \"Our audience checks LinkedIn before lunch.\",\n \"hashtags\": [\n \"buildinpublic\",\n \"crm\"\n ],\n \"image_url\": \"https://cdn.example.com/posts/crm-launch-v2.png\",\n \"image_prompt\": \"A freelancer closing a deal on a laptop, warm morning light\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://app.base44.com/api/apps/{app_id}/social-calendar/posts/{post_id}")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Patch.new(url)
request["api_key"] = '<api-key>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"title\": \"Ship a CRM in an afternoon\",\n \"body\": \"We replaced our lead spreadsheet with an app we built in an afternoon.\",\n \"scheduled_at\": \"2026-09-16T09:30:00Z\",\n \"scheduled_timezone\": \"Asia/Jerusalem\",\n \"hook\": \"social_proof\",\n \"best_time_reason\": \"Our audience checks LinkedIn before lunch.\",\n \"hashtags\": [\n \"buildinpublic\",\n \"crm\"\n ],\n \"image_url\": \"https://cdn.example.com/posts/crm-launch-v2.png\",\n \"image_prompt\": \"A freelancer closing a deal on a laptop, warm morning light\"\n}"
response = http.request(request)
puts response.read_body{
"id": "6886b8d390dc7e2f4a2c91b3",
"app_id": "6820f3a4e7b91d003c45a1f2",
"plan_id": "8c1f9a2e-3b7d-4c5e-9f01-2a3b4c5d6e7f",
"source_post_id": "3f2504e0-4f89-11d3-9a0c-0305e82c3301",
"platform": "linkedin",
"title": "Ship a CRM in an afternoon",
"body": "We replaced our lead spreadsheet with an app we built in an afternoon. Here's what changed.",
"hook": "pain_point",
"cover_index": 0,
"scheduled_at": "2026-09-15T14:00:00",
"scheduled_local_at": "2026-09-15T17:00:00+03:00",
"scheduled_timezone": "Asia/Jerusalem",
"best_time_reason": "Weekday afternoons get the most engagement for this audience.",
"hashtags": [
"buildinpublic",
"crm"
],
"image_url": "https://cdn.example.com/posts/crm-launch.png",
"image_prompt": "A freelancer closing a deal on a laptop, warm morning light",
"status": "scheduled",
"workflow_id": "68a1c4f0d21b4e0a3c77e912"
}{
"detail": [
{
"loc": [
"<string>"
],
"msg": "<string>",
"type": "<string>"
}
]
}Authorizations
Personal API key.
Path Parameters
ID of the post, as returned by List scheduled posts.
^[0-9a-fA-F]{24}$ID of the app whose social calendar you want.
Body
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.
New title for the post. Omit it to keep the current one; an explicit null fails with a 422.
1 - 300"Ship a CRM in an afternoon"
New body text. Omit it to keep the current one; an explicit null fails with a 422.
50000"We replaced our lead spreadsheet with an app we built in an afternoon."
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.
"2026-09-16T09:30:00Z"
New IANA timezone for scheduled_local_at. It never moves the instant the post publishes. An explicit null fails with a 422.
64"Asia/Jerusalem"
New angle for the post. An explicit null fails with a 422.
500"social_proof"
New reason shown alongside the post's time. An explicit null fails with a 422.
1000"Our audience checks LinkedIn before lunch."
Replacement list of up to 30 hashtags, without the leading #. Send [] to publish none; an explicit null fails with a 422.
30100["buildinpublic", "crm"]
New HTTPS image URL, or null to remove the image. Removing it from an Instagram post means the post is rejected when it publishes.
2000"https://cdn.example.com/posts/crm-launch-v2.png"
New image prompt, or null to clear it.
2000"A freelancer closing a deal on a laptop, warm morning light"
Response
The post after the edit.
ID of the post. Pass it as post_id to the other social calendar endpoints.
"6886b8d390dc7e2f4a2c91b3"
ID of the app the post belongs to.
"6820f3a4e7b91d003c45a1f2"
ID of the content plan the post was generated from, or null for a post created through Create scheduled post.
"8c1f9a2e-3b7d-4c5e-9f01-2a3b4c5d6e7f"
ID this post has inside the content plan it came from, or null for a post created through the API.
"3f2504e0-4f89-11d3-9a0c-0305e82c3301"
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.
"linkedin"
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.
"Ship a CRM in an afternoon"
Body text of the post. Base44 publishes this followed by hashtags, so leave the tags out of it.
"We replaced our lead spreadsheet with an app we built in an afternoon. Here's what changed."
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.
"pain_point"
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.
0
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 returns carries +00:00. Read both as UTC.
"2026-09-15T14:00:00"
The same instant as scheduled_at, rendered in scheduled_timezone as an ISO 8601 timestamp. Display only.
"2026-09-15T17:00:00+03:00"
IANA timezone scheduled_local_at is rendered in. It never moves the instant the post publishes.
"Asia/Jerusalem"
Why this time was picked, written by the planner for a plan-generated post. Empty unless something set it.
"Weekday afternoons get the most engagement for this audience."
Hashtags published after body, without the leading #. A leading # you send is stripped before publishing.
["buildinpublic", "crm"]
HTTPS URL of the image published with the post, or null if it has none. An Instagram post needs one to publish.
"https://cdn.example.com/posts/crm-launch.png"
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.
"A freelancer closing a deal on a laptop, warm morning light"
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.
"scheduled"
ID of the automation that publishes this post, set once Start scheduling posts hands it over, and null before that. Its presence is what tells you the publish time is fixed.
"68a1c4f0d21b4e0a3c77e912"
Was this page helpful?