Triggers and scheduling
Start a workflow from a record change, a schedule, a dashboard button or an API route, and add trigger filters so it only runs when it should.
Last updated
A trigger decides when a workflow runs and what data the job starts with. A workflow can have several triggers of different types. For example, run when an order is created and every night at 02:00. Any of them starts the same steps.
| Trigger | Trigger Type | Starts a job when |
|---|---|---|
| Event | Event | A record is created or updated, a user registers or is invited, a payment or subscription changes, or someone taps a push notification button |
| Timed | Timed | A cron schedule comes due |
| Manual | Manual | Someone runs it from a record in the Anythink dashboard, or your code calls the trigger endpoint |
| API route | API Call | A POST reaches the workflow's own route |
Every job starts with a payload of id, entity_name and data. Steps read them as {{ $anythink.trigger.id }}, {{ $anythink.trigger.entity_name }} and {{ $anythink.trigger.data.<field> }}. Each trigger type fills them differently, as the sections below show. For the model behind jobs and steps, see How workflows work.
Add a trigger
Every workflow needs at least one trigger. You choose the first when you create the workflow, and you can add more later.
In the Anythink dashboard
- Open Workflows and select New Workflow, or open an existing workflow.
- In the editor, select the Workflow Settings icon in the toolbar. For a new workflow the same fields are on the create form.
- Under Triggers, select Add trigger.
- Choose a Trigger Type and fill in the fields it shows: Event Type and Entity for an event, Schedule for a timed trigger, Entities for a manual trigger, API Route for an API call.
- Leave Enabled ticked, then select Save Changes.
With the CLI
workflows create makes a workflow with one trigger. The options depend on the type:
# Event: a record changes
anythink workflows create order-paid \
--trigger Event --event EntityUpdated --entity orders --enabled
# Timed: a cron schedule, in UTC
anythink workflows create nightly-report \
--trigger Timed --cron "0 2 * * *" --enabled
# API route: no leading slash
anythink workflows create sync-orders \
--trigger Api --api-route sync-orders --enabled
Each command prints the new workflow's id. Add steps with anythink workflows step-add, as described in Step types. To give a workflow more than one trigger, or a Manual trigger, use Workflow Settings in the Anythink dashboard.
With an AI assistant (MCP)
Create a workflow called nightly-report with a timed trigger that runs at 02:00 every day, and enable it.
The assistant runs workflows create through the cli tool. Name the trigger type, and the event, entity, cron expression or route that goes with it.
Event triggers
An event trigger runs a workflow when something happens in your project. Pick an Event Type. The dashboard shows the names below with spaces (Entity Created), and the CLI and API use them as written.
| Event | Starts when | $anythink.trigger.id |
$anythink.trigger.data |
|---|---|---|---|
EntityCreated |
A record is created through the REST API, in bulk or by import, or by a workflow step | The new record's id | The fields that were sent. It doesn't include the new id or values the server filled in. |
EntityUpdated |
A record is updated | The record's id | The whole record as it is after the update |
UserRegistered |
Someone registers with your project | The user's id | first_name, last_name, email, referral_code |
UserInvited |
A user is invited to your project | The user's id | first_name, last_name, email, referral_code |
PaymentCreated, PaymentSucceeded, PaymentFailed |
AnythinkPay records a payment | 0 |
The payment |
SubscriptionCreated, SubscriptionActivated, SubscriptionExpired |
A subscription is created, activated or expires | 0 |
The subscription |
PaymentMethodCaptured, PaymentMethodCaptureFailed, PaymentMethodRemoved |
A saved payment method is captured, fails to capture or is removed | 0 |
The payment method |
PushActionTaken |
A user taps an action button on a push notification | The user's id, or 0 |
notification_id, category, action_id, target_user_id, received_at, responded_at and any extra data the app sent |
For EntityCreated and EntityUpdated, choose the Entity to watch. The trigger can't be saved without one, and the entity has to exist. {{ $anythink.trigger.entity_name }} holds its name.
Note: On EntityCreated, the trigger data holds the fields in the create request. Read the new record's id from {{ $anythink.trigger.id }}, or add a Read data step to load the saved record.
Payment and subscription events are raised for Stripe activity. See Webhooks for the data each carries and an end-to-end example. For PushActionTaken, iOS button group is the notification category, and leaving it empty matches every category. See Push notifications from a workflow.
Event triggers fire for changes made by any route into the data: the REST API, the Anythink dashboard, imports, and other workflows' Create data and Update data steps. A workflow that updates the entity it watches starts itself again, so give it a filter that stops the loop.
Trigger filters
A filter makes an event trigger skip events you don't care about. It's checked before a job is created, so a filtered-out event creates no job and leaves nothing in Job History.
A filter is a tree of and, or and not groups around conditions:
{
"and": [
{ "field": "status", "op": "changed_to", "value": "paid" },
{ "field": "total", "op": "gte", "value": 100 }
]
}
op |
Matches when |
|---|---|
eq, neq |
The field equals, or doesn't equal, value. Numbers compare as numbers. |
gt, gte, lt, lte |
The field compares with value as a number, then as a date, then as text. A null field never matches. |
in |
value is a list that contains the field's value, such as ["paid", "shipped"] |
contains |
The field's text contains value, ignoring case |
is_null, is_not_null |
The field is missing or null, or is present and not null |
changed |
The field's value is different from before the update |
changed_to |
The field changed and now equals value |
Use only the operators in this table.
fieldis a top-level field on the record. Dotted paths and related records aren't supported.- On
EntityCreated, the filter sees only the fields in the create request. OnEntityUpdated, it sees the whole record after the update. changedandchanged_toneed the previous values, which onlyEntityUpdatedhas. They never match on other events.- Types matter: the boolean
truedoesn't equal the text"true". Text that looks like a date, such as2026-09-01, is compared as a date. - An empty
andmatches everything and an emptyormatches nothing. - For
PushActionTaken, the filter runs against the trigger data, so{ "field": "action_id", "op": "eq", "value": "snooze" }reacts to one button.
In the Anythink dashboard
- In Workflow Settings, set Trigger Type to Event and choose an Event Type and Entity.
- Under the entity, select Add filter. The builder is headed Fire only when….
- Pick a field, an operator and a value. Select + Condition for more, or + Group for a nested group.
- Choose All of these to require every condition, or Any of these to require one.
- Select Save Changes. To remove the filter, select Remove filter.
The builder builds and and or groups. To save a not group, use the CLI or the API.
With the CLI
anythink workflows create order-paid \
--trigger Event --event EntityUpdated --entity orders \
--filter '{"and":[{"field":"status","op":"changed_to","value":"paid"},{"field":"total","op":"gte","value":100}]}' \
--enabled
For a long filter, put the JSON in a file and pass --filter-file filter.json instead.
With an AI assistant (MCP)
Create a workflow called order-paid that runs when an order is updated, but only when its status changes to paid and the total is at least 100. Enable it.
The assistant runs workflows create with --filter through the cli tool.
Timed triggers
A timed trigger runs on a cron schedule.
| Setting | Value |
|---|---|
cron_expression |
Five fields: minute, hour, day of month, month, day of week. There's no seconds field. |
| Time zone | UTC. 0 9 * * * runs at 09:00 UTC, which is 10:00 in London during summer time. |
| Resolution | One minute. Anythink checks for due schedules every minute. |
| Schedule | Cron |
|---|---|
| Every 15 minutes | */15 * * * * |
| Every day at 02:00 UTC | 0 2 * * * |
| Weekdays at 08:30 UTC | 30 8 * * 1-5 |
| First day of the month | 0 0 1 * * |
A scheduled job has no record behind it. $anythink.trigger.id and $anythink.trigger.data are empty and entity_name is null. Begin with a Read data step to fetch what the job should work on. Each due schedule starts one job, and a schedule that was missed isn't replayed.
In the Anythink dashboard
- In Workflow Settings, set Trigger Type to Timed.
- Under Schedule, choose Interval, Daily, Weekly or Monthly and set the time. Times are UTC. An interval runs every 1 to 30 minutes or every 1 to 12 hours.
- Or select Use cron expression and enter the five fields.
- Check the summary under the schedule, such as
Daily at 02:00, then select Save Changes and make sure the workflow is enabled. - To run it once without waiting, select Test Workflow in the toolbar and then Run Test. This fires the workflow now and ignores the schedule.
With the CLI
anythink workflows create nightly-report \
--trigger Timed --cron "0 2 * * *" --enabled
anythink workflows trigger 42
anythink workflows jobs 42
Replace 42 with the workflow's id. workflows trigger runs it once now, and workflows jobs lists the runs. Without --cron the schedule is 0 9 * * *.
With an AI assistant (MCP)
Create a workflow called nightly-report that runs every weekday at 08:30 UTC, and enable it. Then run it once and show me the job.
The assistant runs workflows create --trigger Timed --cron "30 8 * * 1-5", then workflows trigger and workflows jobs through the cli tool.
Manual triggers
A manual trigger lists the entities it applies to. On the detail page of a record in one of those entities, the Workflows section lists the workflow with a play button. Selecting it and confirming starts a job with that record's id in {{ $anythink.trigger.id }} and the entity name in {{ $anythink.trigger.entity_name }}. trigger.data is empty, so load the record with a Read data step if you need its fields.
Your code can start the same job:
POST https://api.my.anythink.cloud/org/{project_id}/workflows/{workflow_id}/trigger
x-api-key: <your key>
Content-Type: application/json
{
"entity_name": "orders",
"entity_id": 1042,
"data": "{\"reason\":\"manual resend\"}"
}
| Field | Detail |
|---|---|
entity_name |
Required for a Manual trigger, and it must be one of the trigger's entities. Otherwise the call is rejected with a message that the workflow isn't permitted for that entity. |
entity_id |
Optional. It becomes trigger.id. |
data |
Optional. It's a JSON string, not an object, and it becomes trigger.data. |
The caller needs the anythink_workflows:trigger permission. A successful call returns 204 No Content and the job runs in the background. See API keys for creating a key that carries only that permission.
In the Anythink dashboard
- In Workflow Settings, set Trigger Type to Manual.
- In Entities, choose one or more entities.
- Select Save Changes and enable the workflow.
- Open a record in one of those entities. In its Workflows section, select the play button next to the workflow and confirm with Trigger.
- To pick a record and edit the payload before running, select Test Workflow in the workflow editor, choose the Entity and Record, and select Run Test.
With the CLI
anythink workflows trigger 42 \
--entity orders --entity-id 1042 \
--payload '{"reason":"manual resend"}'
--entity is required for a workflow with a Manual trigger. --payload is plain JSON, and the CLI sends it as the data string for you.
With an AI assistant (MCP)
Run workflow 42 for order 1042 with the payload {"reason": "manual resend"}, then show me the job.
The assistant runs workflows trigger and workflows jobs through the cli tool.
API route triggers
An API route trigger gives the workflow its own route:
POST https://api.my.anythink.cloud/org/{project_id}/workflows/api/sync-orders?id=1042&entity_name=orders
x-api-key: <your key>
Content-Type: application/json
{ "source": "shopify", "since": "2026-09-01T00:00:00Z" }
| Rule | Detail |
|---|---|
| Method | POST only |
| Route | One path segment such as sync-orders, with no slashes. Stored in lower case and matched without regard to case. |
| Uniqueness | Unique across the project's API route triggers, including disabled ones |
| Authentication | A user token, or an API key, with anythink_workflows:trigger |
| Payload | The JSON body becomes trigger.data. The optional id and entity_name query parameters become trigger.id and trigger.entity_name. An empty body gives an empty data. |
| Response | 204 No Content once the job is queued. 404 when no enabled trigger has that route. |
The response doesn't wait for the workflow. This suits fire-and-forget work such as imports, syncs and notifications. If your app needs a result, have the workflow write it to a record and read that record. Webhooks covers creating the key and an end-to-end example.
In the Anythink dashboard
- In Workflow Settings, set Trigger Type to API Call.
- Enter an API Route such as
sync-orders, with no leading slash. - Select Save Changes and enable the workflow.
With the CLI
anythink workflows create sync-orders \
--trigger Api --api-route sync-orders --enabled
anythink fetch "/workflows/api/sync-orders?id=1042&entity_name=orders" \
--method POST --body '{"source":"shopify"}'
The second command calls the route as the active profile. Then run anythink workflows jobs <workflow_id> to see the job.
With an AI assistant (MCP)
Create a workflow called sync-orders with an API route trigger on the route sync-orders, and enable it. Then call the route with {"source": "shopify"}.
The assistant runs workflows create and fetch through the cli tool.
Workflows with several triggers
- Events: if more than one trigger on a workflow matches the same event, the workflow runs once. If several workflows watch the same event, each starts its own job.
- Schedules: each timed trigger runs on its own schedule.
- Which trigger started it: steps can't tell. If it matters, use separate workflows, or branch on the payload's shape with a Condition or Run a script step.
Enabling and disabling
- The workflow's Enable Workflow setting stops its event and timed triggers from starting jobs, and hides its buttons on records.
- Each trigger also has its own Enabled switch. Clear it to stop one trigger and leave the rest running.
- For an API route, the trigger's Enabled switch decides whether the route answers. Clear it and callers get
404. - Changes apply to jobs that haven't started yet. A job that's already running finishes with the version it started with.
Check it worked
Fire the trigger once, then read the job.
- Cause the event, wait for the schedule, press the record button, or call the route.
- Open the workflow, select View Job History in the toolbar, and open the newest job. It shows the payload the trigger produced and the log and output of every step.
- Or run
anythink workflows jobs <workflow_id>.
If an event trigger with a filter produced no job, the filter didn't match. Check the field name and value against the data in the table above, remembering that EntityCreated only has the fields that were sent. Test workflows and read job history covers reading jobs and tracking down failures.