Blog/API Guides

Scheduling posts across 7 platforms: rate limits, timezones, and queuing

May 15, 2026·12 min readAPI Guides

A deep dive into the platform-specific rate limits, timezone edge cases, and queue architecture you need to understand before shipping a multi-platform scheduling feature.

Every social platform has different rate limits, different rules about what a "post" is, and different behavior around scheduling. Before you build a scheduling feature, here's what you need to know.

Timezone-aware scheduling

The most common scheduling bug: storing "9am" as a local time string and converting it to UTC at storage time. When your server is in UTC and your user is in PST, "9am PST" stored without the offset becomes "9am UTC" — which is 1am on the west coast.

Always pass ISO 8601 timestamps with explicit UTC offsets. Aether stores the absolute UTC moment and never reinterprets it — daylight saving transitions don't affect scheduled posts.

// The scheduledFor field accepts any ISO 8601 datetime with offset
const post = await aether.posts.create({
  profileIds: ["ig_abc", "tiktok_xyz", "li_123"],
  text: "Consistent posting, handled automatically.",
  // 9am Chicago time — Aether converts to UTC internally
  scheduledFor: "2026-06-15T09:00:00-05:00",
});

// To schedule at a specific UTC time instead:
const postUtc = await aether.posts.create({
  profileIds: ["ig_abc"],
  text: "UTC-anchored post",
  scheduledFor: "2026-06-15T14:00:00Z", // 14:00 UTC = 09:00 EST, 06:00 PST

Bulk scheduling with CSV

For content calendars and agencies managing hundreds of posts, the bulk CSV endpoint lets you schedule an entire month in one request. The CSV format is minimal: text, profileIds (comma-separated), scheduledFor, and optional mediaUrls.

// POST /v1/posts/bulk with multipart/form-data
// CSV format: text, profileIds (comma-separated), scheduledFor, mediaUrls (optional)
text,profileIds,scheduledFor
"Monday motivation 💪","ig_abc,li_123","2026-06-16T13:00:00Z"
"Product update","tiktok_xyz","2026-06-17T15:00:00Z"
"Behind the scenes","ig_abc","2026-06-18T11:00:00Z"

// Or via SDK:
const result = await aether.posts.bulkCreate({ csv: csvFileBuffer });
console.log(result.created);  // 3
console.log(result.failed);   // 0

Platform rate limits

Rate limits are enforced by each platform individually, not by Aether. Aether queues your posts and automatically retries on rate limit errors, but understanding the limits helps you design your scheduling windows.

// Platform rate limits (approximate, subject to platform changes)
// Instagram:  25 posts/day per account, 200 API calls/hour
// TikTok:     No hard daily limit, but 15-min cooldown per account recommended
// Facebook:   200 posts/day per page
// LinkedIn:   150 API calls/day per token (use sparingly)
// YouTube:    6 uploads/day per channel (quota-based)
// Threads:    250 posts/day per account
// Reddit:     10 posts/hour per account, 6-minute post interval recommended

// Aether automatically queues and retries on rate limit errors (429)
// Failed posts emit a post.failed webhook with the platform error code

Queue architecture

Aether uses BullMQ (Redis-backed) to process scheduled posts. When you create a post with scheduledFor, a delayed job is created in Redis with a TTL equal to the scheduled time. At the scheduled moment, the worker picks it up, calls the platform API, and dispatches webhooks.

  • Posts are processed within 1–3 seconds of their scheduled time under normal load
  • Failed publishes retry with exponential backoff (5 attempts max, then post.failed webhook)
  • OAuth tokens are proactively refreshed 24 hours before expiry by a separate token-refresh worker
  • You can cancel a scheduled post at any time while its status is scheduled

Cross-platform content strategy

Don't publish identical text to every platform — each platform has different norms. Use the overrides field to customize copy, hashtags, and media per platform while keeping a single API call.