Skip to content

Automation rules

An automation rule tells BottleCRM "when this happens to a record, and these things are true, do that". When a deal is won, create a kick-off task for its assignees and tell the account's team. When a lead arrives from a web form, assign it to the next person in a rotation. Rules arrived in django-crm 1.21.0, with their screens on the web and the phone in 1.22.0. Everything lives in backend/automation/, and rules are managed through the API at /api/automation/.

Who can use them

Only org admins can build, read, change, try or delete rules, and that includes the list and the run history: runs name records and people a member may not be allowed to see. A member gets 403 on every route.

Rules are managed from a signed-in session only. A personal access token or the org API key is refused at /api/automation/ whatever scopes it carries, because a rule keeps acting after the token that wrote it is revoked. Creating one is the same kind of act as creating a webhook.

Building rules in the apps

Admins build rules under Settings, Automation, in the web app and in the phone app. The row is hidden from members.

  • The list shows every rule in order with its status (on, off, paused, not running, or needs attention), the reason beneath when there is one, and its runs and failures over the last seven days. Up and down arrows change a rule's place. New rule starts one: pick a name and the kind of record to watch, then save. A rule is switched on or off in the editor (Save and switch on, Switch off). On a paused rule the button reads Save and take over: switching it on makes you its owner.
  • The editor reads as the rule does: When, Only if, Then. Fields, options, people and webhooks come from your org, so only what it offers can be chosen. A value that was valid when saved and no longer is stays visible, marked "(no longer available)".
  • Try it on a record picks a record and shows what a run would do, writing nothing. It uses the saved rule, so it is disabled while the editor has unsaved changes. It shows what the actions would do and does not check the trigger or the conditions.
  • Run history lists the rule's runs, newest first. Each run opens to its steps.

What a rule is

Part Meaning
Name What the rule is called in lists, notices and the activity feed.
Object The kind of record it watches: lead, contact, account, deal, ticket or task. Fixed once the rule exists.
When The trigger: see Triggers below.
Only if Up to 20 conditions, matched all (every one holds) or any (at least one does). One level, no groups. No conditions always holds.
Then Up to 10 actions, run in order: see Actions below.
Owner The admin who last switched it on. The rule acts as this person.

Rules are checked against what the org offers when they are saved and again before every run, so a rule cannot set a field or an option its record's edit form would refuse, and cannot name a person, webhook or link outside its org.

A rule that was valid and later breaks (its field was switched off, an option was removed, its person was deactivated) stays saved and switched on. Its runs fail with the reason, the list shows it as Needs attention, and saving or switching it on again checks it afresh. Renaming it or switching it off always works.

Fields

Object Fields a rule can read
Lead title, first and last name, email, phone, company, job title, website, city, country, status, source, industry, rating, stage (read only), estimated value, probability, expected close date, next follow-up, assigned to
Contact first and last name, email, phone, company, job title, department, city, country, do not call, assigned to
Account name, email, phone, website, city, country, industry, employees, annual revenue, assigned to
Deal name, stage, outcome (read only), type, source, amount, probability, close date, assigned to
Ticket subject, status, priority, type, closed on, assigned to
Task title, status, priority, due date, assigned to

Your org's active custom fields of types text, textarea, number, date, dropdown and checkbox are added to their object. A field can be set by a rule exactly when the object's own edit form writes it. Server-owned fields (ids, the org, who created a record, timestamps) are never offered.

  • Deal stage lists every pipeline's stages, grouped by pipeline. A rule can only move a deal to a stage of the deal's own pipeline.
  • Deal outcome is open, won or lost, read from the kind of the deal's stage, so "outcome changes to won" fires for a win in any pipeline, whatever the stage is called.
  • Lead status offers converted to read but not to set: converting a lead creates an account, a contact and a deal, and is never an edit. Ticket status treats Duplicate the same way, since only a merge sets it.
  • Assigned to can be read and set, but a change of people cannot be a trigger.

Actions can also reach the record's one parent: a deal's account, a ticket's account, or the lead, account, deal or ticket a task belongs to. Leads, contacts and accounts have no parent.

Triggers

Trigger Fires when
Created A record of the object is created.
Updated Any field a rule can read changed.
A field changes That field changed, to anything.
A field changes to a value That field moved into the value.

"Changes to" fires only on the move into the value: the old value differed and the new one matches. Later edits to a won deal do not run "outcome changes to won" again.

What sets a rule off: any save made through the app. That covers the web and phone apps, the REST API and access tokens, a card moved to another column on a board, a public web form submission, an emailed ticket, and saves made by background jobs. A "created" rule fires on web forms and inbound email even though nobody is signed in.

Rules run as the request finishes, after everything in it was saved, so the page that reloads after a save already shows what the rules did, and a condition such as "assigned to is not empty" sees assignees set in the same save. Ticket routing runs first, so a "ticket created" rule sees the routed assignees. A change that was rolled back sets nothing off.

What does not set rules off:

  • Spreadsheet imports of leads, contacts and tickets, and industry pack sample data as the pack creates it. A 2,000-row import with an active "lead created: create a task" rule creates no tasks.
  • The seed_data management command.
  • Bulk ticket edits. Closing 200 tickets at once runs no rules.
  • Bulk database operations that skip save signals, such as the moves inside a ticket merge.
  • Changes to assignees, tags or teams on their own. Conditions can still read them.
  • Deleting a record. Webhooks cover deletes.

Conditions

