Post Lifecycle
How PostMantis moves a post from acceptance to scheduling, delivery, and completion.
PostMantis keeps the public workflow small on purpose. Post status, delivery status, and media status are separate, so each state keeps one meaning.
Lifecycle overview
Draft --publish--> Pending --workflow advances--> Scheduled --all deliveries settle--> Completed
Scheduled --cancel while every delivery is still pending--> Canceled
Non-draft create requests start at Pending.What the write endpoints actually accept into
Non-draft writes enter pending first. The server then reads the post back before
responding, so a very fast worker may already advance that serialized response to
scheduled. That is a timing race, not a different acceptance rule.
Three status layers
Post workflow, delivery results, and media use separate status models so failures land on the right layer.
| Layer | States |
|---|---|
| Post workflow | draft · pending · scheduled · completed · canceled |
| Delivery result | pending · published · failed |
| Media | pending · processed · failed |
All three layers can be pending at the same time on one response:
{
"status": "pending",
"media": [{ "status": "pending", "asset_id": "8f5f3f18-3cf7-4aa8-a0ea-6fd204d4c4f1" }],
"deliveries": [{ "provider": "x", "status": "pending" }]
}- Post
pending→ the write was accepted and the workflow has not advanced further yet - Media
pending→ the stored media record has not yet inherited a later workflow state - Delivery
pending→ provider delivery has not finished yet
Acceptance commands
Create and publish endpoints are acceptance commands. They return non-terminal workflow state. Terminal outcomes appear only when you read the post later.
| Endpoint | Accepted workflow state |
|---|---|
POST /api/posts | draft or pending |
POST /api/posts/{id}/publish | pending |
A fast worker can make the serialized response show scheduled, but the accepted non-draft state is still pending first.
Operational flow
- A user connects one or more social accounts in the dashboard.
- A dashboard action or API call creates a post and selects target profiles.
- Remote media URLs and direct uploads are normalized into PostMantis-owned assets before the post write is accepted.
- PostMantis stores the post and one pending delivery row per selected profile.
- A background workflow moves the post from
pendingtoscheduled. - If
scheduled_atis in the future, the workflow waits until that time. - PostMantis runs one background delivery task per selected profile.
- Each delivery settles as
publishedorfailed. - Once every delivery is settled, PostMantis marks the post
completed.
Why the workflow is async
PostMantis separates request acceptance from provider delivery. That keeps the public API stable, makes scheduling explicit, and lets per-provider work be tracked durably instead of pretending a publish request finished inside one HTTP response.
Use the flow that matches your intent
| Intent | Request | Accepted response | What happens next |
|---|---|---|---|
| Save a draft only | POST /api/posts with post.draft: true | draft | Stored only. No publish workflow starts yet. |
| Publish an existing draft now | POST /api/posts/{id}/publish with empty body | pending | Workflow advances to scheduled, then dispatch runs as soon as possible. Dashboard wording shows Queued. |
| Publish an existing draft later | POST /api/posts/{id}/publish with top-level scheduled_at | pending | Workflow advances to scheduled, then waits until the future time. Dashboard wording shows Scheduled. |
| Create and publish now | POST /api/posts without draft or post.scheduled_at | pending | Workflow advances to scheduled, then dispatch runs as soon as possible. Dashboard wording shows Queued. |
| Create and schedule for later | POST /api/posts with future post.scheduled_at | pending | Workflow advances to scheduled, then waits until the future dispatch time. |
| Cancel a scheduled post | POST /api/posts/{id}/cancel | canceled | Only works after the post reached scheduled and while every delivery is still pending. |
One rule to remember
pending means the write was accepted and is now in the workflow.
scheduled means the workflow already advanced the post and it is dispatchable or
waiting on a future time gate. If there is no future scheduled_at, the dashboard
labels that scheduled state as Queued.
To inspect the real outcome, read the post later, check the dashboard Publishing Log, or check Publishing health.
Post states
Draft
Stored but not submitted for delivery. Created with post.draft: true. Drafts cannot include scheduled_at. Leave draft mode with POST /api/posts/{id}/publish.
{ "status": "draft", "scheduled_at": null }Pending
The write was accepted and the workflow has not advanced yet. pending is in-progress only. It never means failure.
{
"status": "pending",
"media": [{ "status": "pending", "asset_id": "8f5f3f18-3cf7-4aa8-a0ea-6fd204d4c4f1" }]
}For URL-based inputs, remote media has already been imported into PostMantis-owned storage before this response is returned.
Scheduled
The workflow advanced beyond acceptance. The post is now ready for dispatch, or waiting for its future scheduled_at.
{ "status": "scheduled", "scheduled_at": "2026-03-27T10:30:00Z" }If scheduled_at is in the future, the workflow waits for that time. If scheduled_at is null or in the past, the post dispatches as soon as the delivery worker picks it up.
Why you may see scheduled right after a write
The workflow transitions non-draft posts from pending to scheduled in
the background. Because the server reads the post again before returning the response, a fast
worker can make that first response already show scheduled.
Completed
Workflow orchestration finished.
{
"status": "completed",
"deliveries": [
{ "provider": "x", "status": "published" },
{ "provider": "youtube", "status": "failed" }
]
}completed ≠ fully published
completed means workflow orchestration finished. Inspect deliveries[]
for the true delivery results.
Canceled
Canceled before any delivery left pending. The public contract supports canceling a scheduled post, not deleting already-published provider content.
{ "status": "canceled", "canceled_at": "2026-03-26T11:22:00Z" }Delivery result states
| Status | Meaning |
|---|---|
pending | Delivery not finished yet |
published | Delivery succeeded |
failed | Delivery ended unsuccessfully |
A post can finish with mixed results across providers. That is why post workflow state and delivery result state are modeled separately.
Publish retry behavior
PostMantis retries delivery work automatically when the delivery task execution itself throws and the durable worker treats that run as retryable.
Current delivery task policy:
- up to 3 total attempts per delivery task
- retry strategy: fixed delay
- delay between retries: 60 seconds
Most provider-level publish failures are handled differently. If provider code returns a user-facing failure result, the delivery is finalized as failed without another automatic attempt.
This retry policy applies to the background delivery task, not to the initial POST /api/posts or POST /api/posts/{id}/publish response. Those endpoints remain acceptance commands and return before terminal delivery outcomes exist.
Retry attempts are runtime-level execution details, not first-class delivery events. The Publishing Log shows queue/schedule, published, failed, and manual retry domain events. It does not show every internal worker retry attempt as a separate row.
Media states
Media status is intentionally coarse. Use post status, delivery status, and the Publishing Log as the main source of truth for where a publish is right now.
| Status | Meaning |
|---|---|
pending | The media record has not yet inherited a later workflow state |
processed | The post reached scheduled, completed, or canceled, so the media is treated as ready |
failed | The stored media record explicitly carries a failed status |
If a stored media record already carries failure details, the post read exposes them:
{
"status": "completed",
"media": [
{
"status": "failed",
"asset_id": "8f5f3f18-3cf7-4aa8-a0ea-6fd204d4c4f1",
"error_message": "Media could not be prepared for publishing."
}
]
}Why this matters for automation
Automation reliability
Write endpoints are acceptance commands. Polling is predictable. Reads and dashboard logs map to real state transitions. Partial success is observable, because provider failures stay attached to the right delivery result.
Provider review summary
PostMantis is built for publishing to owned or authorized social accounts connected by the user in the dashboard. It is not a consumer feed reader or a bulk account-provisioning surface. The dashboard is the control plane for connections and credentials, while the API is the runtime surface for content submission and delivery reads.