Workflow Automations

Visual workflow builder for trigger-based email and webhook flows. Define triggers, actions, conditions, and waits as a graph. Cloud-only, Scale plan.

Workflow Automations let you build trigger-driven flows in a visual canvas — for example: "When a contact subscribes to the newsletter → wait 24 hours → send welcome email → if they clicked the CTA, tag them as `engaged`". You build the workflow once, then enroll contacts via triggers (UI events, webhooks, or schedules) and Posthawk runs the graph.

This is an **Scale-plan-only** feature on cloud. Self-hosted users get it included with everything else.

## Triggers

A workflow starts an enrollment when a trigger fires. Built-in triggers:

• `newsletter_subscribed` — a subscriber confirmed (DOI off) or activated (DOI on)
• `newsletter_unsubscribed` — a subscriber unsubscribed (manual, suppression cascade, or one-click)
• `email_opened` / `email_clicked` — recipient interacted with a sent email
• `contact_created` — a contact was created via API or import
• `schedule` — repeating cron-like trigger (every Monday 9am, etc.)
• `webhook` — an external system POSTs to your workflow's webhook URL

The workflow's `trigger` node defines which trigger starts an enrollment. Triggers can include conditions (e.g. only fire on the `weekly-digest` newsletter, only on emails matching a tag).

## Steps

The workflow graph is composed of step nodes:

• `send_email` — send a transactional email or render a template
• `wait` — pause for a duration (`30 minutes`, `24 hours`, `7 days`)
• `wait_until` — pause until a specific datetime
• `condition` — branch based on contact properties, prior step output, or trigger context (`{{trigger.context.tag}}`)
• `webhook` — POST to an external URL (your CRM, Slack, etc.)
• `update_contact` — set tags, metadata, or unsubscribed on the enrolled contact
• `add_to_audience` / `remove_from_audience` — tag operations

Variables in steps support trigger payload interpolation: `{{trigger.contact.email}}`, `{{trigger.context.newsletter_slug}}`, etc.

## Endpoints

Most workflow operations happen through the dashboard. The worker exposes these JWT endpoints for programmatic use:
POST/automations/webhook/:tokenNone

Public webhook ingest endpoint — receives external events that should trigger a workflow enrollment. The token in the URL identifies which workflow to start. Body is forwarded as the trigger payload (`{{trigger.body}}` etc.).

ParameterTypeInDescription
tokenrequiredstringpathWorkflow webhook token (visible in the workflow settings)

Request

bash
curl -X POST https://api.posthawk.dev/automations/webhook/wh_abc123... \
  -H "Content-Type: application/json" \
  -d '{
    "email": "user@example.com",
    "tag": "premium",
    "amount": 99.00
  }'

Response

json
{
  "success": true,
  "enrollmentId": "enroll-uuid"
}
POST/automations/:id/test-runJWT

Run a workflow end-to-end with a synthetic trigger payload. Useful for validating the full graph without enrolling a real contact. Returns the per-step execution log.

ParameterTypeInDescription
idrequiredstringpathWorkflow UUID
triggerPayloadobjectbodyPayload to inject as `{{trigger}}`. Defaults to a sample for the workflow's configured trigger type.
POST/automations/:id/test-stepJWT

Run a single step in isolation against a synthetic context. Useful for testing variable interpolation or condition expressions.

ParameterTypeInDescription
idrequiredstringpathWorkflow UUID
stepKeyrequiredstringbodyThe step's key in the workflow graph
contextobjectbodySynthetic context to inject
POST/automations/:id/schedule/registerJWT

Register a recurring schedule trigger for a workflow. Replaces any existing schedule.

ParameterTypeInDescription
idrequiredstringpathWorkflow UUID
cronrequiredstringbodyCron expression (e.g. "0 9 * * MON")
timezonestringbodyIANA timezone (e.g. "America/New_York"). Defaults to UTC.
POST/automations/:id/schedule/unregisterJWT

Remove the recurring schedule from a workflow without deleting the workflow itself.

ParameterTypeInDescription
idrequiredstringpathWorkflow UUID
POST/automations/internal/triggerNone

Internal-only — used by Posthawk's suppression cascade and other server-to-server systems to fire automation triggers programmatically. Authenticated via the X-Posthawk-Internal shared-secret header.