Scheduled Emails

Schedule emails for future delivery and manage them with list, cancel, reschedule, and send-now operations. All state transitions are race-safe and an audit log records every change.

Each scheduled email moves through a state machine: scheduled → (sending →) sent | failed | cancelled.

State transitions are atomic and race-safe — the worker uses optimistic concurrency (WHERE status='scheduled') so a cancel that lands in the gap between the BullMQ job firing and the SES dispatch always wins, never producing a duplicate send.

Each scheduled email carries an audit_log JSONB array recording every state change with timestamps and details — useful for debugging delivery issues or building a per-email audit trail. An idempotency_token UUID rotates on each reschedule so older queued jobs whose data references the previous token short-circuit at the processor's pre-flight gate.

POST/v1/send

Schedule an email by including scheduledFor in the send request.

Authorizations

Authorizationstring · headerrequired

Bearer authentication header of the form Bearer <token>, where <token> is your API Key.

Body

fromstringrequired

Sender email address

tostring[]required

Array of recipient emails

subjectstringrequired

Email subject

htmlstringoptional

HTML body

textstringoptional

Plain text body

scheduledForstringrequired

ISO 8601 datetime, must be future, max 30 days

timezonestringoptional

Timezone (e.g., "America/New_York")

POST /v1/send
curl -X POST https://your-posthawk-instance.com/v1/send \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer your_api_key" \
  -d '{
    "from": "hello@yourdomain.com",
    "to": ["user@example.com"],
    "subject": "Your weekly report",
    "html": "<h1>Weekly Report</h1><p>Here are your stats...</p>",
    "scheduledFor": "2025-06-15T09:00:00Z",
    "timezone": "America/New_York"
  }'
Response
{
  "success": true,
  "scheduled": true,
  "id": "scheduled-uuid",
  "scheduledFor": "2025-06-15T09:00:00.000Z",
  "message": "Email scheduled successfully",
  "statusUrl": "/scheduled/scheduled-uuid"
}
GET/scheduled

List all scheduled emails with optional filtering and pagination.

Authorizations

Authorizationstring · headerrequired

Bearer authentication header of the form Bearer <token>, where <token> is your API Key.

Query Parameters

statusstringoptional

Filter by status: scheduled, sending, sent, failed, cancelled

limitnumberoptional

Pagination limit

offsetnumberoptional

Pagination offset

GET /scheduled
curl https://api.posthawk.dev/scheduled \
  -H "Authorization: Bearer your_api_key"
Response
{
  "success": true,
  "data": [
    {
      "id": "uuid",
      "from": "hello@yourdomain.com",
      "to": ["user@example.com"],
      "subject": "Weekly Report",
      "scheduled_for": "2026-06-15T09:00:00Z",
      "status": "scheduled",
      "audit_log": [
        { "at": "2026-04-15T10:00:00Z", "action": "created" }
      ]
    }
  ],
  "total": 1
}
GET/scheduled/:id

Get details of a specific scheduled email.

Authorizations

Authorizationstring · headerrequired

Bearer authentication header of the form Bearer <token>, where <token> is your API Key.

Path Parameters

idstringrequired

Scheduled email UUID

GET /scheduled/:id
curl https://api.posthawk.dev/scheduled/{id} \
  -H "Authorization: Bearer your_api_key"
Response
{
  "success": true,
  "data": {
    "id": "uuid",
    "from": "hello@yourdomain.com",
    "to": ["user@example.com"],
    "subject": "Weekly Report",
    "html": "<h1>Weekly Report</h1>...",
    "scheduled_for": "2026-06-15T09:00:00Z",
    "status": "scheduled",
    "idempotency_token": "1f3a8c2d-...",
    "audit_log": [
      { "at": "2026-04-15T10:00:00Z", "action": "created" }
    ],
    "created_at": "2026-04-15T10:00:00Z"
  }
}
DELETE/scheduled/:id

Cancel a pending scheduled email. Race-safe optimistic concurrency: only succeeds if status is still `scheduled`. Returns 409 if the email already started sending or completed.

Authorizations

Authorizationstring · headerrequired

Bearer authentication header of the form Bearer <token>, where <token> is your API Key.

Path Parameters

idstringrequired

Scheduled email UUID

DELETE /scheduled/:id
curl -X DELETE https://api.posthawk.dev/scheduled/{id} \
  -H "Authorization: Bearer your_api_key"
Response
{
  "success": true,
  "data": {
    "id": "uuid",
    "status": "cancelled",
    "cancelled_at": "2026-04-28T11:30:01Z"
  },
  "message": "Scheduled email cancelled successfully"
}
PATCH/scheduled/:id/reschedule

Reschedule a pending email to a new time. Rotates the idempotency_token so any in-flight BullMQ job for the previous slot short-circuits at the processor pre-flight gate.

Authorizations

Authorizationstring · headerrequired

Bearer authentication header of the form Bearer <token>, where <token> is your API Key.

Path Parameters

idstringrequired

Scheduled email UUID

Body

scheduledForstringrequired

New ISO 8601 datetime

PATCH /scheduled/:id/reschedule
curl -X PATCH https://your-posthawk-instance.com/scheduled/uuid/reschedule \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer your_api_key" \
  -d '{ "scheduledFor": "2026-06-20T14:00:00Z" }'
Response
{
  "success": true,
  "data": { "id": "uuid", "scheduled_for": "2026-06-20T14:00:00Z" },
  "message": "Email rescheduled successfully"
}
POST/scheduled/:id/send-now

Fire a scheduled email immediately. Implemented as a reschedule to "now + 1s" through the same race-safe path used for manual reschedules. Useful for "Send now" buttons in admin UIs.

Authorizations

Authorizationstring · headerrequired

Bearer authentication header of the form Bearer <token>, where <token> is your API Key.

Path Parameters

idstringrequired

Scheduled email UUID

POST /scheduled/:id/send-now
curl -X POST https://api.posthawk.dev/scheduled/{id}/send-now \
  -H "Authorization: Bearer your_api_key"
Response
{
  "success": true,
  "data": { "id": "uuid", "scheduled_for": "2026-04-28T11:30:01Z" },
  "message": "Email queued for immediate send"
}