Create Support Rule
POST/api/support/admin/rules
Creates an automation rule: a trigger, a list of conditions that must all match, and a list of actions run in order. New rules are never built-in (is_system: false). When position is omitted the rule is placed after the last existing rule.
support:writeGrant this scope to your token under Settings → Developer → Personal Access Tokens.
Request body
name(string, required, max 120) — the rule name; also the actor label stamped on the ticket events it records. Whitespace is trimmed.trigger(string, required) — one of: ticket_created, ticket_updated, customer_replied, agent_replied, hourly.conditions(object[], required — may be empty, max 20) — every row must hold for the rule to match;[]means "always".actions(object[], required, 1 to 20) — what to do when the rule matches.is_active(boolean, optional) — whether the rule runs. Default: true.position(integer, optional, nullable, min 0) — run order within the trigger, lowest first. Default: after the last rule.
Condition rows (conditions[], max 20; send [] for "always")
conditions[].field(string, required) — one of: status, priority, type, group_key, tenant_id, assignee_user_id, tags, subject, body, subject_or_body, requester_email, source, hours_since_status_change, hours_since_last_customer_message, hours_since_last_agent_message, sla_breached, sla_breaching_soon. Field value types: enum (status,priority,type,group_key,source), tenant (tenant_id), user (assignee_user_id), list (tags), text (subject,body,subject_or_body), string (requester_email), number (hours_since_status_change,hours_since_last_customer_message,hours_since_last_agent_message— decimal hours), bool (sla_breached,sla_breaching_soon).bodyis the message that triggered the rule when there is one, otherwise the ticket's opening message.conditions[].operator(string, required) — one of: is, is_not, in, not_in, contains, not_contains, matches, is_empty, is_not_empty, gt, gte, lt, lte. The operator must fit the field's value type:is/is_notapply to enum, string, text, bool, user, tenant and number;in/not_into enum, string, user and tenant;contains/not_containsto text, string and list;matchesto text and string;is_empty/is_not_emptyto enum, string, text, list, user and tenant;gt/gte/lt/lteto number.conditions[].value(mixed, nullable) — required unless the operator isis_empty/is_not_empty. A single value foris/is_not/matchesand the numeric operators; an array (or comma-separated string) forin/not_in/contains/not_contains. Enum fields accept their listed values only (statuses: open, in_progress, waiting_on_customer, awaiting_release, resolved, closed; priorities: low, medium, high, urgent; types: bug, question, feature_request, billing; sources: app, email, api, assistant, agent, import; groups: an existing group key). Numeric operators need a number;matchesneeds a valid regular expression (a plain pattern is treated as case-insensitive; a delimited/pattern/flagspattern is used as written); bool fields taketrue/false. Comparisons are case-insensitive and trimmed;containsontagsmatches when any listed tag is present, on text when any listed substring occurs;isontagsrequires the exact same set.
Action rows (actions[], 1 to 20, run in order)
actions[].type(string, required) — one of: set_status, set_priority, set_type, set_group, assign_to, assign_replier_if_unassigned, add_tags, remove_tags, add_watchers, add_tenant_default_watchers, notify_assignee, notify_slack, send_customer_notice, add_internal_note, mark_important.actions[].value(mixed, nullable) — depends on the type:set_statusone of open, in_progress, waiting_on_customer, awaiting_release, resolved, closed;set_priorityone of low, medium, high, urgent;set_typeone of bug, question, feature_request, billing;set_groupan existing group key;assign_tothe user id of an agent who can work tickets;add_watchersan array of user ids;add_tags/remove_tagsan array of tag strings;notify_slack/add_internal_notea message template (max 2000 characters) that may use{{placeholder}}keys from: ticket.id, ticket.number, ticket.subject, ticket.status, ticket.priority, ticket.type, ticket.url, tenant.id, requester.name, requester.first_name, requester.email, assignee.name, rule.name;send_customer_noticeone of: auto_closed;assign_replier_if_unassigned,add_tenant_default_watchers,notify_assigneeandmark_importanttake no value (send null).- Runtime notes:
set_status/set_priority/assign_todo nothing when the ticket already has that value;assign_tois ignored when the user is not an agent who can work tickets;add_watchersandadd_tenant_default_watchersskip the requester and anyone already on the ticket;notify_assigneeemails the assignee, or every agent when the ticket is unassigned, at most once per run;notify_slackposts the rendered template;send_customer_noticeemails the requester;add_internal_noteadds a private note;mark_importantadds theimportanttag.
Beyond the shape, every condition and action row is checked against the vocabulary (see Get Rule Options): an operator that does not fit the field, a missing or malformed value, an unknown enum value, an invalid regex, or an action value of the wrong kind fails with a 422 whose error key is the row's index (conditions.0, actions.1). Unknown keys inside a row are dropped.
Response fields: id (integer), name (string), trigger (string — one of: ticket_created, ticket_updated, customer_replied, agent_replied, hourly), trigger_label (string), conditions[] (object[] — field, operator, value), actions[] (object[] — type, value), position (integer — run order within the trigger, lowest first), is_active (boolean), is_system (boolean — built-in rules that can be edited or switched off but not deleted), created_at / updated_at (ISO-8601).
How rules run: a trigger fires when the corresponding event happens — ticket_created, ticket_updated, customer_replied and agent_replied run immediately at the end of the action that caused them; hourly runs from a scheduled sweep over every ticket that is not closed. For a trigger, every active rule runs in position order (ties broken by id); there is no stop-processing flag, so every rule whose conditions match runs. A rule matches when ALL of its conditions hold (an empty condition list always matches). Its actions then run in order; each action that changes something is recorded in the ticket's event history with the actor Rule: <name>, plus one rule_applied event per rule that had an effect. Actions never fire triggers themselves, so rules cannot cascade into one another. An hourly rule fires at most once per ticket per status epoch: it is skipped while its last rule_applied event is newer than the ticket's last status change.
Authentication: Bearer token with the support:write scope, or an authenticated session, from a caller with an active support role who also holds the support admin role. No tenant context — this endpoint is central.
Request
Responses
- 201
- 401
- 403
- 422
- 429
Created
Response Headers
Unauthenticated — the bearer token is missing, revoked, expired, or malformed. Never retry automatically; fix the credential. See the Errors guide.
Forbidden
Response Headers
Unprocessable Content
Response Headers
Rate limited — platform limit is 1,000 requests/min; individual tokens may carry lower limits. Honor the Retry-After header before retrying. See the Rate Limits guide.