Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.actionlayer.dev/llms.txt

Use this file to discover all available pages before exploring further.

The rules engine evaluates a condition tree against trigger events and runs actions when conditions match. Rules are how you auto-approve trusted contacts, flag urgent threads, route by sender, or shortcut the approval step for known cases.
MethodPathPurpose
POST/v1/rulesCreate a rule
GET/v1/rulesList rules
GET/v1/rules/{id}Get one rule
PATCH/v1/rules/{id}Update a rule
DELETE/v1/rules/{id}Delete a rule

How rules work

  1. An event fires (e.g. email.received).
  2. ActionLayer fetches all active rules for that workspace + trigger, ordered by priority ascending.
  3. For each rule, it walks the condition tree. If conditions pass, all actions execute.
  4. If stop_after_match: true on a matching rule, evaluation halts; otherwise the next rule is checked.
Rule evaluation runs in the background (Celery) — it never blocks an API response.

Trigger events

EventFires when
email.receivedAn inbound message is parsed and stored
email.sentAn outbound message is queued for delivery
email.deliveredPostmark confirmed delivery
draft.createdAn agent submits a draft
draft.approvedA draft is approved (manually or via auto-approve)
draft.sentAn approved draft was successfully delivered
draft.staleA draft was marked stale (newer inbound arrived)

Conditions

Conditions are an AND/OR tree:
{
  "operator": "AND",
  "conditions": [
    { "field": "contact.status", "op": "equals", "value": "trusted" },
    {
      "operator": "OR",
      "conditions": [
        { "field": "message.body_text", "op": "contains", "value": "urgent" },
        { "field": "thread.subject",    "op": "contains", "value": "ASAP" }
      ]
    }
  ]
}

Supported fields

Available fields depend on the trigger:
TriggerFields
email.receivedmessage.from_email, message.subject, message.body_text, thread.subject, thread.status, contact.status, contact.tag, contact.domain, identity.id
draft.created / draft.approved / draft.stalethread.subject, thread.status, contact.status, contact.tag, contact.domain, identity.id

Supported operators (op)

OperatorApplies toNotes
equalsstring, enumExact match (case-insensitive for emails)
not_equalsstring, enum
containsstringSubstring, case-insensitive
not_containsstring
starts_with / ends_withstring
in / not_instring, enumvalue must be a list
The condition builder in the dashboard surfaces only the operators valid for each field.

Actions

actions is an ordered list. Each item is a {type, ...params} object.
TypeParamsEffect
set_thread_statusstatus: open|waiting|draft_pending|closedForce the thread into that state
set_approval_modemode: manual|autoOverride auto_approve_replies for this draft only
skip_approval(none)Approve the draft and queue send
notify_channelchannel: telegram|slack|email, config: {...}Fire an ad-hoc notification
add_tagtag: stringTag the contact
set_prioritypriority: low|normal|high|urgentSurface in inbox sorting

Create

curl -X POST https://api.actionlayer.dev/v1/rules \
  -H "Authorization: Bearer $ACTIONLAYER_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Auto-approve trusted contacts",
    "trigger_event": "draft.created",
    "priority": 50,
    "stop_after_match": true,
    "conditions": {
      "operator": "AND",
      "conditions": [
        { "field": "contact.status", "op": "equals", "value": "trusted" }
      ]
    },
    "actions": [
      { "type": "skip_approval" }
    ]
  }'

Request body

FieldTypeDefaultNotes
namestringrequiredHuman label
trigger_eventenumrequiredOne of the events above
conditionsobject{}AND/OR tree, max 10 KB serialized
actionsarray[]Max 10 KB serialized
statusactive | inactiveactiveinactive keeps the rule but skips evaluation
priorityint100Lower number = evaluated first
stop_after_matchboolfalseIf true and the rule matches, no further rules run
identity_idUUIDnullScope rule to a single identity
assistant_idUUIDnullScope rule to a single agent

More examples

Flag urgent threads

{
  "name": "Flag urgent",
  "trigger_event": "email.received",
  "conditions": {
    "operator": "OR",
    "conditions": [
      { "field": "message.subject",  "op": "contains", "value": "URGENT" },
      { "field": "message.body_text", "op": "contains", "value": "asap" }
    ]
  },
  "actions": [
    { "type": "set_priority", "priority": "urgent" },
    { "type": "notify_channel", "channel": "telegram", "config": { "chat_id": "…" } }
  ]
}

Auto-close newsletter threads

{
  "name": "Close newsletters",
  "trigger_event": "email.received",
  "conditions": {
    "operator": "AND",
    "conditions": [
      { "field": "message.from_email", "op": "ends_with", "value": "@substack.com" }
    ]
  },
  "actions": [
    { "type": "set_thread_status", "status": "closed" }
  ]
}

List

curl 'https://api.actionlayer.dev/v1/rules?trigger_event=draft.created&status=active' \
  -H "Authorization: Bearer $ACTIONLAYER_API_KEY"
Returned in priority order (ascending).

Update

curl -X PATCH https://api.actionlayer.dev/v1/rules/RULE_ID \
  -H "Authorization: Bearer $ACTIONLAYER_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"status": "inactive"}'

Delete

curl -X DELETE https://api.actionlayer.dev/v1/rules/RULE_ID \
  -H "Authorization: Bearer $ACTIONLAYER_API_KEY"

Errors

HTTPerrorWhen
402plan_limit_reachedWorkspace at rules cap (0 / 25 / 100 by plan; Builder Pack has no rules)
404not_foundRule does not exist
422validationtrigger_event not allowed, conditions/actions over 10 KB, etc.