Skip to content

03. Setting Up Triggers

This page is about deciding what wakes a workflow up. There are two ways.

Kind When it runs Example
Webhook (WEBHOOK) Every time someone calls the address When an order arrives, when a form is submitted
Schedule (SCHEDULER) At the times you set Every morning at 9, every Monday

Both are written on the ENTRYPOINT node. There is exactly one ENTRYPOINT per workflow.


Webhook triggers

The simplest form

- id: trigger
  name: Webhook trigger
  type: ENTRYPOINT

If you leave trigger out entirely, webhook is the default. In that case the request body you receive is passed on to the next node whole and unchanged.

If you want the incoming data validated

Attach an input-schema and eeumsae will validate the request for you.

- id: trigger
  name: Order webhook
  type: ENTRYPOINT
  trigger:
    kind: WEBHOOK
    input-schema:
      type: object
      required: [orderId, customerName]
      properties:
        orderId:      { type: string }
        customerName: { type: string }
        amount:       { type: number }

Using input-schema changes the behavior like this.

Situation Result
A required field is missing from the request The execution fails
The request contains a field not in properties It is dropped silently (it does not reach the next node)
A field that is in properties Passed through normally

In other words, input-schema is a whitelist. Every field you plan to use later has to be listed in properties. If you wrote a field and its value never arrives, check first whether you left it out of properties.

The call address

You can see and copy it on the workflow's Overview tab, in the Webhook trigger card. The format is:

POST https://api.eeumsae.com/webhooks/{workspaceId}/{workflowSlug}

{workflowSlug} is the slug you chose when you created the workflow.

curl -X POST "https://api.eeumsae.com/webhooks/<workspaceId>/order-notify" \
  -H "Content-Type: application/json" \
  -d '{"orderId": "ORD-1234", "customerName": "Ada Lovelace", "amount": 25000}'

The call returns a response immediately, and the workflow runs asynchronously in the background. A 200 response does not mean the workflow succeeded — it means "received, thanks". Check the result in the execution history. → 10. Executions and Monitoring

If the workflow is turned off, the call is rejected with 409 and nothing is recorded in the execution history. → 10. Executions and Monitoring

Blocking forged requests with a signature

Anyone who knows the webhook URL can trigger the workflow. To stop that, register a workspace secret named WEBHOOK_SECRET.

From the moment it exists, every webhook in that workspace requires a signature. The signature is the HMAC-SHA256 hex digest of the whole request body, keyed with WEBHOOK_SECRET, sent in either of these headers.

Header Format Used by
X-Webhook-Signature the hex string as-is systems you build yourself
X-Hub-Signature-256 sha256= + hex GitHub webhooks, exactly as they send it

If both arrive, X-Webhook-Signature wins. A missing or wrong signature means the workflow does not run.

BODY='{"orderId":"ORD-1234"}'
SIG=$(printf '%s' "$BODY" | openssl dgst -sha256 -hmac "$WEBHOOK_SECRET" -hex | awk '{print $2}')

curl -X POST "https://api.eeumsae.com/webhooks/<workspaceId>/order-notify" \
  -H "Content-Type: application/json" \
  -H "X-Webhook-Signature: $SIG" \
  -d "$BODY"

To wire up a GitHub webhook, just put the same value in the repository's Settings → Webhooks → Secret. GitHub attaches X-Hub-Signature-256 on its own and eeumsae verifies it as-is.

WEBHOOK_SECRET has to be registered as a secret (sensitive). Registering it as a plain variable does not turn verification on. → 08. Variables and Secrets

Reading the received values

${nodes.trigger.response.body.orderId}

trigger here is the id of the ENTRYPOINT node. If you named the node my-trigger, it becomes ${nodes.my-trigger.response.body.orderId}.


Schedule triggers

Runs automatically at the times you set.

- id: trigger
  name: Every morning trigger
  type: ENTRYPOINT
  trigger:
    kind: SCHEDULER
    cron: "0 0 9 * * ?"
    timezone: "Asia/Seoul"
    lookback: PT24H
Field Required Description
cron Required A six-field cron expression (see below)
timezone Optional Defaults to UTC. If you mean local time, you must write it out — for example Asia/Seoul
lookback Optional Computes a query window for you and passes it along (see below)

cron expressions have six fields

This differs from the five-field cron you usually see. A seconds field is prepended.

┌───────────── second (0-59)
│ ┌─────────── minute (0-59)
│ │ ┌───────── hour (0-23)
│ │ │ ┌─────── day of month (1-31)
│ │ │ │ ┌───── month (1-12)
│ │ │ │ │ ┌─── day of week (0-7, 0 and 7 are Sunday)
│ │ │ │ │ │
0 0 9 * * ?

Here are the common ones.

What you want cron
Every day at 9:00 0 0 9 * * ?
Every day at 9:30 0 30 9 * * ?
Every hour on the hour 0 0 * * * ?
Every 30 minutes 0 0/30 * * * ?
Weekdays (Mon-Fri) at 8:00 0 0 8 ? * MON-FRI
Every Monday at 10:00 0 0 10 ? * MON
Midnight on the 1st of every month 0 0 0 1 * ?

* and ?: the day-of-month field and the day-of-week field conflict with each other, so one of them takes a ?. If you are specifying by date, put ? in the day-of-week field; if by weekday, put ? in the day-of-month field.

Watch the time zone: if you omit timezone you get UTC. Writing only 0 0 9 * * ? runs at 6 PM Korea time. To run on Korea time, be sure to include timezone: "Asia/Seoul".

lookback — "just fetch the last 24 hours"

When you build a daily report, you always end up querying "the last day's worth". This feature has eeumsae compute the start and end of that window and pass them to you.

trigger:
  kind: SCHEDULER
  cron: "0 0 9 * * ?"
  timezone: "Asia/Seoul"
  lookback: PT24H        # 24 hours

With this, two values appear in the trigger output.

Value Meaning
${nodes.trigger.response.body.windowStart} Execution time − lookback
${nodes.trigger.response.body.windowEnd} Execution time

Both are ISO-8601 strings (for example 2026-05-19T09:00:00.000+09:00).

- id: fetch-orders
  name: Fetch orders
  type: CALL
  integration: http_request
  input:
    uri: "https://api.example.com/orders"
    method: GET
    queryParams:
      from: "${nodes.trigger.response.body.windowStart}"
      to: "${nodes.trigger.response.body.windowEnd}"

The lookback value is written in ISO-8601 duration format.

Window you want Notation
1 hour PT1H
6 hours PT6H
24 hours PT24H
7 days P7D
30 minutes PT30M

If you omit lookback, windowStart / windowEnd are never created at all. Referencing them raises an error during execution.

Pausing a schedule

Turn the workflow off instead of deleting it and the cron stops firing. Use this when something needs fixing but the daily alert keeps going out. → 10. Executions and Monitoring


Comparing the two

Webhook Schedule
Start condition When called from outside At the times you set
Input data The request body (whatever you want) None (window values if you use lookback)
Testing Straight from curl Wait for the time, or run it immediately over MCP
Good for Reacting to events (orders, sign-ups, inquiries) Recurring reports, checks and syncs

Next → 04. Integration Catalog