This documentation URL will be retired soon. Start using the Ranla API at https://api.ranla.ai. Docs: docs.ranla.ai.

Automations

Create and manage event-driven transactional automations with a Bearer stx_… API key (or dashboard session).

Base URL: https://api.supersendtx.com

You can also build flows visually in the dashboard canvas under Automations.


Authentication

Authorization: Bearer stx_…

Create an automation

POST /automations

Creates a draft. Activate it before events will match.

{
  "name": "Welcome email",
  "trigger": {
    "type": "event",
    "event": "user.created"
  },
  "steps": [
    {
      "type": "send_email",
      "email": {
        "from": "[email protected]",
        "to": "{{event.email}}",
        "subject": "Welcome",
        "html": "<p>Hi {{event.data.name}}</p>"
      }
    }
  ]
}

Examples below are generated from src/lib/dx/snippets.ts (same source as the dashboard).

curl

curl -X POST https://api.supersendtx.com/automations \
  -H "Authorization: Bearer stx_…" \
  -H "Content-Type: application/json" \
  -d '{"name":"Welcome email","trigger":{"type":"event","event":"user.created"},"steps":[{"type":"send_email","email":{"from":"[email protected]","to":"{{event.email}}","subject":"Welcome","html":"<p>Hi {{event.data.name}}</p>"}}]}'

npm

npm install supersendtx

import { SuperSendTX } from 'supersendtx'

const client = new SuperSendTX('stx_…')

const { automation } = await client.automations.create({
  name: 'Welcome email',
  trigger: { type: 'event', event: 'user.created' },
  steps: [
    {
      type: 'send_email',
      email: {
        from: '[email protected]',
        to: '{{event.email}}',
        subject: 'Welcome',
        html: '<p>Hi {{event.data.name}}</p>',
      },
    },
  ],
})

await client.automations.activate(automation.id)

CLI

SUPERSENDTX_API_KEY=stx_… npx -y --package=supersendtx-cli -- supersendtx automations create --file ./welcome.json
SUPERSENDTX_API_KEY=stx_… npx -y --package=supersendtx-cli -- supersendtx automations activate --id "$AUTOMATION_ID"

welcome.json should match the request body above.


Endpoints

Method Path Notes
GET /automations List
POST /automations Create draft
GET /automations/{id} Get
PATCH /automations/{id} Update name/trigger/steps
DELETE /automations/{id} Delete
POST /automations/{id} { "action": "activate" | "pause" }
GET /automations/runs Optional ?automation_id=
GET /automations/runs/{id} Run detail
POST /automations/runs/{id} { "action": "cancel" | "retry" }

Step types

Type Purpose
send_email Send via the same transactional send path as POST /emails — inline subject/html or a published email.template
send_sms Send SMS via Twilio — requires a connected integration and sms.to + sms.body
delay Wait seconds before the next step
condition Continue only if true; false stops the run (not if/else branching)
wait_for_event Pause until another event arrives (optional timeout_seconds; on_timeout continue or fail, default fail)

Trigger options:

Key Meaning
cancel_on_events Array of event names that cancel queued, running, or waiting runs for the same recipient when fired.
once_per_contact true to enrol each person at most once, ever (matched on the event's email or user_id). A second matching event is skipped and reported in the POST /events response as enrollment_skips with reason: "once_per_contact".
cooldown_days Integer 1–3650. Skip enrolment when the same person already had a run on this automation within the last N days (reason: "cooldown").

Dashboard dry-runs and test sends are never deduplicated, and a retry of a failed run bypasses both rules. The check and the enrolment run inside one transaction under an advisory lock keyed on the automation and the person, so two copies of the same event arriving at once (a retried webhook, two workers) still enrol once.

Placeholders in email and SMS steps, in any string:

Placeholder Resolves to
{{event.email}}, {{event.user_id}}, {{event.data.foo}} The triggering event.
{{contact.first_name}}, {{contact.last_name}}, {{contact.email}}, {{contact.status}}, {{contact.attributes.plan}} The contact matched by the event's email or user_id (→ external_id), loaded when the step runs.
{{contact_at_enrollment.attributes.plan}} The same snapshot, frozen when the run was created.
{{unsubscribe_url}} The managed unsubscribe link (product / newsletter category).

A Liquid-style default is accepted: {{contact.first_name | default:"there"}}. An unresolved placeholder renders as empty text, never as literal braces.

Conditions on the contact: a condition step whose path starts with contact. reads the contact fresh at step time, so a 14-day delay followed by { "type": "condition", "path": "contact.attributes.subscribed", "operator": "not_equals", "value": true } means "still not subscribed when the step runs". On contact. and contact_at_enrollment. paths, equals / not_equals compare as text, the same way segments do: booleans and numbers are stringified, so "value": true and "value": "true" both match an attribute stored as true or "true" (attributes are JSON written by whichever integration last touched the contact, and the stored type is not visible to the author). A missing contact or attribute equals only null. Event paths (event.data.*) stay strict, because the payload is typed by your own code. contact_at_enrollment. paths read the frozen snapshot.

Category and unsubscribe: inline send_email steps default to "category": "product" — the send honours product opt-outs, carries List-Unsubscribe headers, and replaces {{unsubscribe_url}} in html and text with the managed link. The placeholder is replaced, never appended, so include it; the API returns a warnings array when a product/newsletter step has none. Set "category": "transactional" only for genuinely transactional mail (receipts, OTPs). Template-backed steps inherit the template's category unless category is set on the step. A recipient who opted out of the category completes the run with a category_opt_out step output instead of failing it.

{
  "name": "Signup → still free after 14 days",
  "trigger": { "type": "event", "event": "signup", "cancel_on_events": ["subscription_checkout"], "once_per_contact": true },
  "steps": [
    { "type": "delay", "seconds": 1209600 },
    { "type": "condition", "path": "contact.attributes.subscribed", "operator": "not_equals", "value": true },
    {
      "type": "send_email",
      "email": {
        "from": "[email protected]",
        "to": "{{event.email}}",
        "subject": "Two weeks in",
        "html": "<p>Hey {{contact.first_name | default:\"there\"}},</p><p>…</p><p><a href=\"{{unsubscribe_url}}\">Unsubscribe</a></p>",
        "text": "Hey {{contact.first_name | default:\"there\"}},\n\n…\n\nUnsubscribe: {{unsubscribe_url}}"
      }
    }
  ]
}

Conversions: a conversion whose last touch inside the goal window was a send from an automation is credited to it (attributed_automation_id / attributed_run_id on the conversion). GET /automations/{id} returns conversions: { total, revenue_cents, mix }; GET /conversions?automation_id= lists them.

SMS example (send_sms)

Connect Twilio first (integrations twilio connect), then create an automation:

{
  "name": "Auth OTP (SMS)",
  "trigger": { "type": "event", "event": "auth.code_requested" },
  "steps": [
    {
      "type": "send_sms",
      "sms": {
        "to": "{{event.data.phone}}",
        "body": "Your code is {{event.data.code}}. Expires in 10 min."
      }
    }
  ]
}
SUPERSENDTX_API_KEY=stx_… npx -y --package=supersendtx-cli -- supersendtx integrations twilio connect \
  --account-sid AC… --auth-token … --from +15551234567
SUPERSENDTX_API_KEY=stx_… npx -y --package=supersendtx-cli -- supersendtx automations create --file ./otp-sms.json
SUPERSENDTX_API_KEY=stx_… npx -y --package=supersendtx-cli -- supersendtx automations activate --id "$AUTOMATION_ID"

Template example (mutually exclusive with inline subject / html / text):

{
  "type": "send_email",
  "email": {
    "from": "[email protected]",
    "to": "{{event.email}}",
    "template": {
      "id": "welcome",
      "variables": { "name": "{{event.data.name}}" }
    }
  }
}

Trigger the flow

After activate, send events with POST /events or:

supersendtx events send --name user.created --email [email protected] --data '{"name":"Ada"}'