Type Operators
Text is, is not, contains, does not contain, is empty, is not empty
Number is, is not, is more than, is less than, is empty, is not empty
Date is, is not, is after, is before, is empty, is not empty
Choice is, is not, is any of, is none of, is empty, is not empty
Yes or no is true, is false
Person, people is exactly, includes, does not include, is empty, is not empty
  • Text comparison with contains ignores case. Dates are fixed dates; relative dates ("in the next 7 days") are not offered.
  • was and was not compare the value from before this save, on any field except people, and only for an "updated" trigger.
  • There is no pattern or regular expression operator. Text you or your customers type is only ever compared, never evaluated.

Actions

A rule's actions run in order inside one transaction, so a later action sees what an earlier one did: assign someone, then notify the record's assignees, and the notice reaches the new assignee.

{name} is the only placeholder, in task titles and notify messages. It is replaced by the record's display name as plain text. Nothing is rendered as a template, markdown or HTML.

  • Set a field on the record or its parent. Clearing is allowed. The write goes through the object's own edit path as the rule's owner, so it passes exactly the checks the edit form applies: a deal moved to a won stage still needs an amount and a close date, and a lead cannot be converted. A record with no parent is a skipped step, not a failure.
  • Assign to one person (replace), or in turn between 2 and 20 people (rotate), skipping anyone no longer active. Either way the record's current assignees are replaced, and the newly assigned get the module's usual assignment email.
  • Create a task with a title of up to 200 characters, an optional due date 0 to 365 days from today in the org's timezone, a priority (Low, Medium or High), and assignees: the record's, the parent's, the rule's owner, or one person. It links to the record where a task can.
  • Notify the record's assignees, its creator, the parent's assignees, the org's admins, or people you pick, with a message of up to 500 characters. Each gets an in-app notification and an email with a link to the record. Only active members of the org are ever reached; there is no way to send to an outside address.
  • Send a webhook to one of the org's own active webhooks with the Signed JSON format, as a rule.triggered event. Signing, the URL rules, retries and the delivery log are the same as for every other webhook.

Notify and create a task reach only people who can open the record. Deals and leads are often private to their assignees, so anyone filtered out is named in the step ("Skipped Meera: cannot open this deal"), and when nobody is left the step is skipped, not failed.

How a run happens

  • Order. For each change, every matching switched-on rule on that object runs, in list order. There is no "stop here".
  • One rule, one transaction. If any step fails, that rule's writes roll back, the run is recorded as failed with the reason, and the next rule still runs. Emails and webhooks go out only once the rule's transaction commits. A broken rule never blocks or undoes the save that set it off.
  • Who it acts as. The rule's owner. Records it creates and fields it sets are credited to the owner, and the activity feed notes the rule's name beside the change.
  • Chains. A rule's own writes can set off other rules, up to 3 deep. A rule acts on a given record at most once per chain, and never on a change its own run made.
  • Owners who lose their rights. When a rule's owner stops being an admin, is deactivated or leaves the org, their active rules are switched off with a reason and the other admins are told. Another admin takes a rule over by switching it on again.
  • Failures reach a person. When a run fails, the rule's owner gets an in-app notice, at most once a day per rule.

Limits

The same on every install:

Limit Value
Conditions per rule 20
Actions per rule 10
Records one action may touch 100 (more fails the step rather than doing part of it)
Chain depth 3
Runs per org per hour 1,000
Run history 30 days

Runs past the hourly limit do not run. Each rule gets one skipped run per hour that counts them, and the org's admins get one notice for that hour.

The open-source code puts no limit on how many rules are switched on. On the hosted app at app.bottlecrm.io an organisation can have three rules switched on at a time for now; switching on a fourth is refused with the reason, and the list says so.

Runs and notifications

Each run records the record it ran on (with its name at the time), its status, its reason, and one step per action. A run is done, failed (a step failed and nothing it wrote was kept) or skipped (counted past the hourly limit). A step is done, undone (rolled back with its failed rule), failed, or skipped.

Rules send four kinds of in-app notification: a notify action's message, a failed run (to the owner), paused rules (to the other admins) and the hourly limit (to the admins).

The API

All under /api/automation/, admin only, from a signed-in session:

Method and path Does
GET catalogue/ objects with their fields, parents and links; operators; action types; the org's active members and Signed JSON webhooks; the limits
GET rules/ the org's rules, each with status, status_text, runs_7d and failures_7d
POST rules/ create, at the end of the list
GET rules/<id>/ one rule
PATCH rules/<id>/ change it (there is no PUT)
DELETE rules/<id>/ delete it and its runs
POST rules/<id>/try/ the steps a run would take on one record, writing nothing
GET rules/<id>/runs/ its runs, newest first, limit/offset paginated
POST rules/reorder/ a new list order: {"ids": [...]}

Another org's id answers 404. An invalid rule is refused with a 400 whose errors are keyed by path, such as conditions[2].value, so an editor can mark the row. The headline example, created and switched on in one request:

{
  "name": "Deal won: onboarding",
  "object_key": "deal",
  "trigger": {"event": "updated", "field": "stage_kind", "to": "won"},
  "match": "all",
  "conditions": [{"field": "amount", "op": "gt", "value": 0}],
  "actions": [
    {
      "type": "create_task",
      "title": "Kick-off call: {name}",
      "due_in_days": 2,
      "priority": "High",
      "assign_to": "record",
      "person": null
    },
    {
      "type": "notify",
      "to": ["parent_assignees"],
      "people": [],
      "message": "{name} is won. Time to say hello."
    }
  ],
  "is_active": true
}

The full field-by-field reference, with every operator and action body, is docs/integrations/automation.md in the Django-CRM repository.

Not built

  • Schedules. A rule runs when a record changes, never on a date or after a delay.
  • Branching. One level of conditions, all or any, with no groups and no if-else.
  • Email to people outside your org.
  • Deletes as a trigger.