How to Schedule Posts via API
Schedule social media posts via API using timed publishing and queue-based scheduling. Code examples for both approaches with Postproxy.
Two ways to schedule posts via API
Most social media platforms do not expose scheduling through their APIs. You can publish immediately, but if you want a post to go out at a specific time, you have to build that yourself — a database, a worker, a timer, retry logic.
A publishing API like Postproxy handles scheduling natively. There are two approaches: timed publishing and queue-based scheduling. Which one to use depends on whether you control the exact time or want the system to manage timing for you.
Timed publishing with scheduled_at
Pass a scheduled_at timestamp when creating a post. Postproxy holds the post and publishes it at the specified time.
curl -X POST "https://api.postproxy.dev/api/posts" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "post": { "body": "Version 3.0 is live. Changelog on the blog.", "scheduled_at": "2026-04-05T14:00:00Z" }, "profiles": ["twitter", "linkedin", "threads"], "media": ["https://yourstorage.com/v3-release.png"] }'The post enters a scheduled state and publishes at exactly 2:00 PM UTC on April 5th. Until then, you can update or delete it.
In Python:
import requestsfrom datetime import datetime, timedelta
api_key = "your_postproxy_api_key"
# Schedule for tomorrow at 9 AM UTCpublish_time = (datetime.utcnow() + timedelta(days=1)).replace( hour=9, minute=0, second=0, microsecond=0)
response = requests.post( "https://api.postproxy.dev/api/posts", headers={ "Authorization": f"Bearer {api_key}", "Content-Type": "application/json", }, json={ "post": { "body": "We just shipped batch imports. Details in the docs.", "scheduled_at": publish_time.isoformat() + "Z", }, "profiles": ["twitter", "linkedin", "instagram"], },)
post = response.json()print(f"Scheduled post {post['id']} for {publish_time}")In Node.js:
const response = await fetch("https://api.postproxy.dev/api/posts", { method: "POST", headers: { Authorization: `Bearer ${process.env.POSTPROXY_API_KEY}`, "Content-Type": "application/json", }, body: JSON.stringify({ post: { body: "We just shipped batch imports. Details in the docs.", scheduled_at: "2026-04-05T14:00:00Z", }, profiles: ["twitter", "linkedin", "instagram"], }),});
const post = await response.json();console.log(`Scheduled post ${post.id}`);This approach works when you know the exact publish time — product launches, announcements, time-sensitive content.
Queue-based scheduling
When you do not care about exact timestamps and want a consistent posting cadence, queues are more practical. A queue has weekly timeslots — Monday at 9 AM, Wednesday at 2 PM, Friday at 10 AM — and posts are assigned to the next available slot automatically.
Create a queue
curl -X POST "https://api.postproxy.dev/api/post_queues" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "profile_group_id": "pg123", "post_queue": { "name": "Weekday Content", "timezone": "America/New_York", "jitter": 10, "queue_timeslots_attributes": [ { "day": 1, "time": "09:00" }, { "day": 3, "time": "14:00" }, { "day": 5, "time": "10:00" } ] } }'This creates a queue that publishes three times a week. The jitter parameter adds a random offset of up to 10 minutes in either direction, so posts do not go out at exactly the same time every week.
Add posts to the queue
curl -X POST "https://api.postproxy.dev/api/posts" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "post": { "body": "Three things we learned running our API at 10K requests per second." }, "profiles": ["twitter", "linkedin", "threads"], "queue_id": "q1abc", "queue_priority": "high" }'The post is assigned to the next available timeslot. Priority determines the order: high priority posts get earlier slots, low priority posts fill whatever is left. The default is medium.
When you add or remove posts, the queue rearranges all scheduled posts to maintain priority ordering. You do not need to manage slot assignments yourself.
Check the next available slot
curl -X GET "https://api.postproxy.dev/api/post_queues/q1abc/next_slot" \ -H "Authorization: Bearer YOUR_API_KEY"{ "next_slot": "2026-04-04T14:00:00Z"}This is useful when you want to show users in your app when their post will go out, or when deciding whether to use the queue or schedule directly.
Batch scheduling
If you have multiple posts to schedule — a week of content, a product launch sequence, a drip campaign — create them in a loop:
import requests
api_key = "your_postproxy_api_key"queue_id = "q1abc"
posts = [ {"body": "Day 1: We are launching something new next week.", "priority": "low"}, {"body": "Day 3: Here is what we have been building.", "priority": "medium"}, {"body": "Day 5: It is live. Link in bio.", "priority": "high"},]
for post in posts: response = requests.post( "https://api.postproxy.dev/api/posts", headers={ "Authorization": f"Bearer {api_key}", "Content-Type": "application/json", }, json={ "post": {"body": post["body"]}, "profiles": ["twitter", "linkedin", "threads"], "queue_id": queue_id, "queue_priority": post["priority"], }, ) result = response.json() print(f"Queued: {result['id']} at {result.get('scheduled_at')}")The queue assigns each post to the next available slot. The high-priority launch post gets the earliest remaining slot, even if it was added last.
Checking scheduled post status
After a scheduled post publishes, check per-platform results:
status = requests.get( f"https://api.postproxy.dev/api/posts/{post_id}", headers={"Authorization": f"Bearer {api_key}"},).json()
print(f"Post status: {status['status']}")for platform in status.get("platforms", []): print(f" {platform['platform']}: {platform['status']}")A post with status processed means publishing jobs were initiated. Individual platforms may still be published, failed, or processing. Check platform-level statuses for the actual outcome.
Pausing and resuming
Queues can be paused without losing posts:
curl -X PATCH "https://api.postproxy.dev/api/post_queues/q1abc" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "post_queue": { "enabled": false } }'While paused, no posts publish — even if their scheduled time passes. When you unpause the queue, all posts are rearranged into future timeslots. Nothing is lost or skipped.
This is useful during incidents, holidays, or when you need to hold content while waiting for approval.
When to use which approach
Timed (scheduled_at) | Queue-based | |
|---|---|---|
| Use when | You know the exact publish time | You want a consistent cadence |
| Control | Full control over timing | System assigns timeslots |
| Good for | Launches, announcements, time-sensitive content | Evergreen content, ongoing social presence |
| Batch workflow | Schedule each post with its own timestamp | Add posts to queue, timing is automatic |
| Rescheduling | Update scheduled_at manually | Change timeslots, queue rearranges all posts |
Both approaches can be combined. Use queues for your regular content cadence and scheduled_at for time-sensitive posts that need to go out at a specific moment.
Compared to building your own scheduler
Without a scheduling API, you need: a database to store pending posts, a worker process to check for due posts, retry logic for failures, and timezone handling. That is a scheduling system — and it has to be reliable, because a missed post is a missed post.
With scheduled_at, you offload all of that. One API call creates the post and sets the time. Postproxy handles the rest — the timer, the publishing, the per-platform error handling, the retries.
If you want to build your own scheduling layer on top — using cron, a task queue, or a workflow engine — that works too. The scheduled_at parameter and the queues API are there for when you would rather not.
Get your API key and start scheduling from Postproxy.
Postproxy
One API for every social platform
Publish to Instagram, X, LinkedIn, TikTok, YouTube and more with a single request. Free plan, no credit card required.