Workflows are "when X happens → do Y automatically" rules. They run in the background whenever something happens in your CRM and execute a chain of actions on your behalf. Think auto-tagging new leads, follow-up reminders after a deal closes, auto-notes when a contact is created — anything you'd otherwise do by hand every time.
Find them in Settings → Workflows.
Starter templates (fastest way in)
Click Browse templates next to "New workflow" to pick from six pre-built automations. Each one opens the editor pre-populated — you tweak the bits that mention "CHANGE-ME" (or just review the steps), then save.
Templates that ship today:
- Tag imported contacts — applies the
importedtag to any contact whose source mentions "Imported" - SMS auto-reply — replies to every inbound SMS with "got it, will follow up shortly"
- Welcome email to new contacts — sends a personalized welcome email when a contact is created with an email address
- Notify me when a deal is won — emails you the moment a deal moves to the Won stage
- Follow-up task after inbound call — auto-creates a "call back" task whenever someone calls you
- Daily 9 AM digest webhook — POSTs to a webhook (Slack, Zapier, anything) every weekday at 9 AM in your local time
If a template doesn't fit, start with the closest one and edit it — that's usually faster than starting from scratch.
Anatomy of a workflow
Every workflow has three parts:
-
Trigger — what fires it. Options:
- When something happens (entity event) — see the full list of supported events below
- On a schedule — once / hourly / daily / weekly in your local timezone
- When an inbound webhook arrives — chained off Settings → Webhooks → Inbound
- When I run it manually — a Run button on the workflow row
-
Condition (optional) — gates execution. "Only run if all of these are true": a list of field/operator/value rules. Supported operators:
equals,not_equalscontains,not_contains,starts_withis_set,is_emptyincludes_tag(only on contact/company/deal triggers)
Field paths reference the trigger context:
entity.first_name,entity.email,entity.source, etc. — direct columns on the triggered entityentity.tags— the entity's tag list (used withincludes_tag)trigger.payload.<field>— anything in the event payload
-
Actions — what to run, in order. Each action has a type + a config:
- Apply tag / Remove tag —
{ tag_name }. Defaults to the trigger entity. - Create task —
{ title, description?, due_in_days? }. Auto-links to the contact when one's in the trigger. Title supports template variables likeFollow up with {{first_name}}. - Create note —
{ body }. Drops on the trigger entity. Template variables supported. - Update field —
{ entity_type, field, value }. Safe-column allowlist enforced per entity (can't rewrite system columns likeuser_id). - Send SMS —
{ body, to?, contact_id? }. Sends through your default Twilio number. If you leavetoblank, it uses the contact from the trigger. US/CA destinations only. Honors STOP opt-outs and account suspension. - Send email —
{ to, subject, body_html?, body_text?, from_name? }. Sends through your default email account (Settings → Email integration). Template variables work in every field. - Fire webhook —
{ url, method?, body? }. Custom POST to a URL of your choice. Default body is{ trigger, entity }. 15-second timeout per call.
- Apply tag / Remove tag —
Scheduled triggers
Pick "On a schedule" and choose a recurrence:
- Once — fires at a specific date/time, then never again
- Every hour — fires at minute N of every hour (e.g. :15 of every hour)
- Every day — fires at a time-of-day in your timezone
- Every week — fires on selected weekdays (M T W T F S S chips) at a time-of-day
The editor shows a "Next runs: …" preview as you set things up — you see the next 4 fire times before you save. Timezone defaults to your browser's IANA tz so "daily 9 AM" means 9 AM where you are, not UTC.
Scheduled workflows fire WITHOUT an entity in context — so steps like "apply tag" or "update field" will skip (no entity to apply to). The actions that work for scheduled are:
- Fire webhook — perfect for daily Slack pings or Zapier triggers
- Send SMS / Send email to a hardcoded recipient — daily check-in to a partner, weekly status email to yourself
Template variables
Action configs that take text can reference fields from the trigger entity:
{{first_name}},{{last_name}},{{full_name}},{{email}},{{phone}}{{entity.<column>}}— any column on the triggered entity{{trigger.payload.<field>}}— anything the trigger event carried
Unknown variables render as empty strings so a missing first_name doesn't break a bulk-run on 50 contacts.
Example: auto-tag new leads from Facebook
- Name: "Auto-tag FB leads"
- Trigger: When something happens →
contact.created - Condition:
entity.sourceequalsfacebook-lead-ads(only when the inbound webhook tagged the source) - Actions:
- Apply tag →
lead - Create task → "Call {{first_name}} within 24h" — due_in_days = 1
- Apply tag →
- Save → it's live. Next FB lead that comes in via your inbound webhook gets tagged AND becomes a follow-up task automatically.
Example: auto-note when a deal closes won
- Name: "Won deal logger"
- Trigger:
deal.stage_changed - Condition:
trigger.payload.is_wonequalstrue - Action: Create note → "🎉 Closed-won on {{entity.title}}. {{trigger.payload.to_stage_name}}."
- Now every won deal auto-drops a note on the deal record. Audit trail forever.
Run history
Click any workflow row to expand its run history — every time it fired, what status (completed / skipped / failed), which step did what, and any error messages. Useful for debugging when a workflow doesn't seem to do what you expect.
Reliability
- Non-blocking. Workflows fire after the originating event (contact-create returns immediately; the workflow runs in the background). A broken workflow can never block your CRM writes.
- Per-step error capture. If step 3 of 5 fails, the run records the error and aborts the rest. You see exactly which step blew up in the run history.
- Auto-pause at 20 failures. Same pattern as outbound webhooks. If a workflow fails 20 times in a row, we pause it and surface the error. Fix the issue + re-enable from the row — the counter clears automatically.
- No silent data loss. Field updates are gated by a per-table allowlist so no workflow can ever rewrite
user_id,created_at, or anything else system-managed. If a workflow tries, the run shows the rejection in its step results.
Currently supported triggers
These entity events fire workflows today:
- Contacts —
contact.created,contact.updated,contact.deleted - Companies —
company.created,company.updated,company.deleted - Deals —
deal.created,deal.stage_changed,deal.updated,deal.deleted - Tasks —
task.created,task.completed,task.updated,task.deleted - Notes —
note.created - SMS —
sms.sent,sms.received - Email —
email.sent - Calls & voicemail —
call.completed,voicemail.received - Tags —
tag.applied
For comms events (SMS / email / call / voicemail) the engine auto-resolves the related contact into the entity context — so you can write conditions like "if contact has tag 'VIP' AND it's an inbound SMS" without any extra wiring.
Limits
- 50 workflows per account. More than enough for any plausible use case; if you hit it, delete or consolidate.
- Per-step delay capped at 60 seconds inline. True multi-day delays use scheduled workflows instead.
- Send SMS is gated by the same checks as manual SMS: STOP opt-outs, account suspension, credit balance, US/CA only. The run row records the reason if a send was blocked.
- Send email uses your first configured email account. The account-aliases mechanism (
from_emailoverride) works the same way as the manual email composer.
Tips: editing + duplicating
Each workflow row has:
- Edit (pencil) — opens the editor for the existing workflow
- Duplicate (copy) — opens the editor with a deep-cloned definition as a new draft, named "<original> (copy)" and inactive by default
- Pause / Resume — toggles
is_active. Paused workflows ignore their trigger entirely. - Delete (trash) — soft-deletes the row. Run history stays for forensics; no future events trigger it.
Inside the editor, the step list has up/down arrows next to each step so you can reorder without rebuilding.
Editing a running workflow
Edits take effect immediately for the next run. In-flight runs that triggered before you saved keep using the previous definition. Run history records the state at fire time, so you'll always be able to see what definition each run used.