View as markdown ↓

API reference

Every Postfleet endpoint lives under /api/v1/ and authenticates with a bearer pf_ API key:

Authorization: Bearer pf_...

A machine-readable OpenAPI 3.1 description of this surface is served at /openapi.json. It documents shipped behavior only — every path, method, status code, request field, and error code is transcribed from the route handlers and kept honest by a drift test. Point your OpenAPI client, code generator, or agent at that file.

The narrative guides — sending & idempotency, drafts & HITL, send lists, authentication, and webhooks — explain the semantics behind these endpoints.

Endpoints

Send

  • POST /api/v1/send — send an email. Optional client_id for idempotent duplicate protection. On a require_approval mailbox the send is queued as a forced draft (202).

Messages

  • GET /api/v1/messages?mailbox_id= — list recent messages in a mailbox (can_read).
  • GET /api/v1/messages/{id} — get one message with body, comprehension, and attachments (can_read).

Drafts

  • POST /api/v1/drafts — create a voluntary draft (can_send).
  • GET /api/v1/drafts?mailbox_id= — list open drafts in a mailbox (can_read).
  • GET /api/v1/drafts/{id} — get a draft (can_read).
  • PATCH /api/v1/drafts/{id} — edit a draft's envelope (can_send).
  • DELETE /api/v1/drafts/{id} — discard a draft (can_send).
  • POST /api/v1/drafts/{id}/send — send a draft. Delivers (201) or, on a require_approval mailbox, promotes to the human queue (202).

Mailboxes

  • POST /api/v1/mailboxes — provision a mailbox. Account-plane: rejected for a mailbox-bound key.

Domains

  • POST /api/v1/domains — add a custom sending domain (paid plan).
  • GET /api/v1/domains — list custom domains.
  • POST /api/v1/domains/{id}/verify — re-check a domain's verification.

Error shapes

Errors are JSON. Client-facing failures with a stable machine-readable code:

  • 403 key_scope — the key cannot perform this action, or is scoped to a different mailbox, or is a mailbox-bound key on an account-plane route.
  • 403 send_blocked_by_list — the recipient is blocked by a send list; carries reason (block_match / no_allow_match), scope (account / mailbox), and list_entry_id on a block match.
  • 409 idempotency_conflict — the client_id was reused with a different payload.
  • 409 idempotency_in_progress — a send with this client_id is still running; retry shortly.
  • 409 approval_conflict — the draft is no longer editable / deletable / sendable (a concurrent transition moved it).
  • 502 delivery_outcome_unknown — an ambiguous provider outcome; the send may or may not have gone out and is left for reconciliation.

Other statuses: 400 validation, 401 bad bearer, 402 quota exhausted, 404 not found (also returned for cross-account and cross-mailbox ids as anti-enumeration), 422 suppressed recipient. Cross-account and cross-mailbox object ids return 404 rather than 403 so a caller cannot enumerate ids it does not own.