PostMantis
Getting Started

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.

LayerStates
Post workflowdraft · pending · scheduled · completed · canceled
Delivery resultpending · published · failed
Mediapending · 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.

EndpointAccepted workflow state
POST /api/postsdraft or pending
POST /api/posts/{id}/publishpending

A fast worker can make the serialized response show scheduled, but the accepted non-draft state is still pending first.

Operational flow

  1. A user connects one or more social accounts in the dashboard.
  2. A dashboard action or API call creates a post and selects target profiles.
  3. Remote media URLs and direct uploads are normalized into PostMantis-owned assets before the post write is accepted.
  4. PostMantis stores the post and one pending delivery row per selected profile.
  5. A background workflow moves the post from pending to scheduled.
  6. If scheduled_at is in the future, the workflow waits until that time.
  7. PostMantis runs one background delivery task per selected profile.
  8. Each delivery settles as published or failed.
  9. 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

IntentRequestAccepted responseWhat happens next
Save a draft onlyPOST /api/posts with post.draft: truedraftStored only. No publish workflow starts yet.
Publish an existing draft nowPOST /api/posts/{id}/publish with empty bodypendingWorkflow advances to scheduled, then dispatch runs as soon as possible. Dashboard wording shows Queued.
Publish an existing draft laterPOST /api/posts/{id}/publish with top-level scheduled_atpendingWorkflow advances to scheduled, then waits until the future time. Dashboard wording shows Scheduled.
Create and publish nowPOST /api/posts without draft or post.scheduled_atpendingWorkflow advances to scheduled, then dispatch runs as soon as possible. Dashboard wording shows Queued.
Create and schedule for laterPOST /api/posts with future post.scheduled_atpendingWorkflow advances to scheduled, then waits until the future dispatch time.
Cancel a scheduled postPOST /api/posts/{id}/cancelcanceledOnly 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

StatusMeaning
pendingDelivery not finished yet
publishedDelivery succeeded
failedDelivery 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.

StatusMeaning
pendingThe media record has not yet inherited a later workflow state
processedThe post reached scheduled, completed, or canceled, so the media is treated as ready
failedThe 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.