powered by

Workflow recipes

Six workflows to copy and adapt: Slack alerts, status emails, push notifications, a nightly clean-up, partner webhooks and chained workflows.

Last updated

Each recipe is a complete workflow you can rebuild and change. They cover the patterns that come up most: telling people when something happens, cleaning up on a schedule, accepting data from another system, and having one workflow hand over to another. Every recipe is shown in the Anythink dashboard, with the CLI and with an AI assistant over MCP.

New to workflows? Start with Build your first workflow, and see How workflows work for the model. Expressions such as {{ $anythink.trigger.data.email }} are explained in Template syntax.

Recipe Trigger Steps
Notify Slack about a new lead A record is created Integration
Email a customer when a ticket is resolved A field changes to a value Send an Email
Send a push when an order ships A field changes to a value Send a Push Notification
Clear out expired records every night A schedule Delete Data
Create or update a record from a partner's webhook An API call Upsert Data
Chain workflows with a record write A field changes, then a record is created Create Data, Update Data

Note: These examples use entity and field names such as leads and status. Swap in your own. A step's parameters name the entity as entity_name, except Read Data, which uses entity.

Notify Slack about a new lead

Goal: post a message in #sales whenever someone is added to leads.

Before you start: connect Slack to your project. See Connect Slack to send messages from workflows. You need a leads entity with name and company text fields.

Key Step Why
post_to_slack Integration Runs Slack's Send Message operation

In the Anythink dashboard

  1. Open Workflows and select New Workflow.
  2. Enter the Name notify-new-lead. Leave Trigger Type as Event, set Event Type to Entity Created and Entity to leads.
  3. Select Create Workflow, then Add Step and choose Integration.
  4. Enter the Name Post to Slack and the Key post_to_slack, and tick Enable Step.
  5. Choose the Slack provider and the Send Message operation. Enter the channel #sales and this message:
text
New lead: {{ $anythink.trigger.data.name }} from {{ $anythink.trigger.data.company | default: "an unknown company" }}
  1. Save the step, make it the start step, save the workflow, then select Enable Workflow.

With the CLI

bash
anythink workflows create notify-new-lead \
  --trigger Event --event EntityCreated --entity leads --enabled

anythink workflows step-add <workflow_id> post_to_slack \
  --name "Post to Slack" --action Integration --start --enabled \
  --params '{
    "provider": "slack",
    "operation": "send-message",
    "credential_source": "system",
    "inputs": {
      "channel": "#sales",
      "text": "New lead: {{ $anythink.trigger.data.name }} from {{ $anythink.trigger.data.company | default: '"'"'an unknown company'"'"' }}"
    }
  }'

The workflows create command prints the workflow's id. Use it in step-add.

With an AI assistant (MCP)

Create a workflow called notify-new-lead that runs when a record is created in leads. Add an Integration step with the key post_to_slack that sends a Slack message to #sales saying "New lead: " followed by the lead's name, " from " and its company, or "an unknown company" if it's empty. Make it the start step and enable the workflow.

The assistant runs workflows create and workflows step-add through the cli tool.

How it works:

  • credential_source: "system" posts as your project's Slack connection, not as a particular user.
  • | default covers a lead with no company, so the message never shows a raw {{ }}.
  • The step output has ok: true when Slack accepted the message. Open View Job History to see it.
  • If Slack isn't connected, the step fails and the job is marked Failed with a message that says so. Link the step's on failure handle to a Send an Email step if you want to hear about it.

Email a customer when a ticket is resolved

Goal: send the requester an email the moment a ticket's status becomes resolved, and only then.

Before you start: verify a sending domain and create an email template with the type ticket_resolved that uses the variables {{ first_name }} and {{ subject }}. See Send email from a workflow. You need a tickets entity with requester_email, first_name, subject and status text fields.

Key Step Why
send_resolved Send an Email Sends the template to the requester

The trigger carries a filter, so editing a resolved ticket later doesn't send the email again.

In the Anythink dashboard

  1. Open Workflows and select New Workflow. Name it ticket-resolved.
  2. Set Event Type to Entity Updated and Entity to tickets.
  3. Under Fire only when…, select Add filter. Set the field to status, the operator to changed to and the value to resolved.
  4. Select Create Workflow, then Add Step and choose Send An Email. Name it Email requester with the Key send_resolved.
  5. Enter {{ $anythink.trigger.data.requester_email }} as the To Email Address and pick the ticket_resolved template.
  6. On the Mappings tab, set first_name to {{ $anythink.trigger.data.first_name }} and subject to {{ $anythink.trigger.data.subject }}.
  7. Save the step, make it the start step, save the workflow and select Enable Workflow.

