CFFBRWCFFBRWDocumentation
⚠Auto-generated documentation — This content was generated with AI assistance and is currently under review. Information may be incomplete or inaccurate. When in doubt, contact our support team.

Triggers & Scheduling

Workflows can run on a schedule, fire on an API call, or batch up inbound events through a queue.

Pick the right trigger

TriggerWhen to pick it
ManualYou run the workflow from the dashboard or MCP. One-off or exploratory.
CronFixed schedule. Daily digest, hourly sync, weekly report.
API / webhookOne event = one run. Deploy notifications, form submissions, CI hooks.
QueueEvents arrive unpredictably and you want to batch them. Inbound webhooks, email drops, lead captures, IoT telemetry. One batched run every N minutes or every M messages, whichever comes first.

Queue is the "don't run me once per event" trigger. If you'd rather spend one AI call on 50 events than 50 AI calls on one event each, this is the knob.

Cron Scheduling

Run your workflow on a recurring schedule:

  1. Open your workflow → Settings
  2. Find the Schedule section
  3. Enter a cron expression
  4. Click Save

Common Cron Expressions

ExpressionSchedule
0 9 * * 1-5Weekdays at 9:00 AM UTC
0 */6 * * *Every 6 hours
0 0 * * 1Every Monday at midnight UTC
*/30 * * * *Every 30 minutes
0 8 1 * *1st of every month at 8:00 AM UTC

How It Works

  • The schedule triggers on Cloudflare's edge — no server to keep running
  • Each trigger creates a new run with the published plan
  • You can pass default variables in the schedule configuration
  • View scheduled runs in the Runs tab like any other run
  • The workflow must be published for the schedule to fire

Disabling a Schedule

Go to workflow Settings → click the delete icon next to the schedule, or unpublish the workflow.

Webhook Triggers

Trigger a workflow from any external service that can send HTTP requests:

POST https://api.cffbrw.com/v1/trigger/:workflowId
Authorization: Bearer wfk_your-api-key
Content-Type: application/json

{
  "variables": {
    "message": "Deploy completed",
    "environment": "production"
  }
}

Use Cases

  • CI/CD — Trigger a workflow after a deployment completes
  • Monitoring — Run analysis when an alert fires
  • Form submissions — Process incoming data from web forms
  • Third-party integrations — Connect services that support outgoing webhooks

Requirements

  • The workflow must be published
  • Authentication via wfk_ API key (from Settings → API Keys)
  • Variables in the request body are available as {VARIABLE_NAME} in the workflow markdown

API Keys

Manage API keys in the dashboard under Settings → API Keys:

  • Click Create Key to generate a new wfk_ prefixed key
  • Each key is scoped to your workspace
  • Keys can only trigger published workflows (403 on drafts)
  • Revoke a key by clicking the delete icon

Security: API keys are shown once on creation. Store them securely. They cannot be recovered after dismissing the dialog.

Queue Trigger

Use a queue trigger when events stream in at their own pace and you want one batched run instead of one run per event.

How it works: your workflow gets a persistent inbox at POST /v1/enqueue/:workflowId. External systems post messages there. The platform accumulates them. When either a time window elapses (say, 5 minutes) or a batch size is reached (say, 10 messages), whichever trips first, the platform fires one workflow run with inputs.batch set to the whole batch.

Setting it up

  1. Open your workflow → Settings
  2. Find the Queue Trigger section and toggle queue
  3. Configure:
    • Window — how long to wait before firing a batch. 1 second to 1 day.
    • Batch size — fire immediately once this many messages arrive. 1 to 100.
    • Max queue depth — reject enqueue past this many queued messages. 1 to 10,000.
    • Ingest secret — strongly recommended. Without it, anyone who knows the workflow ID can post messages. Set it and include it on each enqueue request.
  4. Save Configuration and Publish.

Posting messages

curl -X POST https://api.cffbrw.com/v1/enqueue/$WORKFLOW_ID \
  -H "X-Webhook-Secret: your-secret" \
  -H "Content-Type: application/json" \
  -d '{"event": "lead.created", "email": "alice@example.com"}'

Response:

{ "enqueued": true, "queueDepth": 4, "msgId": 42 }

You can post in two shapes:

  • Bare — the whole body is the payload. { "event": "lead.created" } → stored payload is { "event": "lead.created" }.
  • Envelope — wrap with optional metadata. { "payload": {...}, "source": "webhook-A", "dedupeKey": "order-123" } → stored payload is the inner object, source and dedupeKey are envelope fields.

Deduplication: set dedupeKey in the envelope to prevent double-processing when your producer retries. If a message with the same key is already in the queue (not yet drained), enqueue returns 409 DEDUPE instead of inserting a duplicate. The key is scoped to the queue and reusable after the message drains.

Writing the workflow

The workflow receives inputs.batch as an array of { id, payload, received_at, source? } objects. Typical shape:

# Lead digest

Summarize today's inbound leads and post to Slack.

## Step 1 — Filter qualified leads

`inputs.batch` is an array of new leads. Keep only those with `score >= 7`.

\`\`\`transform
return data.input.batch.filter(m => m.payload.score >= 7);
\`\`\`

## Step 2 — Summarize

Generate a digest from the filtered leads.

## Step 3 — Post to #sales

Send the digest via Slack.

The compiler will warn you if you publish a queue-triggered workflow that never references inputs.batch — almost always a misconfiguration.

Behavior notes

  • Serial execution. While a batch is being processed, new messages still accumulate, but the next drain waits until the current run finishes. Simpler to reason about for workloads that dedupe or aggregate against shared state.
  • Backpressure. Once queue depth hits maxQueueDepth, enqueue returns 429 with the depth details. Well-behaved webhook producers retry on 429, which gives you natural backpressure.
  • Dead-letter on failure. If a dispatched run fails, its messages go to a dead-letter queue (not auto-retried). Inspect at GET /v1/queues/:id/dead-letter, replay via POST /v1/queues/:id/dead-letter/replay. Replay preserves original timestamps; if replaying would push the queue past its depth cap, it returns 409 instead of silently losing data.
  • Batch too large. If a batch's serialized size would exceed the platform's per-run limit, it's diverted to the dead-letter queue with failure_reason="batch_too_large". Lower maxBatchSize if you see this.

Inspect the queue

  • GET /v1/queues/:workflowId → depth, in-flight run id, next fire time, dead-letter count
  • GET /v1/queues/:workflowId/messages?limit=50 → queued message list
  • GET /v1/queues/:workflowId/dead-letter?limit=50 → dead-letter entries
  • DELETE /v1/queues/:workflowId/messages/:id → remove a single queued message
  • DELETE /v1/queues/:workflowId → purge all queued messages (admin escape hatch)

Inspection endpoints use your Clerk session (dashboard auth). Enqueue uses the workflow's ingest secret.

Combining Triggers

A single workflow can have multiple trigger types active simultaneously:

  • Manual runs from the dashboard
  • A cron schedule for daily execution
  • A webhook endpoint for on-demand triggers
  • A queue trigger for inbound event streams

All triggers use the same published plan and create independent runs.