Workflows run your backend logic inside Anythink. A trigger starts a job, the job runs a chain of steps on the workflow worker, and every step's output is available to the steps after it.
Workflows are Anythink's automation engine. Use them for the logic that would otherwise need a backend service: reacting to new records, running nightly jobs, exposing an endpoint that does several things at once, calling other APIs, and sending email or push notifications.
This page explains the model and what happens at runtime. To build one, start with Build your first workflow.
| Part | What it is |
|---|---|
| Workflow | A named automation with one or more triggers and a set of steps. Names are unique within a project. |
| Trigger | What starts the workflow: a data event, a schedule, a button, or an API call. A workflow can have several. |
| Step | One action — read data, create a record, call an API, run a script, send a notification. Each has a key. |
| Job | One run of a workflow. It records the trigger payload, every step's log and output, and the final status. |
Steps are connected, not ordered. Each step has an on success link and an optional on failure link to another step. One step is marked as the start step. A job begins there and follows the links until a step has nowhere left to go.
Pending and a payload of { id, entity_name, data }, then puts it on the workflow queue. For event triggers with a filter, the filter is checked first; if it doesn't match, no job is created.Running.{{ $anythink.trigger.data.email }} in the step's parameters are resolved just before it runs.$anythink.steps.<key>.Success when the last step it ran succeeded, or when a failure was handled by an on failure path that completed. It ends Failed when a step fails and has no on failure link.Every job and step result is kept in the workflow's Job History, so you can see exactly what each step received and returned. See Monitoring and testing.
| Trigger | Starts a job when | Typical use |
|---|---|---|
| Event | A record is created or updated, a user registers or is invited, a payment or subscription changes, or a push notification action is tapped | Welcome emails, follow-up tasks, syncing data |
| Timed | A cron schedule comes due (UTC, checked every minute) | Nightly imports, weekly reports, reminders |
| Manual | Someone runs it from a record in the dashboard, or your code calls the trigger endpoint | Admin actions, one-off fixes |
| API endpoint | A POST reaches /org/{orgId}/workflows/api/{route} |
Custom endpoints for your app |
Event triggers can carry a filter so a workflow only runs when it matters — for example, only when an order's status changes to paid. Full details: Triggers and scheduling.
| Step | What it does |
|---|---|
| Read data | Reads records from an entity, with filters, sorting and a limit |
| Create data | Creates one record, or one per item in a list |
| Update data | Updates records by id or by filter |
| Upsert data | Matches records on key fields, then updates, ignores or creates |
| Delete data | Deletes every record matching a filter |
| Condition | Branches the workflow on one or more comparisons |
| Run a script | Runs JavaScript against the trigger data and earlier step outputs |
| Call an API | Sends an HTTP request and keeps the JSON response |
| Send an email | Sends one of your project's email templates |
| Send a push notification | Sends to a user, a list of users, a record's owners, or everyone — once or per row |
| File handler | Downloads a file into Anythink and attaches it to a record, links an existing file, or detaches one |
| Integration | Calls a connected service: Claude, OpenAI, Grok, Slack, GitHub, Google Calendar, LinkedIn or X |
Every parameter and output is listed in Step types.
Parameters can contain templates. The most common ones:
{{ $anythink.trigger.id }} the record id that fired an event trigger
{{ $anythink.trigger.data.email }} a field from the trigger data
{{ $anythink.steps.find_customer.data[0].name }} a field from an earlier step's output
{{ $anythink.secrets.stripe_key }} a project secret
{{ $anythink.now }} the current time (UTC, ISO 8601)
When a template is the whole value of a JSON field, the value keeps its type, so a number stays a number and an object stays an object. The full rules are in Template syntax.
Workflow steps run as the Anythink workflow worker, a trusted service, not as the person who triggered the job. That has two consequences you need to design for:
user_id eq {{ $anythink.trigger.data.user_id }}.auto_set_rls, group grants, or an _rls payload). See Step types.Anyone who can edit a workflow can therefore read and send any data in the project. Keep workflow permissions (anythink_workflows:create, :update) for people you'd trust with that access.
| Limit | Value |
|---|---|
| Step executions per job | 250. A job that loops past this fails with "exceeded maximum step limit". |
| Retries | None. A failed step fails the job unless it has an on failure path. Re-run by triggering again. |
| Schedules | Five-field cron, UTC only, one-minute resolution. Missed runs aren't caught up. |
| Scripts | 30 seconds, 64 MB and 100,000 statements per run. No network access. |
| File downloads | 50 MB and 30 seconds per file. |
| Runs per month | Set by your plan's workflow quota. Jobs over quota fail with a quota message and aren't billed. |
| API endpoint responses | 204 No Content. The job runs in the background; the response doesn't include its result. |
| Job order | Not guaranteed. Jobs run concurrently. |
| Sub-workflows | Not supported. Build shared logic into each workflow, or trigger another workflow's API route with Call an API. |
A few behaviours are worth knowing before you build:
Failed. Link the false branch to a step, even a no-op, when "nothing to do" is a normal outcome.