Sendry Docs
API Reference

Automations

Manage event-triggered email workflows, their steps, and per-contact runs.

Automations are event-triggered workflows that run a sequence of steps per contact. This page covers the REST endpoints for building, activating, and inspecting them. For trigger types, step config shapes, and re-entry behavior, see the Automations guide.

All endpoints require Authorization: Bearer <api_key>. Mutation endpoints require full_access scope; reads accept read_only and above.


Create automation

POST /v1/automations

Requires full_access scope. The automation is created in draft status.

Request body

FieldTypeRequiredDescription
namestringYesAutomation name. 1-200 characters.
trigger_typestringYesOne of event, contact_added_to_segment, schedule, manual.
descriptionstringNoFree-form description. Max 1000 characters.
trigger_configobjectNoTrigger parameters. { "event_name": "..." } is required when trigger_type is event.
entry_segment_idstringNoSegment a contact must be in before entering the automation.
reentry_policystringNoonce_per_contact, cooldown, or always. Default once_per_contact.
reentry_cooldown_secondsintegerNoCooldown window when reentry_policy is cooldown. Minimum 1.

Example request

{
  "name": "Welcome series",
  "trigger_type": "event",
  "trigger_config": { "event_name": "user.signed_up" },
  "reentry_policy": "once_per_contact"
}

Response

{
  "id": "auto_abc123",
  "name": "Welcome series",
  "description": null,
  "status": "draft",
  "trigger_type": "event",
  "trigger_config": { "event_name": "user.signed_up" },
  "entry_segment_id": null,
  "reentry_policy": "once_per_contact",
  "reentry_cooldown_seconds": null,
  "total_runs": 0,
  "active_runs": 0,
  "completed_runs": 0,
  "failed_runs": 0,
  "created_at": "2026-05-10T09:00:00Z",
  "updated_at": "2026-05-10T09:00:00Z"
}

List automations

GET /v1/automations

Requires read_only scope.

Query parameters

ParameterTypeDefaultDescription
limitnumber50Results per page (1-100).
cursorstringPagination cursor from the previous response's next_cursor.
statusstringFilter by status: draft, active, paused, archived.

Response

{
  "data": [
    {
      "id": "auto_abc123",
      "name": "Welcome series",
      "description": null,
      "status": "active",
      "trigger_type": "event",
      "trigger_config": { "event_name": "user.signed_up" },
      "entry_segment_id": null,
      "reentry_policy": "once_per_contact",
      "reentry_cooldown_seconds": null,
      "total_runs": 128,
      "active_runs": 4,
      "completed_runs": 120,
      "failed_runs": 4,
      "created_at": "2026-05-10T09:00:00Z",
      "updated_at": "2026-05-12T11:30:00Z"
    }
  ],
  "has_more": false,
  "next_cursor": null
}

Pagination is cursor-based. Pass next_cursor as the cursor parameter to get the next page.


Get automation

GET /v1/automations/:id

Requires read_only scope. Returns the same automation object as Create.


Update automation

PATCH /v1/automations/:id

Requires full_access scope. Only draft or paused automations can be edited; other statuses return 409 invalid_status. trigger_type is immutable.

Request body

All fields are optional. Send only the fields you want to change.

FieldTypeRequiredDescription
namestringNoAutomation name. 1-200 characters.
descriptionstring | nullNoSet to null to clear. Max 1000 characters.
trigger_configobjectNoReplaces the trigger parameters.
entry_segment_idstring | nullNoSet to null to clear.
reentry_policystringNoonce_per_contact, cooldown, or always.
reentry_cooldown_secondsinteger | nullNoCooldown window. Set to null to clear. Minimum 1.

Example request

{
  "name": "Welcome series v2",
  "trigger_config": { "event_name": "user.completed_onboarding" }
}

Response

Returns the updated automation object (same shape as Create).


Delete automation

DELETE /v1/automations/:id

Requires full_access scope. Only draft or archived automations may be deleted; other statuses return 409 invalid_status.

{
  "deleted": true
}

Activate automation

POST /v1/automations/:id/activate

Requires full_access scope. The automation must have at least one step, otherwise the request returns 409 no_steps. Activating an already-active automation is a no-op; archived automations cannot be activated (409).

Returns the automation object with status set to active.


Pause automation

POST /v1/automations/:id/pause

Requires full_access scope. Existing runs continue; new triggers are ignored. Only active automations can be paused (409 otherwise).

Returns the automation object with status set to paused.


Archive automation

POST /v1/automations/:id/archive

Requires full_access scope. New triggers are ignored and run history is retained. Archiving an already-archived automation is a no-op.

Returns the automation object with status set to archived.


Trigger a manual automation

POST /v1/automations/:id/trigger

Requires full_access scope. Enqueues a run for an automation whose trigger_type is manual, bypassing the configured trigger. The automation must be active, and the run is quota-checked against your plan. Using this endpoint on a non-manual automation returns 409 invalid_trigger_type.

Request body

At least one of contact_id or contact_email is required.

FieldTypeRequiredDescription
contact_idstringNo*ID of the contact to run the automation for.
contact_emailstringNo*Email of the contact. Created automatically if it does not exist.
contextobjectNoArbitrary key/value payload available to step variables and conditions.

Example request

{
  "contact_email": "jane@acme.com",
  "context": { "plan": "pro" }
}

Response

{
  "run_id": "run_abc123"
}

List automation steps

GET /v1/automations/:id/steps

Requires read_only scope. Steps are returned in execution order.