With the CLI

bash
anythink workflows create ticket-resolved \
  --trigger Event --event EntityUpdated --entity tickets \
  --filter '{"field":"status","op":"changed_to","value":"resolved"}' \
  --enabled

anythink workflows step-add <workflow_id> send_resolved \
  --name "Email requester" --action SendAnEmail --start --enabled \
  --params '{
    "to": "{{ $anythink.trigger.data.requester_email }}",
    "template_type": "ticket_resolved",
    "payload": "{\"first_name\":\"{{ $anythink.trigger.data.first_name }}\",\"subject\":\"{{ $anythink.trigger.data.subject }}\"}"
  }'

payload is a string that holds JSON, so its inner quotes are escaped.

With an AI assistant (MCP)

Create a workflow called ticket-resolved that runs when a record in tickets is updated and its status changes to resolved. Add a Send An Email step with the key send_resolved that emails the ticket's requester_email using the ticket_resolved template, with first_name and subject filled from the ticket. Make it the start step and enable the workflow.

The assistant runs workflows create with a filter, then workflows step-add, through the cli tool.

How it works:

  • changed_to compares the record before and after the update. It matches once, when status moves to resolved, not on every later edit.
  • payload supplies the template's own variables. A key the template doesn't use is ignored.
  • The step queues one email for one recipient. It refuses to send if any value still contains {{, so a typo fails the job instead of emailing a placeholder.

Send a push when an order ships

Goal: tell the customer when their order's status becomes shipped.

Before you start: set up push delivery and register your app's devices. See Push notifications from a workflow. You need an orders entity with a status text field and a user_id integer field holding the customer's user id.

Key Step Why
notify Send a Push Notification Sends to the customer's devices

In the Anythink dashboard

  1. Open Workflows and select New Workflow. Name it order-shipped.
  2. Set Event Type to Entity Updated and Entity to orders.
  3. Under Fire only when…, add a filter: status, changed to, shipped.
  4. Select Create Workflow, then Add Step and choose Send a Push Notification. Give it the Key notify.
  5. Choose Custom content. Set the Title to Order {{ $anythink.trigger.id }} has shipped and the Body to Tap to track your delivery.
  6. Under Send to, choose A single user and enter {{ $anythink.trigger.data.user_id }} as the User id.
  7. Save the step, make it the start step, save the workflow and select Enable Workflow.

With the CLI

bash
anythink workflows create order-shipped \
  --trigger Event --event EntityUpdated --entity orders \
  --filter '{"field":"status","op":"changed_to","value":"shipped"}' \
  --enabled

anythink workflows step-add <workflow_id> notify \
  --name "Push customer" --action SendPushNotification --start --enabled \
  --params '{
    "title": "Order {{ $anythink.trigger.id }} has shipped",
    "body": "Tap to track your delivery.",
    "click_action": "myapp://orders/{{ $anythink.trigger.id }}",
    "data": { "order_id": "{{ $anythink.trigger.id }}" },
    "audience": { "kind": "user", "user_id": "{{ $anythink.trigger.data.user_id }}" }
  }'

With an AI assistant (MCP)

Create a workflow called order-shipped that runs when a record in orders is updated and its status changes to shipped. Add a Send a Push Notification step with the key notify that sends "Order" plus the order's id plus "has shipped" to the user in the order's user_id. Make it the start step and enable the workflow.

The assistant runs workflows create and workflows step-add through the cli tool.

How it works:

  • On an update, $anythink.trigger.id is the order's id and $anythink.trigger.data is the updated record, so user_id comes straight from the order.
  • click_action and data travel with the notification, and your app decides what to do with them.
  • The step waits for delivery and reports how many devices it reached. It fails if there is nobody to send to, such as a customer with no registered device, so link its on failure handle if that's a normal outcome.

Clear out expired records every night

Goal: delete every row in sessions whose expires_at has passed, at 03:00 UTC each day.

Before you start: you need a sessions entity with an expires_at timestamp field.

Key Step Why
purge Delete Data Removes every record matching the filter

In the Anythink dashboard

  1. Open Workflows and select New Workflow. Name it purge-expired-sessions.
  2. Set Trigger Type to Timed. Select Use cron expression and enter 0 3 * * *.
  3. Select Create Workflow, then Add Step and choose Delete Data. Give it the Key purge.
  4. Set Entity to sessions. Select Add Filter Condition and set the field to expires_at, the operator to less than and the value to {{ $anythink.now }}.
  5. Save the step, make it the start step, save the workflow and select Enable Workflow.
  6. To try it now, select Test Workflow in the editor.

With the CLI

bash
anythink workflows create purge-expired-sessions \
  --trigger Timed --cron "0 3 * * *" --enabled

anythink workflows step-add <workflow_id> purge \
  --name "Delete expired sessions" --action DeleteData --start --enabled \
  --params '{
    "entity_name": "sessions",
    "filter_conditions": [
      { "field": "expires_at", "operator": "lt", "value": "{{ $anythink.now }}" }
    ]
  }'

