Workflows
Overview
Workflows define conditions and actions that run against tickets. The trigger_type controls when a workflow fires:
on_new_ticket: runs once when a new ticket is created. Does not run on replies.on_inbound_message: runs on every inbound message, including replies to existing tickets.on_no_reply: runs when a customer message has been waiting for a reply longer than the configured duration. Requirestrigger_parameters(see below). Fires once per waiting period and re-arms when the customer writes in again after a reply. Withonly_business_hours, durations in minutes or hours pause the clock outside the workspace's business hours, and durations in days count business days (days on which the workspace is fully closed do not count). Without it, days mean calendar days (2 daysfires exactly 48 hours after the unanswered message).on_tag_added: runs when a tag is added to a ticket. Optionally scope it to specific tags withtrigger_parameters(see below).on_tag_removed: runs when a tag is removed from a ticket. Optionally scope it to specific tags withtrigger_parameters(see below).manual: can be triggered from the ticket sidebar when conditions match.
Admin role is required to create, update, or delete workflows.
List Workflows
GET /api/workflows
Show Workflow
GET /api/workflows/{workflow}
The response includes nested conditions and actions arrays.
Create Workflow (admin only)
POST /api/workflows
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
name |
string | Yes | |
description |
string | No | |
trigger_type |
string | Yes | on_new_ticket, on_inbound_message, on_no_reply, on_tag_added, on_tag_removed, or manual |
trigger_parameters |
object | No | Required for on_no_reply: { "value": 4, "unit": "hours", "only_business_hours": false }. Unit is minutes, hours (default), or days, capped at 30 days in total. With only_business_hours, only the workspace's business hours (or business days, for the days unit) count toward the duration. For on_tag_added and on_tag_removed, optionally { "tags": ["tag-ulid", ...] } to scope the trigger to specific tags; omit or leave empty to fire for any tag. |
condition_match_type |
string | No | all (default) or any |
is_enabled |
boolean | No | Defaults to true |
conditions |
array | No | Array of { type, parameters } condition objects |
actions |
array | No | Array of { type, parameters } action objects |
Condition Types
body_containschannel_ischannel_type_iscontact_is_newdoes_not_have_tagfrom_domain_equalsfrom_email_containsfrom_email_equalshas_tagis_first_messagesubject_containssubject_equals
Example Request
curl -X POST https://there-there.app/api/workflows \
-H "Authorization: Bearer YOUR_API_TOKEN" \
-H "X-Workspace-Id: 1" \
-H "Content-Type: application/json" \
-d '{
"name": "Auto-close spam",
"trigger_type": "on_new_ticket",
"condition_match_type": "any",
"conditions": [
{ "type": "subject_contains", "parameters": { "value": "unsubscribe" } }
],
"actions": [
{ "type": "set_status", "parameters": { "status": "spam" } }
]
}'
On No Reply Example Request
curl -X POST https://there-there.app/api/workflows \
-H "Authorization: Bearer YOUR_API_TOKEN" \
-H "X-Workspace-Id: 1" \
-H "Content-Type: application/json" \
-d '{
"name": "Escalate waiting tickets",
"trigger_type": "on_no_reply",
"trigger_parameters": {
"value": 4,
"unit": "hours",
"only_business_hours": true
},
"condition_match_type": "all",
"actions": [
{ "type": "assign_ticket", "parameters": { "assign_type": "team", "team": "TEAM_ULID", "user": null } }
]
}'
Update Workflow (admin only)
PUT /api/workflows/{workflow}
Omit fields to leave them unchanged. If conditions or actions is included, existing conditions/actions are replaced entirely.
Delete Workflow (admin only)
DELETE /api/workflows/{workflow}