Update Scheduled Post
Update the timing or status of an already-scheduled post using the PostPost API. This guide covers the complete workflow with error handling and edge cases.
Overview
You can modify a scheduled post before it publishes by:
- Rescheduling to a different time
- Pausing (converting to draft)
- Resuming a paused draft
Important: You can only update posts with status draft or scheduled. Posts that are published, failed, pending, or processing cannot be modified.
Prerequisites
- API Key: Get your key from the PostPost Dashboard
- Post Group ID: The ID returned when you created the post
- Post must be updatable: Status must be
draftorscheduled
API Reference
Endpoint:
PUT https://api.postpost.dev/api/v1/update-post/:postGroupIdHeaders:
Content-Type: application/json
x-api-key: YOUR_API_KEYRequest Body (at least one field required):
{
"status": "scheduled",
"scheduledTime": "2026-03-15T14:00:00.000Z"
}| Field | Type | Required | Description |
|---|---|---|---|
status | string | No* | "draft" or "scheduled" |
scheduledTime | string | No* | ISO 8601 UTC datetime (must be future) |
*At least one of status or scheduledTime must be provided.
Success Response (200):
{
"success": true,
"message": "Post updated successfully",
"postGroup": {
"_id": "507f1f77bcf86cd799439011",
"status": "scheduled",
"scheduledTime": "2026-03-15T14:00:00.000Z"
}
}Complete JavaScript Implementation
const PUBLORA_API_KEY = process.env.PUBLORA_API_KEY;
const BASE_URL = 'https://api.postpost.dev/api/v1';
/**
* Update a scheduled post before publication
* @param {string} postGroupId - The post group ID to update
* @param {Object} options - Update options
* @param {string} [options.scheduledTime] - New ISO 8601 UTC datetime
* @param {string} [options.status] - New status: 'draft' or 'scheduled'
* @returns {Promise<Object>} Updated post data
*/
async function updateScheduledPost(postGroupId, options = {}) {
// Validate inputs
if (!postGroupId) {
throw new Error('postGroupId is required');
}
if (!options.scheduledTime && !options.status) {
throw new Error('Either scheduledTime or status must be provided');
}
// Validate scheduledTime is in the future
if (options.scheduledTime) {
const scheduledDate = new Date(options.scheduledTime);
if (isNaN(scheduledDate.getTime())) {
throw new Error('Invalid scheduledTime format. Use ISO 8601: YYYY-MM-DDTHH:mm:ss.sssZ');
}
if (scheduledDate <= new Date()) {
throw new Error('scheduledTime must be in the future');
}
}
// Validate status
if (options.status && !['draft', 'scheduled'].includes(options.status)) {
throw new Error('status must be "draft" or "scheduled"');
}
// Build request body
const body = {};
if (options.scheduledTime) body.scheduledTime = options.scheduledTime;
if (options.status) body.status = options.status;
// Make API request
const response = await fetch(`${BASE_URL}/update-post/${postGroupId}`, {
method: 'PUT',
headers: {
'Content-Type': 'application/json',
'x-api-key': PUBLORA_API_KEY
},
body: JSON.stringify(body)
});
const data = await response.json();
// Handle errors
if (!response.ok) {
const error = new Error(data.error || `HTTP ${response.status}`);
error.status = response.status;
error.response = data;
switch (response.status) {
case 400:
if (data.error?.includes('past')) {
error.message = 'Cannot schedule in the past. Use a future datetime.';
} else if (data.error?.includes('status')) {
error.message = 'Post cannot be updated. It may be published, failed, or processing.';
}
break;
case 401:
error.message = 'Invalid API key. Check your x-api-key header.';
break;
case 404:
error.message = 'Post not found. It may have been deleted or belongs to another user.';
break;
}
throw error;
}
return data;
}
// ============ USAGE EXAMPLES ============
// Example 1: Reschedule to a new time
async function reschedulePost(postGroupId, newDateTime) {
try {
const result = await updateScheduledPost(postGroupId, {
scheduledTime: newDateTime
});
console.log('Post rescheduled:', result.postGroup.scheduledTime);
return result;
} catch (error) {
console.error('Failed to reschedule:', error.message);
throw error;
}
}
// Example 2: Pause a scheduled post (move to draft)
async function pausePost(postGroupId) {
try {
const result = await updateScheduledPost(postGroupId, {
status: 'draft'
});
console.log('Post paused (moved to draft)');
return result;
} catch (error) {
console.error('Failed to pause:', error.message);
throw error;
}
}
// Example 3: Resume a draft with new schedule
async function resumePost(postGroupId, scheduledTime) {
try {
const result = await updateScheduledPost(postGroupId, {
status: 'scheduled',
scheduledTime: scheduledTime
});
console.log('Post scheduled for:', result.postGroup.scheduledTime);
return result;
} catch (error) {
console.error('Failed to resume:', error.message);
throw error;
}
}
// Example 4: Schedule for tomorrow at 9am UTC
function getTomorrowAt9AM() {
const tomorrow = new Date();
tomorrow.setDate(tomorrow.getDate() + 1);
tomorrow.setUTCHours(9, 0, 0, 0);
return tomorrow.toISOString();
}
// Run examples
const postGroupId = '507f1f77bcf86cd799439011';
await reschedulePost(postGroupId, '2026-03-20T14:00:00.000Z');
await pausePost(postGroupId);
await resumePost(postGroupId, getTomorrowAt9AM());Complete Python Implementation
import os
import requests
from datetime import datetime, timezone, timedelta
from typing import Optional
PUBLORA_API_KEY = os.environ.get('PUBLORA_API_KEY')
BASE_URL = 'https://api.postpost.dev/api/v1'
class PostPostError(Exception):
"""Custom exception for PostPost API errors."""
def __init__(self, message: str, status_code: int = None, response: dict = None):
super().__init__(message)
self.status_code = status_code
self.response = response
def update_scheduled_post(
post_group_id: str,
scheduled_time: Optional[str] = None,
status: Optional[str] = None
) -> dict:
"""
Update a scheduled post before publication.
Args:
post_group_id: The post group ID to update
scheduled_time: New ISO 8601 UTC datetime (e.g., '2026-03-15T14:00:00.000Z')
status: New status - 'draft' or 'scheduled'
Returns:
dict: Updated post data with success status
Raises:
PostPostError: If the API request fails
ValueError: If inputs are invalid
"""
# Validate inputs
if not post_group_id:
raise ValueError('post_group_id is required')
if not scheduled_time and not status:
raise ValueError('Either scheduled_time or status must be provided')
# Validate scheduled_time is in the future
if scheduled_time:
try:
scheduled_dt = datetime.fromisoformat(scheduled_time.replace('Z', '+00:00'))
if scheduled_dt <= datetime.now(timezone.utc):
raise ValueError('scheduled_time must be in the future')
except ValueError as e:
if 'future' in str(e):
raise
raise ValueError('Invalid scheduled_time format. Use ISO 8601: YYYY-MM-DDTHH:mm:ss.sssZ')
# Validate status
if status and status not in ['draft', 'scheduled']:
raise ValueError('status must be "draft" or "scheduled"')
# Build request body
body = {}
if scheduled_time:
body['scheduledTime'] = scheduled_time
if status:
body['status'] = status
# Make API request
response = requests.put(
f'{BASE_URL}/update-post/{post_group_id}',
headers={
'Content-Type': 'application/json',
'x-api-key': PUBLORA_API_KEY
},
json=body
)
data = response.json()
# Handle errors
if not response.ok:
error_message = data.get('error', f'HTTP {response.status_code}')
if response.status_code == 400:
if 'past' in error_message.lower():
error_message = 'Cannot schedule in the past. Use a future datetime.'
elif 'status' in error_message.lower():
error_message = 'Post cannot be updated. It may be published, failed, or processing.'
elif response.status_code == 401:
error_message = 'Invalid API key. Check your x-api-key header.'
elif response.status_code == 404:
error_message = 'Post not found. It may have been deleted or belongs to another user.'
raise PostPostError(error_message, response.status_code, data)
return data
# ============ USAGE EXAMPLES ============
def reschedule_post(post_group_id: str, new_datetime: str) -> dict:
"""Reschedule a post to a new time."""
try:
result = update_scheduled_post(post_group_id, scheduled_time=new_datetime)
print(f"Post rescheduled: {result['postGroup']['scheduledTime']}")
return result
except (PostPostError, ValueError) as e:
print(f"Failed to reschedule: {e}")
raise
def pause_post(post_group_id: str) -> dict:
"""Pause a scheduled post by moving it to draft."""
try:
result = update_scheduled_post(post_group_id, status='draft')
print("Post paused (moved to draft)")
return result
except (PostPostError, ValueError) as e:
print(f"Failed to pause: {e}")
raise
def resume_post(post_group_id: str, scheduled_time: str) -> dict:
"""Resume a draft post with a new schedule."""
try:
result = update_scheduled_post(
post_group_id,
status='scheduled',
scheduled_time=scheduled_time
)
print(f"Post scheduled for: {result['postGroup']['scheduledTime']}")
return result
except (PostPostError, ValueError) as e:
print(f"Failed to resume: {e}")
raise
def get_tomorrow_at_9am() -> str:
"""Get ISO 8601 string for tomorrow at 9am UTC."""
tomorrow = datetime.now(timezone.utc) + timedelta(days=1)
scheduled = tomorrow.replace(hour=9, minute=0, second=0, microsecond=0)
return scheduled.strftime('%Y-%m-%dT%H:%M:%S.000Z')
# Run examples
if __name__ == '__main__':
post_group_id = '507f1f77bcf86cd799439011'
reschedule_post(post_group_id, '2026-03-20T14:00:00.000Z')
pause_post(post_group_id)
resume_post(post_group_id, get_tomorrow_at_9am())cURL Examples
Reschedule a post
curl -X PUT "https://api.postpost.dev/api/v1/update-post/507f1f77bcf86cd799439011" \
-H "Content-Type: application/json" \
-H "x-api-key: YOUR_API_KEY" \
-d '{"scheduledTime": "2026-03-15T14:00:00.000Z"}'Pause a post (move to draft)
curl -X PUT "https://api.postpost.dev/api/v1/update-post/507f1f77bcf86cd799439011" \
-H "Content-Type: application/json" \
-H "x-api-key: YOUR_API_KEY" \
-d '{"status": "draft"}'Resume with new schedule
curl -X PUT "https://api.postpost.dev/api/v1/update-post/507f1f77bcf86cd799439011" \
-H "Content-Type: application/json" \
-H "x-api-key: YOUR_API_KEY" \
-d '{"status": "scheduled", "scheduledTime": "2026-03-15T14:00:00.000Z"}'Edge Cases and Error Handling
Posts That Cannot Be Updated
| Status | Can Update? | Reason |
|---|---|---|
draft | Yes | Not yet scheduled |
scheduled | Yes | Waiting for publication time |
pending | No | Being processed by scheduler |
processing | No | Currently publishing |
published | No | Already live on platform |
failed | No | Publication failed |
Common Errors
| Error | Cause | Solution |
|---|---|---|
"Scheduled time cannot be in the past" | DateTime is before current time | Use a future datetime |
"Cannot update post: post is currently in published status" | Post already published | Cannot modify published posts |
"Post group not found" | Invalid ID or wrong user | Verify postGroupId and API key |
"Invalid API key" | Bad x-api-key header | Check API key in dashboard |
"Invalid scheduled time format" | Malformed datetime | Use ISO 8601: YYYY-MM-DDTHH:mm:ss.sssZ |
Checking Post Status Before Update
async function canUpdatePost(postGroupId) {
const response = await fetch(
`https://api.postpost.dev/api/v1/get-post/${postGroupId}`,
{ headers: { 'x-api-key': PUBLORA_API_KEY } }
);
const data = await response.json();
const status = data.posts?.[0]?.status;
return ['draft', 'scheduled'].includes(status);
}
// Usage
if (await canUpdatePost(postGroupId)) {
await updateScheduledPost(postGroupId, { scheduledTime: newTime });
} else {
console.log('Post cannot be updated - already published or processing');
}Complete Workflow: Create Draft and Schedule Later
// Step 1: Create a draft post
const createResponse = await fetch('https://api.postpost.dev/api/v1/create-post', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'x-api-key': 'YOUR_API_KEY'
},
body: JSON.stringify({
content: 'My post content here',
platforms: ['linkedin-ABC123', 'twitter-XYZ789']
// No scheduledTime = creates as draft
})
});
const { postGroupId } = await createResponse.json();
console.log('Draft created:', postGroupId);
// Step 2: Later, schedule the draft
const updateResponse = await fetch(
`https://api.postpost.dev/api/v1/update-post/${postGroupId}`,
{
method: 'PUT',
headers: {
'Content-Type': 'application/json',
'x-api-key': 'YOUR_API_KEY'
},
body: JSON.stringify({
status: 'scheduled',
scheduledTime: '2026-03-15T14:00:00.000Z'
})
}
);
const result = await updateResponse.json();
console.log('Post scheduled for:', result.postGroup.scheduledTime);Related Guides
- Create Post - Create new posts
- Get Post - Check post status
- Delete Post - Remove posts
- Scheduling Guide - Scheduling best practices