Response

{
  "data": [
    {
      "id": "step_def456",
      "automation_id": "auto_abc123",
      "parent_step_id": null,
      "branch_label": null,
      "position": 0,
      "type": "send_email",
      "config": {
        "type": "send_email",
        "from": "Acme <hello@acme.com>",
        "subject": "Welcome to Acme",
        "html": "<h1>Welcome!</h1>"
      },
      "created_at": "2026-05-10T09:05:00Z",
      "updated_at": "2026-05-10T09:05:00Z"
    }
  ]
}

Add step

POST /v1/automations/:id/steps

Requires full_access scope. The automation must be draft or paused. If position is omitted the step is appended after the highest existing position.

Request body

FieldTypeRequiredDescription
configobjectYesStep configuration. Must include a type: send_email, wait, branch, or ab_split.
parent_step_idstring | nullNoParent step for branching paths.
branch_labelstring | nullNoWhich branch this step belongs to (e.g. a, b).
positionintegerNoExecution order. Minimum 0. Defaults to append.

The shape of config depends on its type. See the step type reference. ab_split weights must sum to 100. Branch steps require condition.op.

Example request

{
  "config": {
    "type": "wait",
    "duration_seconds": 86400
  }
}

Response

Returns the created step object (same shape as List automation steps). type is copied from config.type.


Update step

PATCH /v1/automations/:id/steps/:stepId

Requires full_access scope. The automation must be draft or paused. All fields are optional.

Request body

FieldTypeRequiredDescription
configobjectNoReplacement step configuration.
parent_step_idstring | nullNoParent step for branching paths.
branch_labelstring | nullNoWhich branch this step belongs to.
positionintegerNoNew execution order. Siblings at or after this position are shifted up.

Returns the updated step object.


Delete step

DELETE /v1/automations/:id/steps/:stepId

Requires full_access scope. The automation must be draft or paused.

{
  "deleted": true
}

List automation runs

GET /v1/automations/:id/runs

Requires read_only scope.

Query parameters

ParameterTypeDefaultDescription
limitnumber50Results per page (1-100).
cursorstringPagination cursor from the previous response's next_cursor.
statusstringFilter by run status: pending, in_progress, completed, failed, cancelled.

Response

{
  "data": [
    {
      "id": "run_abc123",
      "automation_id": "auto_abc123",
      "contact_id": "con_abc123",
      "contact_email": "jane@acme.com",
      "trigger_event_id": "evt_abc123",
      "status": "in_progress",
      "current_step_id": "step_def456",
      "context": { "plan": "pro" },
      "started_at": "2026-05-10T09:00:00Z",
      "completed_at": null,
      "failed_at": null,
      "failure_reason": null,
      "created_at": "2026-05-10T09:00:00Z",
      "updated_at": "2026-05-10T09:00:01Z"
    }
  ],
  "has_more": false,
  "next_cursor": null
}

A run starts as pending, moves to in_progress while steps execute, and ends as completed, failed, or cancelled.


Enqueue a run manually

POST /v1/automations/:id/runs

Requires full_access scope. Creates and enqueues a run for an active automation, bypassing the configured trigger (any trigger type). The automation must have at least one step. At least one of contact_id or contact_email is required.

Request body

FieldTypeRequiredDescription
contact_idstringNo*ID of the contact to run for.
contact_emailstringNo*Email of the contact.
contextobjectNoArbitrary key/value payload for the run.

Example request

{
  "contact_id": "con_abc123",
  "context": { "source": "dashboard" }
}

Response

Returns the created run object (same shape as List automation runs), typically with status: "pending".


Get automation run

GET /v1/automations/:id/runs/:runId

Requires read_only scope.

Response

{
  "id": "run_abc123",
  "automation_id": "auto_abc123",
  "contact_id": "con_abc123",
  "contact_email": "jane@acme.com",
  "trigger_event_id": "evt_abc123",
  "status": "completed",
  "current_step_id": null,
  "context": { "plan": "pro" },
  "started_at": "2026-05-10T09:00:00Z",
  "completed_at": "2026-05-11T09:00:00Z",
  "failed_at": null,
  "failure_reason": null,
  "created_at": "2026-05-10T09:00:00Z",
  "updated_at": "2026-05-11T09:00:00Z"
}

Cancel automation run

POST /v1/automations/:id/runs/:runId/cancel

Requires full_access scope. Cancelling a run that is already completed, failed, or cancelled is a no-op.

Returns the run object with status set to cancelled.


List run steps

GET /v1/automations/:id/runs/:runId/steps

Requires read_only scope. Returns one record per step the run has reached, in creation order.

Response

{
  "data": [
    {
      "id": "runstep_ghi789",
      "run_id": "run_abc123",
      "step_id": "step_def456",
      "status": "completed",
      "email_id": "email_abc123",
      "branch_taken": null,
      "scheduled_for": null,
      "started_at": "2026-05-10T09:00:00Z",
      "completed_at": "2026-05-10T09:00:01Z",
      "error": null,
      "created_at": "2026-05-10T09:00:00Z"
    }
  ]
}

Run step status values: pending, in_progress, completed, skipped, failed.


Plan limits

PlanAutomationsRuns / month
FreeNot available0
ProUnlimited10,000
BusinessUnlimited100,000
EnterpriseUnlimitedUnlimited

Runs are counted per calendar month. On the Free plan, creating an automation returns 403 automation_not_available. Exhausting the monthly run quota returns 429 plan_limit_reached.

On this page