anythink workflows trigger <workflow_id>
anythink workflows jobs <workflow_id>

The last two commands run the workflow once now and show its job.

With an AI assistant (MCP)

Create a workflow called purge-expired-sessions that runs every day at 03:00 UTC. Add a Delete Data step with the key purge that deletes records from sessions where expires_at is earlier than the current time. Make it the start step and enable the workflow, then run it once and show me the job.

The assistant runs workflows create, workflows step-add, workflows trigger and workflows jobs through the cli tool.

How it works:

  • Schedules are in UTC and checked once a minute. A run that was missed isn't made up later.
  • {{ $anythink.now }} is read when the step runs, so each night compares against that moment.
  • Delete Data removes every match and requires at least one filter condition, so it can't empty an entity by accident.
  • Preview the filter first. Use a Read Data step with the same condition, or run the equivalent anythink data list command, and check what comes back.
  • A scheduled job has no record behind it, so $anythink.trigger.data is empty. Everything the step needs comes from its own parameters.

Create or update a record from a partner's webhook

Goal: accept orders from a partner's system over HTTP, creating a record for a new order and updating the record when the partner sends the same order again.

Before you start: you need a partner_orders entity with a unique partner_ref text field, plus status, total and customer_email fields. Give the partner its own API key with only the anythink_workflows:trigger permission. See Webhooks and API keys.

Key Step Why
upsert_order Upsert Data Matches on the partner's reference, then updates or creates

In the Anythink dashboard

  1. Open Workflows and select New Workflow. Name it partner-order.
  2. Set Trigger Type to API Call and enter the API Route partner-order, without a leading slash.
  3. Select Create Workflow, then Add Step and choose Upsert Data. Give it the Key upsert_order.
  4. Set Entity to partner_orders, Match On to partner_ref, On Match to Update and Update Fields to status and total.
  5. Set the Payload:
json
{
  "partner_ref": "{{ $anythink.trigger.data.order_id }}",
  "status": "{{ $anythink.trigger.data.status | default: \"received\" }}",
  "total": "{{ $anythink.trigger.data.total }}",
  "customer_email": "{{ $anythink.trigger.data.customer.email }}"
}
  1. Save the step, make it the start step, save the workflow and select Enable Workflow.

With the CLI

bash
anythink workflows create partner-order \
  --trigger Api --api-route partner-order --enabled

anythink workflows step-add <workflow_id> upsert_order \
  --name "Upsert order" --action UpsertData --start --enabled \
  --params '{
    "entity_name": "partner_orders",
    "match_on": ["partner_ref"],
    "on_match": "Update",
    "update_fields": ["status", "total"],
    "payload": "{\"partner_ref\":\"{{ $anythink.trigger.data.order_id }}\",\"status\":\"{{ $anythink.trigger.data.status | default: '"'"'received'"'"' }}\",\"total\":\"{{ $anythink.trigger.data.total }}\",\"customer_email\":\"{{ $anythink.trigger.data.customer.email }}\"}"
  }'

Test it the way the partner will, with the route and a key:

bash
curl -X POST "https://api.my.anythink.cloud/org/$PROJECT_ID/workflows/api/partner-order" \
  -H "x-api-key: $ANYTHINK_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"order_id":"ord_1001","total":42.5,"customer":{"email":"ada@example.com"}}'

Expect 204 No Content. Send it again with "status":"shipped" and "total":45. There is still one record, now with the new status and total.

With an AI assistant (MCP)

Create a workflow called partner-order with an API trigger on the route partner-order. Add an Upsert Data step with the key upsert_order for partner_orders that matches on partner_ref and, on a match, updates status and total. Fill the record from the request body: order_id into partner_ref, status (default "received"), total and customer.email. Make it the start step and enable the workflow.

