Actions
An action is what Gordon CRM does automatically when a matching trigger fires. Each action targets a specific
entity via its action_id — either a tag or a campaign.
Gordon CRM supports seven action types, split into five categories.
Tag Actions
Tag actions modify a contact's tags. These are the most common automation actions and appear on the central
Automations page (/automations).
Add Tag
| action_type | add_tag |
| action_id | The UUID of the tag to apply |
| Behavior | Adds the specified tag to the contact. Uses UPSERT with ON CONFLICT … DO NOTHING for idempotency — if the contact already has the tag, the operation is silently skipped. |
After a tag is successfully added, the engine fires a cascading tag_applied trigger for the newly added tag.
This enables chaining — for example, adding tag A can trigger a rule that enrolls the contact in a campaign.
Form submitted
→ Action: Add "VIP" tag
→ Cascading trigger: "VIP" tag applied
→ Action: Enroll in "VIP Welcome" campaignImportant: Cascading tag triggers increment an internal depth counter. If the depth exceeds 3, the chain is terminated to prevent infinite loops. See Loop Protection.
Remove Tag
| action_type | remove_tag |
| action_id | The UUID of the tag to remove |
| Behavior | Removes the specified tag from the contact. If the tag was not applied, the operation is silently skipped. |
After a tag is successfully removed (confirmed by checking the return value), the engine fires a cascading
tag_removed trigger. This allows exit workflows — for example, removing a "Member" tag can unenroll a
contact from member-only campaigns.
Campaign Actions
Campaign actions manage a contact's enrollment in drip sequence campaigns. These rules are managed on each
Campaign detail page (/campaigns/[id]) and are excluded from the central Automations page.
Enroll in Campaign
| action_type | enroll_campaign |
| action_id | The UUID of the campaign |
| Behavior | Creates a campaign_enrollments row for the contact with status: active. Uses the campaign engine to calculate the first eligible step and its scheduled next_action_at timestamp. |
The enrollment process includes multiple safety checks:
- Active enrollment check — If the contact already has an
activeorprocessingenrollment in the same campaign, the action is skipped entirely. - Trigger event dedup — If a
triggerEventIdis provided (e.g., from an event registration), the engine checks for a priorcompletedenrollment with the same trigger event ID. This prevents webhook retries from re-enrolling contacts. - Campaign status check — The campaign itself must be in
activestatus. Draft or paused campaigns will not accept new enrollments. - Step calculation — The campaign engine's
calculateNextCampaignStepfunction determines when the first email should be sent based on delay offsets and event dates. If all steps are in the past (late enrollee), the enrollment is immediately marked ascompleted.
Remove from Campaign
| action_type | remove_campaign |
| action_id | The UUID of the campaign |
| Behavior | Sets the contact's active enrollment to status: cancelled and records a cancelled_at timestamp. Only cancels enrollments with active or processing status. |
This is typically used as part of an exit criteria workflow on the campaign detail page — for example, "When the contact is tagged as 'Unresponsive' → remove from this campaign."
Where Actions Are Managed
| Action Type | Managed On | Why |
|---|---|---|
add_tag, remove_tag | Automations page (/automations) | General-purpose rules, not tied to a specific campaign |
enroll_campaign, remove_campaign | Campaign detail page (/campaigns/[id]) | Tightly coupled to campaign lifecycle; entry/exit criteria belong with the campaign |
create_task | Automations page (/automations) | Task creation rules are general-purpose, similar to tag rules |
send_notification | Automations page (/automations) | Internal alerts are general-purpose operational rules |
This split keeps the UI focused — marketers manage campaign enrollment rules alongside the campaign itself, while system-level tag automations, task creation, and notification rules live in a central hub.
Task Actions
Task actions automatically create to-do items in response to triggers. These rules are managed on the central
Automations page (/automations).
Create Task
| action_type | create_task |
| action_id | A generated UUID (ensures uniqueness — allows multiple create_task rules per trigger) |
| action_config | Inline JSONB configuration (see below) |
| Behavior | Creates a new task row linked to the triggering contact, with title, description, assignee, and a calculated due date from the action config. |
Unlike tag and campaign actions — which point action_id at a pre-existing entity (a tag or campaign) — the
create_task action has no pre-existing entity to reference. The task doesn’t exist until the automation fires.
Inline action_config
When action_type = 'create_task', the action_config JSONB column stores the task blueprint:
{
"title": "Follow up with new lead",
"description": "Review form submission and send intro email",
"assigned_to": "user-uuid-or-null",
"due_offset_hours": 48
}| Field | Type | Description |
|---|---|---|
title | string | The task title (defaults to "Follow up" if not set) |
description | string | Optional task description |
assigned_to | uuid | null | The workspace member to assign the task to |
due_offset_hours | number | Due date offset in hours from trigger time (e.g. 48 = 2 days from now) |
Why inline config instead of task templates? A task template table would require its own CRUD surface, RLS policies, and navigation entry — all for something used rarely. Inline
action_configon the automation rule itself keeps the design simple with zero new tables. Users who need the same task config on multiple rules can manually recreate the rule with the same settings.
Contact and Deal Linking
When the automation fires:
- Contact is always auto-linked from the trigger’s
contactId(every trigger provides a contact context). - Deal is auto-linked from the trigger context when available (e.g.
deal_stage_changedtriggers). - Due date is calculated as
trigger_time + due_offset_hours.
UI Form
When a user selects "Create Task" as the action type on the Automations page, the standard entity picker is replaced with an inline form:
| Field | Input | Description |
|---|---|---|
| Task Title | Text input | Required — the title of the task to create |
| Description | Text input | Optional details |
| Assign To | Dropdown (workspace members) | Who gets assigned |
| Due In | Number input + "hours after trigger" | When the task is due |
Action Entity Resolution
When displaying rules in the UI, the engine resolves action_id values to human-readable names:
| Action Type | Resolution Strategy |
|---|---|
add_tag / remove_tag | Tag name from the tags table |
enroll_campaign / remove_campaign | Campaign name from the campaigns table |
create_task | Task title from action_config.title |
send_agreement | Template title from the agreement_templates table |
send_notification | Recipient names from workspace member profiles |
Agreement Actions
Agreement actions dispatch digital agreements to a contact for signing.
Send Agreement
| action_type | send_agreement |
| action_id | The UUID of the agreement template |
| action_config | {"template_id": "uuid"} |
| Behavior | Dispatches the specified agreement template to the contact via email with a tokenized signing link. |
Dedup Behavior
The dispatch service applies the same dedup logic as manual sending:
| Existing State | Result |
|---|---|
| Signed at current version | Silently skipped (no email, no new record) |
| Signed at older version | New pending agreement created for the current version |
| Pending | Existing token resent (acts as a reminder) |
| No existing record | New pending agreement created |
UI Form
When a user selects "Send Agreement" as the action type on the Automations page, the standard entity picker is replaced with a template dropdown listing all active agreement templates. If no active templates exist, italic helper text reads: "No active templates. Create one in Settings → Agreement Templates."
See Agreements for full documentation on template management and the signing flow.
Notification Actions
Notification actions send internal email alerts to workspace members (and optionally external recipients) when a trigger fires. These are managed on the central Automations page.
Send Notification
| action_type | send_notification |
| action_id | A generated UUID (same pattern as create_task) |
| action_config | Inline JSONB configuration (see below) |
| Behavior | Sends an internal notification email to all configured recipients with contact details and trigger context. |
Inline action_config
When action_type = 'send_notification', the action_config JSONB column stores the
recipient configuration:
{
"member_ids": ["user-uuid-1", "user-uuid-2"],
"external_emails": ["partner@example.com"]
}| Field | Type | Description |
|---|---|---|
member_ids | uuid[] | Workspace members to notify (resolved to their email addresses at send time) |
external_emails | string[] | Additional email addresses outside the workspace |
At least one recipient (member or external) is required.
What the Email Contains
Notification emails automatically include:
- Contact details — The name and email of the contact who triggered the automation.
- Trigger context — Which trigger fired (e.g. "Form submitted: Request a Demo").
- Deal enrichment — When triggered by a deal event (
deal_stage_changedordeal_status_changed), the email also includes the deal name and deal value (formatted as currency).
UI Form
When a user selects "Send Internal Notification" as the action type on the Automations page:
| Field | Input | Description |
|---|---|---|
| Notify Members | Member picker (multi-select) | Select one or more workspace members |
| External Emails | Text input with chip display | Type an email address and press Enter to add it |