Automations
Event-triggered email workflows. Send multi-step sequences when something happens in your app.
Sendry Automations let you fire an event from your app and have Sendry run a multi-step workflow per contact — send an email, wait, branch on a condition, or split into an A/B test.
A typical use case: a user signs up, your backend fires user.signed_up, and Sendry automatically sends a welcome email, waits a day, then sends a tips email.
Automations are available on the Pro plan and above. The Free plan does not include automations.
Concepts
| Term | Meaning |
|---|---|
| Automation | A workflow tied to a trigger. |
| Step | An ordered action inside an automation: send_email, wait, branch, or ab_split. |
| Run | One execution of an automation for one contact. |
| Trigger | What starts a run — either an event match or a contact being added to a segment. |
| Re-entry | Whether a contact can run the same automation more than once. |
Trigger types
| Type | Fires when |
|---|---|
event | An event with a matching name and payload conditions is sent to POST /v1/events. |
contact_added_to_segment | A contact enters a specific segment. |
Re-entry policies
| Policy | Behavior |
|---|---|
once_per_contact | A given contact can run this automation at most once. Subsequent triggers are ignored. |
cooldown | A contact can re-enter after cooldown_seconds have passed since the last run. |
always | Every matching trigger creates a new run. |
Status
| Status | Description |
|---|---|
draft | Saved but not yet active. Triggers are ignored. |
active | Triggers create runs. |
paused | Existing runs continue, but new triggers are ignored. |
archived | Hidden from the dashboard. New triggers ignored. Run history retained. |
Quickstart
1. Create an automation
In the dashboard, open Automations and click New Automation. The visual builder lets you drop in a trigger and chain steps without writing JSON.
You can also create one via the API:
curl -X POST https://api.sendry.online/v1/automations \
-H "Authorization: Bearer $SENDRY_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"name": "Welcome series",
"trigger": {
"type": "event",
"event_name": "user.signed_up"
},
"reentry_policy": "once_per_contact"
}'
2. Add steps
Build a sequence: send a welcome email, wait one day, send a follow-up tip.
# Step 1: welcome email
curl -X POST https://api.sendry.online/v1/automations/auto_abc123/steps \
-H "Authorization: Bearer $SENDRY_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"type": "send_email",
"config": {
"from": "Acme <hello@acme.com>",
"subject": "Welcome to Acme, {{first_name}}!",
"html": "<h1>Hi {{first_name}}</h1><p>Glad you joined.</p>",
"message_type": "marketing"
}
}'
# Step 2: wait 24 hours
curl -X POST https://api.sendry.online/v1/automations/auto_abc123/steps \
-H "Authorization: Bearer $SENDRY_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"type": "wait",
"config": { "duration_seconds": 86400 }
}'
# Step 3: tips email
curl -X POST https://api.sendry.online/v1/automations/auto_abc123/steps \
-H "Authorization: Bearer $SENDRY_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"type": "send_email",
"config": {
"template_id": "tpl_tips_day1",
"from": "Acme <hello@acme.com>",
"message_type": "marketing"
}
}'
3. Activate it
curl -X PATCH https://api.sendry.online/v1/automations/auto_abc123 \
-H "Authorization: Bearer $SENDRY_API_KEY" \
-H "Content-Type: application/json" \
-d '{ "status": "active" }'
4. Fire the event from your app
Whenever a user signs up, send the event. Sendry looks up (or creates) the contact by contact_email and starts a run.
await sendry.events.send({
name: "user.signed_up",
contact_email: "jane@acme.com",
properties: { plan: "pro", first_name: "Jane" },
});client.events.send(
name="user.signed_up",
contact_email="jane@acme.com",
properties={"plan": "pro", "first_name": "Jane"},
)curl -X POST https://api.sendry.online/v1/events \
-H "Authorization: Bearer $SENDRY_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"name": "user.signed_up",
"contact_email": "jane@acme.com",
"properties": {"plan": "pro", "first_name": "Jane"}
}'That's it — Sendry handles the rest. Inspect runs in the dashboard or via GET /v1/automations/:id/runs.
Step type reference
Each step has a type and a config object whose shape depends on the type.
send_email
Sends an email to the contact triggering the run. Either template_id or both subject and a body (html/text) must be provided.
| Field | Type | Required | Description |
|---|---|---|---|
template_id | string | No* | Saved template ID. Mutually exclusive with subject + html/text. |
subject | string | No* | Subject line. Required if no template_id. |
html | string | No* | HTML body. At least one of html or text is required if no template. |
text | string | No | Plain-text body. |
from | string | Yes | Sender. Domain must be verified. |
reply_to | string | No | Reply-to address. |
message_type | string | No | transactional or marketing. Default marketing. |
topic_id | string | No | Subscription topic — recipients unsubscribed from this topic are skipped. |
variables | object | No | Extra template variables. Merged with event properties + contact fields. |
Variables in the body use {{variable_name}} syntax. Available by default: contact fields (first_name, email, etc.) and the event properties payload.
wait
Pauses the run for a fixed duration.
| Field | Type | Required | Description |
|---|---|---|---|
duration_seconds | number | Yes | Seconds to wait before running the next step. |
Common values: 3600 (1 hour), 86400 (1 day), 604800 (1 week).
branch
Splits the run path based on a condition. The next step continues if the condition is true; otherwise the run ends (or jumps to a configured "else" branch in the visual builder).
| Field | Type | Required | Description |
|---|---|---|---|
condition | object | Yes | Condition object (see below). |
Condition operators:
| Operator | Fields | Matches if |
|---|---|---|
property_eq | property, value | The given property equals value. |
property_exists | property | The given property is set (non-null). |
Properties are looked up first in the event payload, then on the contact.
{
"type": "branch",
"config": {
"condition": {
"op": "property_eq",
"property": "plan",
"value": "pro"
}
}
}
ab_split
Splits incoming runs between two paths by weight. Useful for A/B-testing subject lines or content.
| Field | Type | Required | Description |
|---|---|---|---|
split | { a: number, b: number } | Yes | Weights for branch A and branch B. They are normalized. |
seed | string | No | Optional seed for deterministic bucketing per contact. |
{
"type": "ab_split",
"config": {
"split": { "a": 50, "b": 50 },
"seed": "subject-test-2026-q1"
}
}
API reference
All automation endpoints require Authorization: Bearer <api_key>. Mutation endpoints require full_access scope; reads accept read_only and above.
| Method | Endpoint | Description |
|---|---|---|
| POST | /v1/automations | Create an automation. |
| GET | /v1/automations | List automations (cursor-paginated). |
| GET | /v1/automations/:id | Get one automation. |
| PATCH | /v1/automations/:id | Update fields like status, name, trigger. |
| DELETE | /v1/automations/:id | Archive (soft-delete) an automation. |
| POST | /v1/automations/:id/steps | Append a step. |
| GET | /v1/automations/:id/steps | List steps in execution order. |
| GET | /v1/automations/:id/runs | List per-contact runs for an automation. |
| POST | /v1/events | Fire an event. Most apps only need this endpoint. |
Event payload
{
"name": "user.signed_up",
"contact_email": "jane@acme.com",
"properties": {
"plan": "pro",
"first_name": "Jane"
}
}
| Field | Type | Required | Description |
|---|---|---|---|
name | string | Yes | Event name. Match this against an automation trigger. |
contact_email | string | Yes | Contact identifier. Created automatically if it doesn't exist. |
properties | object | No | Arbitrary key/value payload. Available to step variables and conditions. |
Run object
{
"id": "run_abc123",
"automation_id": "auto_abc123",
"contact_id": "ct_xyz789",
"status": "in_progress",
"current_step_index": 1,
"started_at": "2026-05-10T09:00:00Z",
"completed_at": null,
"next_run_at": "2026-05-11T09:00:00Z"
}
Run status values: in_progress, completed, cancelled, failed.
Use cases
- Welcome drip —
user.signed_up→ welcome email → wait 1 day → tips email → wait 3 days → "ready to upgrade?" email. - Cart abandonment —
cart.abandoned→ wait 1 hour → reminder email → wait 24 hours → discount email (branch oncart.recovered). - Post-purchase follow-up —
order.delivered→ wait 3 days → "how was it?" email → wait 7 days → review request. - Behavioral onboarding —
feature.first_used→ contextual tip email;feature.unused_after_7_days→ nudge email. - Re-engagement —
contact_added_to_segment(segment: "inactive 30 days") → re-engagement email → branch onemail.clicked.
Plan limits
| Plan | Automations | Active runs / mo |
|---|---|---|
| Free | Not available | — |
| Pro | 25 | 50,000 |
| Business | 250 | 500,000 |
| Enterprise | Unlimited | Custom |
Related
- Send email API — used by
send_emailsteps under the hood. - Templates API — manage
template_idreferences. - Visual Editor — build the templates referenced by automation steps.