The assistant runs workflows create and workflows step-add through the cli tool.

How it works:

  • The JSON body the partner sends becomes $anythink.trigger.data, and paths such as customer.email reach into it.
  • match_on makes the webhook safe to repeat: the same order_id updates its record and never creates a second one. The unique partner_ref field backs that up at the database.
  • update_fields limits what a repeat call can overwrite, so edits your team makes to other fields survive.
  • The response is 204 as soon as the job is queued. It doesn't say whether the upsert worked, so check the workflow's job history. If the partner needs an answer, have it read the record afterwards.

Chain workflows with a record write

Goal: when an order is paid, create an invoice record. Then a second workflow notices the new invoice and marks the order as invoiced.

Before you start: you need an orders entity with total (decimal), status (text) and invoiced (boolean) fields, and an invoices entity with order_id (integer) and amount (decimal).

There is no step that calls another workflow. Instead, a Create Data or Update Data step writes a record, and that write starts any workflow with an event trigger on the entity. Two workflows hand over through the data.

Workflow Trigger Step
raise-invoice orders updated, status changed to paid Create Data on invoices
mark-invoiced invoices created Update Data on orders

In the Anythink dashboard

  1. Create the workflow raise-invoice. Set Event Type to Entity Updated and Entity to orders. Under Fire only when…, add status, changed to, paid.
  2. Add a Create Data step with the Key create_invoice. Set Entity to invoices and the Payload:
json
{
  "order_id": "{{ $anythink.trigger.id }}",
  "amount": "{{ $anythink.trigger.data.total }}"
}
  1. Make it the start step, save, and select Enable Workflow.
  2. Create a second workflow, mark-invoiced. Set Event Type to Entity Created and Entity to invoices.
  3. Add an Update Data step with the Key mark_invoiced. Set Entity to orders, Record ids to {{ $anythink.trigger.data.order_id }} and the Payload to { "invoiced": true }.
  4. Make it the start step, save, and select Enable Workflow.

With the CLI

bash
anythink workflows create raise-invoice \
  --trigger Event --event EntityUpdated --entity orders \
  --filter '{"field":"status","op":"changed_to","value":"paid"}' --enabled

anythink workflows step-add <raise_invoice_id> create_invoice \
  --name "Create invoice" --action CreateData --start --enabled \
  --params '{"entity_name":"invoices","payload":"{\"order_id\":\"{{ $anythink.trigger.id }}\",\"amount\":\"{{ $anythink.trigger.data.total }}\"}"}'

anythink workflows create mark-invoiced \
  --trigger Event --event EntityCreated --entity invoices --enabled

anythink workflows step-add <mark_invoiced_id> mark_invoiced \
  --name "Mark order invoiced" --action UpdateData --start --enabled \
  --params '{"entity_name":"orders","ids":"{{ $anythink.trigger.data.order_id }}","payload":"{\"invoiced\":true}"}'

Try it: create an order, then set its status to paid.

bash
anythink data create orders --data '{"customer_email":"sam@example.com","total":149.50,"status":"new","invoiced":false}'
anythink data update orders 1 --data '{"status":"paid"}'
anythink data list invoices
anythink data get orders 1

Within a few seconds invoices has one row with amount 149.5 and order 1 shows invoiced as true. Both workflows have one successful job.

With an AI assistant (MCP)

Create two workflows. The first, raise-invoice, runs when a record in orders is updated and its status changes to paid, and has a Create Data step that adds an invoices record with order_id set to the order's id and amount set to its total. The second, mark-invoiced, runs when an invoices record is created and has an Update Data step that sets invoiced to true on the order whose id is the invoice's order_id. Enable both.

The assistant runs workflows create and workflows step-add for each workflow through the cli tool.

How it works:

  • $anythink.trigger.id is the order's id, and amount keeps its number type because the template is the whole value.
  • In mark-invoiced, the new invoice is the trigger data, so order_id leads back to the order.
  • The second workflow updates orders, which is the entity the first one watches. The changed to paid filter is what stops a loop: the update changes invoiced, not status, so raise-invoice doesn't start again.
  • Always give a workflow that writes to its own trigger entity a filter that its write can't satisfy. A workflow also has a limit of 250 steps per job.
  • The two jobs run on their own, so there is no guaranteed order and no shared failure. Each has its own entry in View Job History.

Next steps