Skip to main content
Was this helpful?

Automation API

Rule-Based Automation

Create rules, inspect executions, trigger webhooks, and manage approvals

PrimeCal automation is built around user-owned rules with triggers, conditions, and actions. This page documents the full non-admin automation surface directly from the controller and DTOs.

JWT or user API keyPublic webhook triggerAudit logs and statsSmart values

Authentication and Permissions

  • All rule-management routes require authentication.
  • POST /api/automation/webhook/:token is explicitly public via @Public().
  • Rules are scoped to the authenticated user.
  • Sensitive rules can require explicit approval before execution.
  • The controller uses the API validation pipe for create and update operations.

Endpoint Reference

MethodPathPurposeRequest or queryAuthSource
POST/api/automation/rulesCreate a rule.Body: rule create payloadJWT or user API keyautomation/automation.controller.ts
GET/api/automation/rulesList rules with pagination and optional enabled filter.Query: page,limit,enabledJWT or user API keyautomation/automation.controller.ts
GET/api/automation/rules/:idGet one rule.Path: idJWT or user API keyautomation/automation.controller.ts
PUT/api/automation/rules/:idUpdate a rule.Path: id, body: partial rule payloadJWT or user API keyautomation/automation.controller.ts
DELETE/api/automation/rules/:idDelete a rule.Path: idJWT or user API keyautomation/automation.controller.ts
POST/api/automation/rules/:id/executeRun a rule immediately.Path: idJWT or user API keyautomation/automation.controller.ts
GET/api/automation/rules/:id/audit-logsList audit logs for one rule.Path: id, query from AuditLogQueryDtoJWT or user API keyautomation/automation.controller.ts
GET/api/automation/audit-logs/:logIdGet one audit log entry.Path: logIdJWT or user API keyautomation/automation.controller.ts
GET/api/automation/rules/:id/statsGet execution statistics for a rule.Path: idJWT or user API keyautomation/automation.controller.ts
POST/api/automation/webhook/:tokenTrigger a webhook-backed rule.Path: token, JSON payloadPublicautomation/automation.controller.ts
POST/api/automation/rules/:id/webhook/regenerateRegenerate the rule's webhook token.Path: idJWT or user API keyautomation/automation.controller.ts
POST/api/automation/rules/:id/webhook/rotate-secretRotate the webhook signing secret.Path: idJWT or user API keyautomation/automation.controller.ts
POST/api/automation/rules/:id/approveApprove a sensitive rule.Path: id, body: noteJWT or user API keyautomation/automation.controller.ts
GET/api/automation/smart-values/:triggerTypeList smart values for a trigger type.Path: triggerTypeJWT or user API keyautomation/automation.controller.ts

Request Shapes

List and approval queries

  • ListAutomationRulesQueryDto.page: optional int, minimum 1, default 1
  • ListAutomationRulesQueryDto.limit: optional int, 1..100, default 20
  • ListAutomationRulesQueryDto.enabled: optional boolean
  • ApproveAutomationRuleDto.note: optional string, max 500 chars

Rule definition

CreateAutomationRuleDto

  • name: required, 1..200 chars
  • description: optional, max 1000 chars
  • triggerType: required enum
  • triggerConfig: optional object
  • isEnabled: optional boolean
  • conditionLogic: optional enum AND|OR
  • conditions: optional array, max 10 items
  • actions: required array, 1..5 items

UpdateAutomationRuleDto keeps the same structure but makes all fields optional.

