Get Started

How it works

Architecture behind scheduling and publishing

Every OpenPost feature is built around one promise: your post publishes on time, in the right format, every time. This page walks through the pipeline between “you clicked Schedule” and “your audience saw the post.” The details aren’t strictly required reading, but if you’re integrating, they help.

The lifecycle of a post

Every post in OpenPost moves through the same six states. You can watch the transitions in real-time under Posts, or subscribe to webhooks to trigger your own systems.

Post states
draft  →  scheduled  →  publishing  →  published

                           failed  →  canceled
  • draft— saved but no time chosen. Lives in the workspace indefinitely.
  • scheduled— a time slot is reserved. We’ll publish at that moment.
  • publishing— the moment arrived; we’re calling the platform’s API.
  • published — live on the platform. The post has a live_url now.
  • failed— something went wrong. Includes a reason and, when possible, a retry button.
  • canceled— you manually cancelled before publish.

The scheduler

OpenPost runs a minute-accurate scheduler on Postgres pg_cron. Every minute, the scheduler picks up every post whose schedule_at has passed and is still scheduled, claims it atomically, and moves it to publishing. This claim step uses a transactional update so duplicate workers can never race on the same post.

Why pg_cron and not a queue?

We evaluated BullMQ, Temporal, and Trigger.dev. All of them work, but they add a second database of truth. pg_cron runs in the same Postgres transaction as the post row, so “claimed” and “publishing” can never disagree. Simpler, fewer failure modes.

The publisher

Once a post is publishing, the platform-specific publisher takes over. Each of our eight channels has its own module that handles:

  • Format conversion— threads are split into per-tweet payloads, carousels into per-slide uploads, videos into the platform’s required spec.
  • Token refresh— if your OAuth token is expired, we refresh it transparently before the call.
  • Retry policy— three retries with exponential backoff on 5xx/network errors. 4xx errors fail fast (they won’t succeed on retry).
  • Result capture— live URL, provider post ID, and any warnings the platform returned.

What happens when things go wrong

OpenPost is designed to fail loudly rather than silently drop posts:

  • Token revoked — post fails with a channel_disconnected error. We email you, show a banner in the dashboard, and surface the failed post in the notification center.
  • Platform outage— retries complete; if still failing, the post moves to failedwith the platform’s error message attached. You can manually retry once the platform recovers.
  • Rate limited— we back off and retry within the platform’s window. No duplicate posts.

Delivery guarantees

Schedule accuracy

±30 seconds

At-least-once

No — exactly-once

Duplicate prevention

DB-level claim

Retry policy

3× exp. backoff on 5xx

Uptime target

99.9% monthly

Timezone handling

IANA, per-channel

Where your data lives

OpenPost runs on Supabase (Postgres 15) hosted in us-east-2. Your posts, media, and analytics never leave that region unless you request export. Media files are stored in an encrypted S3 bucket; pre-signed URLs are scoped to your workspace.

An EU region is on the roadmap for 2026. If EU residency is a hard requirement for you, get in touch— we can discuss a private deployment ahead of the public launch.

What you can observe

Every state change emits a webhook event if you’ve subscribed. Every publish writes an audit log entry visible under Settings → Audit log. Every API call returns an x-op-request-id header you can include when you contact support.

Last updated April 2026 Edit this page