Routines
Tags: automation, routines
Routines — the unified automation primitive (schedule, webhook, and system-event triggers)
Resources
Request and response models used by the endpoints on this page.
CreateRoutineRequest
| Field | Type | Required | Description |
|---|---|---|---|
agentId | MemberId | ||
cronString | String | ||
description | String | ||
eventRules | Array<EventRuleData> | null | ||
intervalSeconds | Integer | ||
limit | Integer | Default: 0 | |
memberFilterId | Integer | ||
name | String | ✓ | |
prompt | String | ||
repeatCount | Integer | ||
scheduleEnabled | Boolean | Default: False | |
scheduleMode | String | Default: CRON | |
scheduledTime | String | ||
skills | Array | ||
startDate | String | ||
targetMemberId | Integer | ||
timezone | String | ||
visibility | String | Default: workspace | |
webhookEnabled | Boolean | Default: False | |
workflowId | Integer |
Example:
{
"name": "string",
"scheduleEnabled": false,
"scheduleMode": "CRON",
"limit": 0,
"visibility": "workspace",
"webhookEnabled": false
}
EventRuleData
| Field | Type | Required | Description |
|---|---|---|---|
actionParams | dict[str, Any] | Parameters for the action | |
actionType | <enum EventRuleActionType | ✓ | The action type to execute |
active | Boolean | Whether the rule is active (default: True) | |
conditions | String | CEL condition expression for conditional execution | |
delay | Integer | Delay in seconds before executing the action (default: 0) | |
eventType | <enum EventRuleEventType | ✓ | The event type that triggers this rule |
name | String | Display name for the rule | |
objectType | EventRuleObjectType | The object type this rule applies to (inferred from parent if not provided) | |
triggerParams | dict[str, Any] | Parameters for the trigger (e.g., webhook config) | |
uuid | String | ✓ | UUID for matching/creating event rules |
Example:
{
"uuid": "string",
"eventType": null,
"actionType": null,
"active": true,
"delay": 0
}
EventRuleResponse
| Field | Type | Required | Description |
|---|---|---|---|
actionParams | Dict[str, Any] | ✓ | |
actionSetLocked | Boolean | Default: False | |
actionType | <enum EventRuleActionType | ✓ | |
active | Boolean | ✓ | |
appConnectionId | Integer | ||
calendarEventTypeId | Integer | ✓ | |
calendarId | Integer | ✓ | |
celBlockedAt | DateTime | ||
conditions | String | ✓ | |
createdAt | DateTime | ✓ | |
dataTypeId | Integer | ✓ | |
dataTypeName | String | ||
delay | Integer | ✓ | |
error | String | ✓ | |
errorMessage | String | ✓ | |
eventType | <enum EventRuleEventType | ✓ | |
failedAt | DateTime | ✓ | |
id | Integer | ✓ | |
journeyId | Integer | ||
journeyStepId | Integer | ✓ | |
name | String | ✓ | |
objectType | <enum EventRuleObjectType | ✓ | |
order | Integer | ✓ | |
routineId | Integer | ✓ | |
taskId | Integer | ✓ | |
taskName | String | ||
taskWorkflowId | Integer | ||
triggerParams | Dict[str, Any] | ✓ | |
updatedAt | DateTime | ✓ | |
uuid | String | ✓ | |
workflowRevisionId | Integer | ✓ |
Example:
{
"id": 0,
"uuid": "string",
"objectType": null,
"name": "string",
"eventType": null,
"conditions": "string",
"actionType": null,
"actionParams": {},
"triggerParams": {},
"active": false,
"createdAt": "2024-01-01T00:00:00Z",
"updatedAt": "2024-01-01T00:00:00Z",
"taskId": 0,
"dataTypeId": 0,
"routineId": 0,
"workflowRevisionId": 0,
"calendarId": 0,
"calendarEventTypeId": 0,
"journeyStepId": 0,
"error": "string",
"errorMessage": "string",
"failedAt": "2024-01-01T00:00:00Z",
"delay": 0,
"order": 0,
"actionSetLocked": false
}
MemberSummary
| Field | Type | Required | Description |
|---|---|---|---|
id | Integer | ✓ | |
name | String |
Example:
{
"id": 0
}
PaginatedResponse[RoutineResponse]
| Field | Type | Required | Description |
|---|---|---|---|
items | Array<RoutineResponse> | ✓ | |
page | Integer | ✓ | |
pageSize | Integer | ✓ | |
total | Integer | ✓ | |
totalPages | Integer | ✓ |
Example:
{
"items": [],
"total": 0,
"page": 0,
"pageSize": 0,
"totalPages": 0
}
PaginatedResponse[RoutineRunResponse]
| Field | Type | Required | Description |
|---|---|---|---|
items | Array<RoutineRunResponse> | ✓ | |
page | Integer | ✓ | |
pageSize | Integer | ✓ | |
total | Integer | ✓ | |
totalPages | Integer | ✓ |
Example:
{
"items": [],
"total": 0,
"page": 0,
"pageSize": 0,
"totalPages": 0
}
RoutineConfigEventResponse
| Field | Type | Required | Description |
|---|---|---|---|
actor | MemberSummary | null | ||
actorMemberId | Integer | ||
actorType | <enum RoutineConfigEventActorType | ✓ | |
fieldsChanged | Array | ||
id | Integer | ✓ | |
occurredAt | DateTime | ✓ | |
reason | <enum RoutineConfigEventReason | ✓ | |
routineId | Integer | ✓ | |
scheduleEnabledAfter | Boolean | ||
scheduleEnabledBefore | Boolean | ||
scheduleTransitioned | Boolean | ✓ | |
uuid | String | ✓ | |
webhookEnabledAfter | Boolean | ||
webhookEnabledBefore | Boolean | ||
webhookTransitioned | Boolean | ✓ |
Example:
{
"id": 0,
"uuid": "string",
"routineId": 0,
"occurredAt": "2024-01-01T00:00:00Z",
"actorType": null,
"reason": null,
"scheduleTransitioned": false,
"webhookTransitioned": false
}
RoutineResponse
| Field | Type | Required | Description |
|---|---|---|---|
agentId | Integer | ||
createdAt | DateTime | ✓ | |
cronString | String | ||
description | String | ||
eventRules | Array<EventRuleResponse> | Default: [] | |
id | Integer | ✓ | |
intervalSeconds | Integer | ||
limit | Integer | ✓ | |
memberFilterId | Integer | ||
memberFilterName | String | ||
name | String | ✓ | |
nextRun | DateTime | ||
ownerId | Integer | ✓ | |
prompt | String | ||
repeatCount | Integer | ||
scheduleEnabled | Boolean | ✓ | |
scheduleMode | String | ✓ | |
scheduledTime | DateTime | ||
skills | Array | ||
startDate | DateTime | ||
targetMemberId | Integer | ||
timezone | String | ||
updatedAt | DateTime | ✓ | |
uuid | String | ✓ | |
visibility | String | ✓ | |
webhookEnabled | Boolean | Default: False | |
webhookSecretPlaintext | String | ||
workflowId | Integer |
Example:
{
"id": 0,
"uuid": "string",
"name": "string",
"scheduleEnabled": false,
"scheduleMode": "string",
"limit": 0,
"visibility": "string",
"ownerId": 0,
"createdAt": "2024-01-01T00:00:00Z",
"updatedAt": "2024-01-01T00:00:00Z",
"eventRules": [],
"webhookEnabled": false
}
RoutineRunResponse
| Field | Type | Required | Description |
|---|---|---|---|
assignmentId | Integer | ||
chatId | Integer | ||
completedAt | DateTime | ||
completionMessageId | Integer | ||
createdAt | DateTime | ✓ | |
errorMessage | String | ||
failureCode | String | ||
id | Integer | ✓ | |
jobId | String | ||
member | MemberSummary | null | ||
memberId | Integer | ||
parentRunId | Integer | ||
routineId | Integer | ✓ | |
skipReason | String | ||
startedAt | DateTime | ||
status | String | ✓ | |
updatedAt | DateTime | ✓ | |
uuid | String | ✓ |
Example:
{
"id": 0,
"uuid": "string",
"routineId": 0,
"status": "string",
"createdAt": "2024-01-01T00:00:00Z",
"updatedAt": "2024-01-01T00:00:00Z"
}
RoutineVoiceReadinessPreviewRequest
| Field | Type | Required | Description |
|---|---|---|---|
eventRules | Array<EventRuleData> | null | ||
memberFilterId | Integer | ||
name | String | ||
routineId | Integer | ||
targetMemberId | Integer |
Example:
{}
RoutineVoiceReadinessPreviewResponse
| Field | Type | Required | Description |
|---|---|---|---|
totalWarnings | Integer | ✓ | |
warnings | Array<RoutineVoiceReadinessWarningResponse> | ✓ |
Example:
{
"warnings": [],
"totalWarnings": 0
}
RoutineVoiceReadinessWarningResponse
| Field | Type | Required | Description |
|---|---|---|---|
actionType | String | ✓ | |
affectedMemberCount | Integer | ✓ | |
audienceSize | Integer | ✓ | |
code | Literal['audience_empty', 'audience_filter_not_authorized', 'audience_voice_disabled', 'audience_missing_phone', 'phone_number_missing', 'phone_number_unresolved', 'phone_number_archived', 'phone_number_voice_disabled'] | ✓ | |
eventRuleId | Integer | ||
eventRuleUuid | String | ||
phoneNumberId | Integer | ||
phoneNumberName | String | ||
routineId | Integer | ||
routineName | String | ||
targetKind | Literal['member', 'member_filter', 'owner', 'none'] | ✓ |
Example:
{
"actionType": "string",
"code": "audience_empty",
"targetKind": "member",
"audienceSize": 0,
"affectedMemberCount": 0
}
SchedulePreviewRequest
| Field | Type | Required | Description |
|---|---|---|---|
count | Integer | Default: 5 | |
cronString | String | ✓ | |
timezone | String |
Example:
{
"cronString": "string",
"count": 5
}
SchedulePreviewResponse
| Field | Type | Required | Description |
|---|---|---|---|
nextRuns | Array | ✓ |
Example:
{
"nextRuns": []
}
UpdateRoutineRequest
| Field | Type | Required | Description |
|---|---|---|---|
agentId | MemberId | ||
cronString | String | ||
description | String | ||
eventRules | Array<EventRuleData> | null | ||
intervalSeconds | Integer | ||
limit | Integer | ||
memberFilterId | Integer | ||
name | String | ||
prompt | String | ||
repeatCount | Integer | ||
rotateWebhookSecret | Boolean | ||
scheduleEnabled | Boolean | ||
scheduleMode | String | ||
scheduledTime | String | ||
skills | Array | ||
startDate | String | ||
targetMemberId | Integer | ||
timezone | String | ||
visibility | String | ||
webhookEnabled | Boolean | ||
workflowId | Integer |
Example:
{}
Endpoints
GET /api/v2/w/{workspace_uuid}/routines- ListPOST /api/v2/w/{workspace_uuid}/routines- CreatePOST /api/v2/w/{workspace_uuid}/routines/preview-schedule- Preview SchedulePOST /api/v2/w/{workspace_uuid}/routines/preview-voice-readiness- Preview Voice ReadinessGET /api/v2/w/{workspace_uuid}/routines/runs- RunsDELETE /api/v2/w/{workspace_uuid}/routines/{event_id}- Delete Event IdGET /api/v2/w/{workspace_uuid}/routines/{event_id}- Get Event IdPUT /api/v2/w/{workspace_uuid}/routines/{event_id}- Update Event IdGET /api/v2/w/{workspace_uuid}/routines/{event_id}/history- HistoryPOST /api/v2/w/{workspace_uuid}/routines/{event_id}/run- RunDELETE /api/v2/w/{workspace_uuid}/routines/{event_id}/runs- Delete Runs
List
GET /api/v2/w/{workspace_uuid}/routines
Description:
List all Routines for the workspace with pagination.
Visibility rules, owner/ownerId composition and the query itself:
lib/services/routine_read_service.py.
Authorization: Requires automations:read scope
Parameters:
page(Integer) — min: 1pageSize(Integer) — min: 1, max: 100sortBy(RoutineSortField)sortOrder(SortOrder)owner(String)ownerId(Integer)agentId(Integer) — min: 1agentOnly(Boolean)
Response: See PaginatedResponse[RoutineResponse]
Create
POST /api/v2/w/{workspace_uuid}/routines
Description:
Create a new Routine.
Authorization: Requires automations:write scope
Parameters:
request- See CreateRoutineRequest
Response: See RoutineResponse
Preview Schedule
POST /api/v2/w/{workspace_uuid}/routines/preview-schedule
Description:
Preview the next N run times for a cron expression.
An omitted/blank timezone falls back to the workspace's, then UTC —
the same precedence the schedulers apply, so the preview cannot promise a
wall-clock the dispatcher will not honour. This is what the editor already
does client-side; sending the fallback through the server too keeps a
direct API/CLI caller from getting a different answer.
Authorization: Requires automations:read scope
Parameters:
request- See SchedulePreviewRequest
Response: See SchedulePreviewResponse
Preview Voice Readiness
POST /api/v2/w/{workspace_uuid}/routines/preview-voice-readiness
Description:
Non-blocking preview of what would stop this Routine placing its calls.
Warn-not-block authoring assist, read-only and non-persisting. It evaluates
the draft's target audience and its phone:call actions against the
prerequisites the dispatch path actually enforces — the Member voice
opt-out, a reachable member phone, and a resolvable, unarchived,
voice-enabled workspace number.
Every one of those failures is silent today: the opt-out makes the action
skip, which leaves the RoutineRun COMPLETED, so the schedule looks
like it ran and no call was placed (CS-173). This endpoint is the surface
that says so before the schedule fires.
There is no hard create/update sibling to this check: an unready audience is a transient member-data condition, not a structural one, so blocking the save would refuse a Routine that becomes correct the moment someone toggles a Member preference. Advisory is the right and only posture here.
No PHI reaches the response: the audience is aggregated in SQL and comes
back as counts, never rows. (The predicates do read Member.phone and
Member.notify_voice — that is the question being asked; no value from
either column crosses the wire, a log, or a breadcrumb.)
The counts are an upper bound over the whole matched cohort and do not
honour Routine.limit, which caps how many members a single run
dispatches to. A capped Routine can therefore be warned about members it
would not have reached on the next slot; it is never silent about members
it would.
Authorization: Requires automations:write scope
Parameters:
request- See RoutineVoiceReadinessPreviewRequest
Response: See RoutineVoiceReadinessPreviewResponse
Runs
GET /api/v2/w/{workspace_uuid}/routines/runs
Description:
List all Routine runs for the workspace with pagination.
Only runs for Routines the caller can see are returned. The visibility
join and the routineId/status filters live in
lib/services/routine_read_service.py.
Authorization: Requires automations:read scope
Parameters:
page(Integer) — min: 1pageSize(Integer) — min: 1, max: 100sortBy(EventRunSortField)sortOrder(SortOrder)routineId(Integer)status(String)
Response: See PaginatedResponse[RoutineRunResponse]
Delete Event Id
DELETE /api/v2/w/{workspace_uuid}/routines/{event_id}
Description:
Delete a Routine.
Authorization: Requires automations:admin scope
Parameters:
event_id(Integer)
Response: dict[str, str]
Get Event Id
GET /api/v2/w/{workspace_uuid}/routines/{event_id}
Description:
Get a specific Routine by ID.
Authorization: Requires automations:read scope
Parameters:
event_id(Integer)
Response: See RoutineResponse
Update Event Id
PUT /api/v2/w/{workspace_uuid}/routines/{event_id}
Description:
Update an existing Routine.
Authorization: Requires automations:write scope
Parameters:
event_id(Integer)request- See UpdateRoutineRequest
Response: See RoutineResponse
History
GET /api/v2/w/{workspace_uuid}/routines/{event_id}/history
Description:
Config-change history for one Routine, newest first (GH #22937).
Access rules and rationale: lib/services/routine_history_service.py.
Authorization: Requires automations:read scope
Parameters:
event_id(Integer)limit(Integer)before_id(Integer)transitions_only(Boolean)
Response: List of RoutineConfigEventResponse
Run
POST /api/v2/w/{workspace_uuid}/routines/{event_id}/run
Description:
Run a Routine manually.
Authorization: Requires automations:write scope
Parameters:
event_id(Integer)member_id(Integer)member_filter_id(Integer)
Response: dict[str, str]
Delete Runs
DELETE /api/v2/w/{workspace_uuid}/routines/{event_id}/runs
Description:
Reset/clear all runs for a Routine.
Orchestration, ordering and rationale:
lib/services/routine_reset_service.py.
Authorization: Requires automations:admin scope
Parameters:
event_id(Integer)
Response: dict[str, str | int]