Trigger types

  • event.created
  • event.updated
  • event.deleted
  • event.starts_in
  • event.ends_in
  • relative_time_to_event
  • calendar.imported
  • scheduled.time
  • webhook.incoming
  • task.status_changed — fires when a task's status changes. Not yet selectable from the rule builder UI; create rules using it directly through this API.
  • task.scheduled_start — fires when a task (including one instantiated from a routine template) reaches its scheduled start time. Also API-only for now. See Smart-Home Automation for the "routine task drives a smart-home device" pattern this enables.
  • notification.dispatched — fires whenever a notification is dispatched to the rule owner on any channel (event reminders, reservation alerts, another rule's send_notification action, etc.). Use the notification.type / notification.channel condition fields to narrow it. See the Trigger Reference for a worked smart-home example.

Relative time trigger config

The relative-time trigger config has nested validation for:

  • eventFilter.calendarIds
  • eventFilter.titleContains
  • eventFilter.descriptionContains
  • eventFilter.tags
  • eventFilter.labels
  • eventFilter.isAllDayOnly
  • eventFilter.isRecurringOnly
  • referenceTime.base: start|end
  • offset.direction: before|after
  • offset.value: int >= 0
  • offset.unit: minutes|hours|days|weeks
  • execution.runOncePerEvent
  • execution.fireForEveryOccurrenceOfRecurringEvent
  • execution.skipPast
  • execution.pastDueGraceMinutes: 0..60
  • execution.schedulingWindowDays: 1..730

Conditions

CreateConditionDto

  • field: required enum
  • operator: required enum
  • value: required string, max 1000 chars
  • groupId: optional string
  • logicOperator: required enum AND|OR|NOT
  • order: optional number

Current condition fields:

  • event.title
  • event.description
  • event.location
  • event.notes
  • event.duration
  • event.is_all_day
  • event.color
  • event.status
  • event.calendar.id
  • event.calendar.name
  • webhook.data
  • notification.type / notification.channel / notification.data.* — only resolvable on notification.dispatched rules; see Condition Reference.

Current operators include:

  • contains, not_contains, matches, not_matches
  • equals, not_equals
  • starts_with, ends_with
  • is_empty, is_not_empty
  • greater_than, less_than
  • greater_than_or_equal, less_than_or_equal
  • is_true, is_false
  • in, not_in, in_list, not_in_list

Actions

CreateActionDto

  • actionType: required enum
  • actionConfig: optional object
  • order: optional number

Current action types:

  • set_event_color
  • add_event_tag
  • send_notification
  • update_event_title
  • update_event_description
  • cancel_event
  • move_to_calendar
  • create_task
  • webhook
  • instantiate_routine — starts a routine template right now, the same as the manual "Start now" endpoint. actionConfig: { routineTemplateId: number }. Enforces the same ownership/group-readability check as POST /api/routine-templates/:id/instantiate, so a rule can never instantiate a template its owner can't see. Not yet in the action picker UI; see Routine Templates API and Smart-Home Automation.

Webhook action config

The webhook action's actionConfig also accepts, beyond url:

  • method: optional enum GET|POST|PUT|PATCH|DELETE, default POST
  • authType: optional enum none|bearer|basic|header, default none
  • authToken: required when authType isn't none
  • authHeaderName: required when authType is header (the header the token is sent under)
  • includeEventData, headers, customPayload, timeoutMs, maxResponseBytes, signingSecret: unchanged from the original webhook action

This generalization is what lets the webhook action call a smart-home device's REST API (e.g. a Home Assistant switch.turn_on service call) instead of only posting to a webhook receiver. See Smart-Home Automation for a full example.

Example Calls

Create a rule

curl -X POST "$PRIMECAL_API/api/automation/rules" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"name": "Highlight school pickups",
"triggerType": "event.created",
"conditionLogic": "AND",
"conditions": [
{
"field": "event.title",
"operator": "contains",
"value": "pickup",
"logicOperator": "AND"
}
],
"actions": [
{
"actionType": "set_event_color",
"actionConfig": { "color": "#f59e0b" }
}
]
}'

Run a rule now

curl -X POST "$PRIMECAL_API/api/automation/rules/14/execute" \
-H "Authorization: Bearer $TOKEN"

Trigger a webhook rule

curl -X POST "$PRIMECAL_API/api/automation/webhook/$WEBHOOK_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"payload": {
"source": "school-system",
"message": "Late pickup today"
}
}'

Read smart values

curl "$PRIMECAL_API/api/automation/smart-values/event.created" \
-H "Authorization: Bearer $TOKEN"

Instantiate a routine when a webhook arrives

curl -X POST "$PRIMECAL_API/api/automation/rules" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"name": "Smart alarm starts Morning Routine",
"triggerType": "webhook.incoming",
"actions": [
{
"actionType": "instantiate_routine",
"actionConfig": { "routineTemplateId": 42 }
}
]
}'

Call a smart-home device's REST API on a task'''s scheduled start

curl -X POST "$PRIMECAL_API/api/automation/rules" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"name": "Start laundry via Home Assistant",
"triggerType": "task.scheduled_start",
"actions": [
{
"actionType": "webhook",
"actionConfig": {
"url": "https://homeassistant.local:8123/api/services/switch/turn_on",
"method": "POST",
"authType": "bearer",
"authToken": "YOUR_HOME_ASSISTANT_LONG_LIVED_TOKEN",
"customPayload": { "entity_id": "switch.washing_machine" }
}
}
]
}'

Response and Behavior Notes

  • DELETE /api/automation/rules/:id returns 204 No Content.
  • POST /api/automation/rules/:id/execute returns a message and updated execution count.
  • POST /api/automation/rules/:id/webhook/regenerate returns the new webhookToken.
  • POST /api/automation/rules/:id/webhook/rotate-secret returns the new webhookSecret and graceUntil.
  • Public webhook execution uses the raw body and headers when evaluating the rule.
  • The webhook action defaults to POST when method is omitted, for backward compatibility with rules saved before the field existed.
  • The instantiate_routine action returns the created task ids and count in its audit log entry; if the referenced routineTemplateId isn't readable by the rule's owner, the action fails (silently, per the standard automation error-handling model) and is logged in the audit trail rather than throwing during rule save.

Best Practices

  • Keep actions narrow and deterministic. Rules with too many side effects become hard to debug.
  • Use smart values and the catalog returned by GET /api/automation/smart-values/:triggerType instead of hard-coding tokens.
  • Prefer GET /api/automation/rules/:id/audit-logs and /stats when troubleshooting before editing the rule itself.
  • Regenerate webhook tokens if a URL leaks. Rotate webhook secrets if the signing secret leaks.
  • When building UI, treat relative-time triggers as a first-class subtype because their config is far richer than basic event triggers.
  • Store smart-home authToken values as carefully as any other credential — they travel with the rule if it's ever cloned or exported.