Campaigns
Base path: /api/campaigns
GET /campaigns
List all campaigns.
Auth: Admin
Query parameters: page, limit
Response: Array of campaign objects.
POST /campaigns
Create a new campaign.
Auth: Admin
Request body:
| Field | Type | Required | Description |
|---|---|---|---|
name | string | Yes | Internal campaign name |
subject | string | Yes | Email subject line |
blocks | array | Yes | Email builder block array |
segment_filters | object | No | Audience filter criteria |
GET /campaigns/:id
Get a single campaign with details.
PUT /campaigns/:id
Update a campaign.
DELETE /campaigns/:id
Delete a campaign.
POST /campaigns/:id/send
Send the campaign to all matching recipients.
Auth: Admin
Builds the recipient list from segment_filters, then enqueues one email job per recipient in the job_queue for background processing by the worker. The worker renders the blocks array via MJML before sending.
Segments
GET /campaigns/segments
List saved audience segments.
POST /campaigns/segments
Save an audience segment for reuse.
| Field | Type | Required |
|---|---|---|
name | string | Yes |
filters | object | Yes |
DELETE /campaigns/segments/:id
Delete a saved segment.
Templates
GET /campaigns/templates
List saved email templates.
POST /campaigns/templates
Save an email template.
| Field | Type | Required |
|---|---|---|
name | string | Yes |
blocks | array | Yes |
DELETE /campaigns/templates/:id
Delete a template.
POST /campaigns/render-mjml
Render MJML email to HTML for preview.
Auth: Admin
Request body:
{
"mjml": "<mjml><mj-body>...</mj-body></mjml>"
}
Response:
{
"html": "<html>...</html>"
}
Segment Filter Fields
The segment_filters object (and filters in saved segments) supports the following fields. All fields are optional and combined with AND logic.
| Field | Type | Description |
|---|---|---|
has_email | boolean | Only clients with a non-empty email address |
has_phone | boolean | Only clients with a non-empty phone number |
labels | array of strings | Clients assigned any of the given label names |
last_visit_days_ago | integer | Clients whose last completed booking was more than N days ago (or who have no bookings) |
min_total_spent | number | Minimum lifetime spend across all POS orders |
max_total_spent | number | Maximum lifetime spend across all POS orders |
birthday_months | array of integers | Clients whose birthday falls in any of the given months (1=January, 12=December) |
service_category_id | integer | Clients who have booked a service in this category |
min_visits | integer | Minimum number of completed bookings |
max_visits | integer | Maximum number of completed bookings |
gender | string | Filter by client gender value (e.g. male, female) |
The segment filter is applied at send time. The field names used in the actual server code (last_visit_days_ago, min_total_spent, birthday_months, etc.) are what you must use in API requests. The UI may show friendlier labels.