Social Media API Bulk Posting Guide (2026)
Posting to dozens of clients across multiple platforms every day is painful when you're doing it manually. Here's how agencies automate bulk posting with the OmniSocials API.

If you're running social media for more than two or three clients, manual posting stops working fast. Clicking through dashboards, copy-pasting captions, switching between accounts. It adds up to hours every week that shouldn't exist.
On this page
- What Is Social Media API Bulk Posting?
- Why Native Platform APIs Don't Scale for Bulk Operations
- How to Bulk Post to Social Media via API
- Step 1: Build Your Posts Array
- Step 2: Send the Posts in a Loop
- Step 3: Python Version
- Step 4: Handle Responses and Errors
- Bulk Posting with Media Uploads
- Building an Agency Bulk Posting Pipeline
- API Comparison: Bulk Posting Across Providers
- Frequently Asked Questions
- Sources
Social media API bulk posting is how agencies solve this. One script. Hundreds of posts. Every platform covered.
This guide shows you exactly how to do it with the OmniSocials API, including working code examples you can drop into your own scripts today.
What Is Social Media API Bulk Posting?
Social media API bulk posting is the process of creating many social media posts programmatically, from a script or pipeline, rather than one at a time in a dashboard. Agencies use it to schedule weeks of content for multiple clients in minutes, without touching a dashboard.
The alternative, using native platform APIs directly, is painful. Instagram's Graph API requires separate OAuth tokens per user, Facebook has its own approval review process, LinkedIn enforces strict rate limits, and none of them share a common schema. Building a bulk posting system on top of raw platform APIs means maintaining integrations with 13 different systems, each with its own quirks and breaking changes.
OmniSocials solves this with a single unified API. Connect your accounts once in the dashboard, get one API key, and you're posting everywhere.
Why Native Platform APIs Don't Scale for Bulk Operations
Here's what bulk posting looks like if you try to build it yourself on native platform APIs:
| Task | Native APIs | OmniSocials API |
|---|---|---|
| Task: OAuth setup | Native APIs: Separate OAuth flow per platform | OmniSocials API: One API key, done |
| Task: Post to 5 platforms | Native APIs: 5 separate API calls with different schemas | OmniSocials API: 1 request, accounts array |
| Task: Schedule a post | Native APIs: Platform-specific scheduling (Instagram: published_time, LinkedIn: specificContent) | OmniSocials API: schedule_at field, same for all |
| Task: Handle media | Native APIs: Upload to each platform separately, get different media IDs | OmniSocials API: Upload once to OmniSocials, it handles the rest |
| Task: Bulk 50 posts | Native APIs: 250 API calls (50 posts on 5 platforms), multiple auth tokens | OmniSocials API: 50 requests to POST /v1/posts from one loop, one key per workspace |
| Task: Get status | Native APIs: Poll 5 different APIs | OmniSocials API: Single GET /v1/posts/:id |
I've worked with agencies that had custom scripts hitting native APIs directly. Every platform update broke something. With OmniSocials, that maintenance burden disappears.
How to Bulk Post to Social Media via API
You'll need an OmniSocials account with your social accounts connected, and your API key from Settings > API. The 14-day free trial gives you full API access.
Step 1: Build Your Posts Array
Each post in the array follows the POST /v1/posts schema: content, media_urls (optional, public image or video URLs), accounts, and schedule_at (optional: leave it out and the post is saved as a draft, it does not publish).
An API key belongs to one workspace, and a workspace holds one account per platform, so an agency gives each client its own workspace and API key. Tag each post with the client it belongs to:
const clientKeys = {
clientA: process.env.OMNISOCIALS_KEY_CLIENT_A, // omsk_live_...
clientB: process.env.OMNISOCIALS_KEY_CLIENT_B,
};
const posts = [
{
client: "clientA",
content: "Client A, Monday post: New product launch! 🚀",
media_urls: ["https://cdn.yoursite.com/client-a/product-launch.jpg"],
accounts: ["instagram", "facebook", "linkedin"],
schedule_at: "2027-03-01T09:00:00Z"
},
{
client: "clientA",
content: "Client A, Wednesday post: Behind the scenes.",
media_urls: ["https://cdn.yoursite.com/client-a/behind-the-scenes.jpg"],
accounts: ["instagram", "threads"],
schedule_at: "2027-03-03T11:00:00Z"
},
{
client: "clientB",
content: "Client B, Monday post: Tips for Q2 planning.",
accounts: ["linkedin", "bluesky"],
schedule_at: "2027-03-01T08:00:00Z"
}
];
You can mix clients, platforms, and schedules in a single array. Your script picks the right key per post.
Step 2: Send the Posts in a Loop
There is no bulk endpoint. Each POST /v1/posts request creates one post (for as many platforms as you list), so the script loops over the array. The rate limit is 100 requests per minute per API key: pace the loop, and on a 429 wait for the Retry-After seconds before trying again.
const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
async function createPost(apiKey, post) {
while (true) {
const res = await fetch('https://api.omnisocials.com/v1/posts', {
method: 'POST',
headers: {
'Authorization': `Bearer ${apiKey}`,
'Content-Type': 'application/json',
},
body: JSON.stringify(post),
});
if (res.status === 429) {
await sleep(Number(res.headers.get('Retry-After') || 1) * 1000);
continue;
}
const body = await res.json();
return res.ok ? { data: body.data } : { error: body.error };
}
}
const results = [];
for (const { client, ...post } of posts) {
results.push(await createPost(clientKeys[client], post));
await sleep(700); // about 85 requests a minute, under the limit
}
That loop creates 3 posts on 7 platform/account combinations with 3 requests. With native APIs, that's 7 separate calls with different auth headers and schemas.
Step 3: Python Version
import os
import time
import requests
client_keys = {
"client_a": os.environ["OMNISOCIALS_KEY_CLIENT_A"],
"client_b": os.environ["OMNISOCIALS_KEY_CLIENT_B"],
}
posts = [
{
"client": "client_a",
"content": "Client A, Monday post: New product launch!",
"media_urls": ["https://cdn.yoursite.com/client-a/product-launch.jpg"],
"accounts": ["instagram", "facebook", "linkedin"],
"schedule_at": "2027-03-01T09:00:00Z"
},
{
"client": "client_b",
"content": "Client B, Tips for Q2 planning.",
"accounts": ["linkedin", "bluesky"],
"schedule_at": "2027-03-01T08:00:00Z"
}
]
def create_post(api_key, post):
while True:
response = requests.post(
"https://api.omnisocials.com/v1/posts",
headers={"Authorization": f"Bearer {api_key}"},
json=post,
)
if response.status_code == 429:
time.sleep(int(response.headers.get("Retry-After", 1)))
continue
body = response.json()
return body.get("data"), body.get("error")
for item in posts:
post = {key: value for key, value in item.items() if key != "client"}
data, error = create_post(client_keys[item["client"]], post)
if error:
print(f"Failed: {error['code']}: {error['message']}")
else:
print(f"Post {data['id']}: {data['status']}")
time.sleep(0.7) # stays under 100 requests per minute
Step 4: Handle Responses and Errors
Each request returns HTTP 201 with the created post in data (its id and status, scheduled when you sent schedule_at), or a 4xx with { "error": { "code", "message" } }, for example 400 validation_error for a schedule_at in the past or 400 platform_not_connected for a platform the workspace hasn't connected. The results array from Step 2 keeps your input order:
results.forEach((result, index) => {
if (result.error) {
console.error(`Post ${index} failed: ${result.error.code}: ${result.error.message}`);
} else {
console.log(`Post ${index} ${result.data.status}: ${result.data.id}`);
}
});
Set up webhooks to get notified when posts publish or fail. Polling hundreds of post IDs isn't practical at scale. Create one with POST /v1/webhooks; it can subscribe to post.scheduled, post.published, post.failed, post.approved, and post.rejected, and each delivery lists the per-platform results in data.targets.
Bulk Posting with Media Uploads
If your images already have a public URL, pass it in media_urls and OmniSocials downloads it. If you're generating images dynamically (client reports, data visualizations, product shots), upload them first via /v1/media/upload, then reference the returned media ID in the media field of your posts.
import { readFile } from 'node:fs/promises';
import { basename } from 'node:path';
// Upload media first (multipart field "file")
async function uploadMedia(apiKey, filePath) {
const formData = new FormData();
const file = new Blob([await readFile(filePath)], { type: 'image/png' });
formData.append('file', file, basename(filePath));
const res = await fetch('https://api.omnisocials.com/v1/media/upload', {
method: 'POST',
headers: { 'Authorization': `Bearer ${apiKey}` },
body: formData,
});
const { data } = await res.json();
return data.id; // Media ID for the `media` field
}
// Then use it in your posts
const mediaId = await uploadMedia(clientKeys.clientA, './client-report-week14.png');
const posts = [
{
client: "clientA",
content: "Weekly performance report, week 14.",
media: [mediaId],
accounts: ["linkedin"],
schedule_at: "2027-03-01T08:00:00Z"
}
];
Upload with the same client's key you post with: media lives in that workspace's library.
OmniSocials resizes and reformats uploaded media per each platform's requirements. You upload once; it handles Instagram's 1:1 crop, LinkedIn's aspect ratio requirements, and Twitter's compression separately.
Building an Agency Bulk Posting Pipeline
Here's a pattern I've seen work well for agencies managing 10+ clients:
- Maintain a content calendar in a spreadsheet or CMS. Rows contain: client ID, copy, platform list, scheduled date, image path
- Run a script weekly that reads the calendar, uploads any new images, and loops over the full week's posts with one
POST /v1/postsper post, using each client's API key - Use webhooks to log results: write published/failed status back to your CMS or Slack
- Query
/v1/analytics/overviewwith each client's key at the end of each month to pull engagement data per client
This reduces content scheduling from hours of dashboard work to a single script execution. The rate limit is 100 requests per minute per API key, and each request creates one post for several platforms, so a week of posts for a client goes out in a minute or two.
API Comparison: Bulk Posting Across Providers
Prices checked October 18, 2026, on each vendor's pricing page.
| Feature | OmniSocials API | Ayrshare | Buffer API | Publer API |
|---|---|---|---|---|
| Feature: Price (billed yearly) | OmniSocials API: $10 per seat, API included | Ayrshare: Premium $129/mo ($149 billed monthly) | Buffer API: $5 per channel (Essentials) | Publer API: Business plan, from $8 per account |
| Feature: Pricing unit | OmniSocials API: Seat (one per brand or extra teammate) | Ayrshare: Social profile | Buffer API: Channel | Publer API: Social account |
| Feature: Platforms | OmniSocials API: 13 | Ayrshare: 14, no Mastodon | Buffer API: 12 | Publer API: 12, plus WordPress |
| Feature: Multi-platform per post | OmniSocials API: Yes (accounts array) | Ayrshare: Yes | Buffer API: Yes | Publer API: Yes |
| Feature: Hosted MCP server | OmniSocials API: Yes, 56 tools | Ayrshare: Yes, 33 tools | Buffer API: Yes | Publer API: Not checked |
OmniSocials has no bulk endpoint either: scheduling 200 posts means 200 requests, which one loop sends in a little over two minutes at 100 requests per minute. What saves calls is that each request can target several platforms at once.
Frequently Asked Questions
What is social media API bulk posting?
Social media API bulk posting is the process of creating many social media posts programmatically, from a script or pipeline, rather than one at a time in a dashboard. Agencies use it to schedule weeks of content for multiple clients in minutes, without touching a dashboard.
Can I post to multiple platforms at once with an API?
Yes. The OmniSocials API accepts an accounts array in each post request, letting you publish to Instagram, LinkedIn, Facebook, TikTok, and 8 other platforms in one call. There is no bulk endpoint: for bulk operations, send one POST /v1/posts request per post from a loop.
How many posts can I bulk schedule at once?
Each OmniSocials API request creates one post, which can target several platforms at once. The rate limit is 100 requests per minute per API key, so one key can schedule up to 100 posts a minute, enough for most agency workflows.
Is there a free way to test social media bulk posting via API?
OmniSocials offers a 14-day free trial. The API is included in every plan. There's no separate developer tier. You get full API access from day one. There are no test keys, so test with drafts: leave out schedule_at and a post is saved as a draft that never publishes on its own.
What's the difference between bulk posting and normal API posting?
With OmniSocials there is no separate bulk endpoint: bulk posting is normal API posting run from a loop. Each POST /v1/posts request creates one post for one or more platforms, and a script sends as many as you need while staying under 100 requests per minute.
If you're building an agency workflow or automating content at scale, the full API reference is at docs.omnisocials.com. The 14-day trial gives you a real API key and full API access from the start.
Sources
- Meta Graph API Documentation: Official reference for Facebook and Instagram's native API, demonstrating the OAuth complexity OmniSocials abstracts away
- LinkedIn Marketing API Docs: LinkedIn's developer documentation showing platform-specific rate limits and post schema requirements
- Sprout Social 2025 Index: Industry data on social media management time savings and agency workflows
- OmniSocials API Docs: Full reference for all OmniSocials API endpoints, including posts, media, and webhooks
Try OmniSocials for 14 days
Plan, schedule and answer on 13 platforms from one calendar, or let your AI agent do it. The first charge comes when the trial ends.


