Subscriptions
Subscribe to events and get notified when interactions happen.
Subscriptions connect events to notification adapters. When an interaction matches a subscription's resource type + action combination, a notification is automatically queued.
Creating a subscription
POST /api/subscriptions
{
"actionId": "uuid",
"resourceTypeId": "uuid",
"subscriberId": "uuid",
"originId": "uuid",
"config": {
"adapter": "adapter:email",
"personalizations": [{
"to": [{
"email": "{{interaction.email}}",
"name": "{{interaction.name}}"
}],
"dynamic_template_data": {
"userName": "{{interaction.name}}"
}
}],
"from": { "email": "noreply@example.com" },
"template_id": "d-template-id"
}
}Fields
| Field | Required | Description |
|---|---|---|
actionId | Yes | Action UUID to match |
resourceTypeId | Yes | Resource type UUID to match |
subscriberId | Yes | Subscriber to notify |
originId | No | Filter by origin — null matches all origins |
config | No | Adapter-specific configuration with template variables |
labels | No | Array of label strings for organizing subscriptions (max 10, each max 50 chars) |
delivery_schedule | No | Time-window configuration controlling when notifications are delivered (see Delivery Schedule) |
How it works
- An interaction is created via
POST /api/interactions - A database trigger finds all matching subscriptions (by resource type + action)
- For each match, a notification is added to the queue
- The queue processor picks it up and calls the configured adapter
- The adapter delivers the notification (email, Slack, webhook, etc.)
- The result is logged in the audit trail
Template variables
Use {{interaction.fieldName}} in your subscription config to inject values from the interaction's metadata:
{
"to": "{{interaction.email}}",
"subject": "Order {{interaction.orderId}} confirmed",
"body": "Hi {{interaction.name}}, your order is ready."
}Beyond interaction fields, you can reference global config, adapter settings, secrets, and built-in functions. See the full Template Engine reference for all available namespaces and functions.
Labels
Labels are user-defined text tags for organizing and categorizing subscriptions. Assign labels like "Production Alerts", "Billing", or "Security" to group related subscriptions together.
Label format
| Rule | Constraint |
|---|---|
| Allowed characters | Alphanumeric, spaces, hyphens, underscores |
| Max label length | 50 characters |
| Max labels per subscription | 10 |
| Regex pattern | /^[a-zA-Z0-9 _-]{1,50}$/ |
Creating a subscription with labels
POST /api/subscriptions
{
"actionId": "uuid",
"resourceTypeId": "uuid",
"subscriberId": "uuid",
"labels": ["Production", "Billing Alerts", "high-priority"],
"config": { ... }
}Updating labels
Labels are replaced on update — provide the full array each time:
PUT /api/subscriptions/:id
{
"labels": ["Production", "Security"]
}Filtering by label
Use the label query parameter to find subscriptions containing a specific label:
GET /api/subscriptions?label=ProductionUse the labels query parameter with a comma-separated list to find subscriptions containing at least one of the specified labels:
GET /api/subscriptions?labels=Production,Security,BillingWhen no label filter is provided, all subscriptions are returned regardless of their labels.
Delivery Schedule
Delivery schedules control when notifications are eligible for delivery. Configure time windows so notifications are only sent during business hours, on-call shifts, or other specific periods.
When a subscription has a delivery schedule and a notification is queued outside all configured windows, the queue processor defers the notification — setting its nextAttempt to the start of the next eligible window. The notification is delivered once the window opens.
Schedule structure
{
"timezone": "America/New_York",
"windows": [
{
"days": [1, 2, 3, 4, 5],
"startTime": "09:00",
"endTime": "17:00"
},
{
"days": [6],
"startTime": "10:00",
"endTime": "14:00"
}
]
}| Field | Type | Description |
|---|---|---|
timezone | string | IANA timezone identifier (e.g., "America/New_York", "Europe/London") |
windows | array | One or more delivery windows |
windows[].days | number[] | Days of the week: 0 = Sunday, 1 = Monday, ..., 6 = Saturday |
windows[].startTime | string | Window start in HH:MM 24-hour format |
windows[].endTime | string | Window end in HH:MM 24-hour format |
Timezone handling
The timezone field must be a valid IANA timezone identifier. The queue processor converts the current time to the schedule's timezone before checking windows. If the timezone is invalid at processing time, the notification is delivered immediately (fail-open).
Default behavior
When no delivery schedule is configured (delivery_schedule is null), the subscription is treated as "Always active" — notifications are delivered immediately with no time restrictions.
Creating a subscription with a delivery schedule
POST /api/subscriptions
{
"actionId": "uuid",
"resourceTypeId": "uuid",
"subscriberId": "uuid",
"delivery_schedule": {
"timezone": "America/New_York",
"windows": [
{
"days": [1, 2, 3, 4, 5],
"startTime": "09:00",
"endTime": "17:00"
}
]
},
"config": { ... }
}Updating a delivery schedule
PUT /api/subscriptions/:id
{
"delivery_schedule": {
"timezone": "Europe/London",
"windows": [
{
"days": [1, 2, 3, 4, 5],
"startTime": "08:00",
"endTime": "18:00"
},
{
"days": [6],
"startTime": "10:00",
"endTime": "14:00"
}
]
}
}To remove a delivery schedule and return to "Always active", set it to null:
PUT /api/subscriptions/:id
{
"delivery_schedule": null
}API reference
| Method | Endpoint | Description |
|---|---|---|
GET | /api/subscriptions | List all |
GET | /api/subscriptions/:id | Get by ID |
POST | /api/subscriptions | Create |
PUT | /api/subscriptions/:id | Update |
DELETE | /api/subscriptions/:id | Delete |
POST | /api/subscriptions/:id/pause | Pause |
POST | /api/subscriptions/:id/resume | Resume |
Query parameters
| Parameter | Type | Description |
|---|---|---|
label | string | Filter subscriptions containing this label |
labels | string | Comma-separated list — returns subscriptions containing at least one |