---
title: "Async publishing and job lifecycle"
description: "How Dravo queues, delivers and reports publish jobs, including scheduling, statuses and idempotency."
section: "Core concepts"
url: https://dravo.dev/docs/concepts/async-publishing
---
# Async publishing and job lifecycle

## Why publishing is async

Posting to a social platform can take seconds (video processing, retries on
transient failures). So `POST /v1/publish` does not wait. It validates your
request, enqueues a job, and returns `202 Accepted` with a `job_id`. Delivery
happens in the background and the result is recorded per account.

## The job lifecycle

```text
POST /v1/publish
      |
      v
  [queued] --> [processing] --> [published]   (all accounts ok)
                            \--> [partial]     (some ok, some failed)
                            \--> [failed]      (none ok)

scheduled_at set:
  [scheduled] --(time arrives)--> [queued] --> ...
```

A job fans out to every account in `account_ids`. Each account gets its own
delivery result with the platform post id or a structured error.

## Statuses

| Status | Meaning |
| --- | --- |
| `scheduled` | Accepted for a future time, not yet queued. |
| `queued` | In the delivery queue, waiting for a worker. |
| `processing` | Being delivered to the target platforms. |
| `published` | Delivered to every targeted account. |
| `partial` | Delivered to some accounts; others failed. |
| `failed` | Failed for every account. |
| `canceled` | A scheduled job was canceled before it queued. |

Read the per account results in the [publish history](/docs/api/publish) to see
which account produced which outcome.

## Scheduling

Pass `scheduled_at` as an ISO 8601 timestamp with a timezone offset. It must be
at least 60 seconds in the future. The job sits in `scheduled` until its time
arrives, then moves to `queued`. You can cancel it while it is still scheduled
with [`POST /v1/publish/{job_id}/cancel`](/docs/api/publish). See the
[scheduling guide](/docs/guides/scheduling).

## Idempotency

Network retries can cause you to send the same request twice. Send an
`Idempotency-Key` header with a unique value per logical post and Dravo returns
the original job for repeated calls instead of enqueuing a duplicate.

```bash
curl -X POST https://api.dravo.dev/v1/publish \
  -H "Authorization: Bearer $DRAVO_API_KEY" \
  -H "Idempotency-Key: post-2026-06-23-launch" \
  -H "Content-Type: application/json" \
  -d '{ "account_ids": ["acc_8f2c1d"], "text": "Launch day." }'
```
