Skip to main content
POST
/
v1
/
programs
/
{programId}
/
automations
Create an automation
curl --request POST \
  --url https://api.scrip.dev/v1/programs/{programId}/automations \
  --header 'Content-Type: application/json' \
  --header 'X-API-Key: <api-key>' \
  --data @- <<EOF
{
  "event_name": "weekly_reminder",
  "name": "Weekly points reminder",
  "scope": "participants",
  "trigger": {
    "type": "cron",
    "cron_expression": "0 9 * * 1",
    "schedule_config": {},
    "schedule_type": "INTERVAL",
    "timezone": "America/New_York",
    "trigger_at": "2026-02-01T09:00:00Z"
  },
  "description": "Sends a weekly reminder event to VIP participants",
  "filter_hints": [
    {}
  ],
  "guard_condition": "participant.counters.purchases >= 1",
  "participant_filter": "participant.tags.exists(t, t == 'vip')",
  "participant_id": "550e8400-e29b-41d4-a716-446655440001",
  "payload": {}
}
EOF
import requests

url = "https://api.scrip.dev/v1/programs/{programId}/automations"

payload = {
"event_name": "weekly_reminder",
"name": "Weekly points reminder",
"scope": "participants",
"trigger": {
"type": "cron",
"cron_expression": "0 9 * * 1",
"schedule_config": {},
"schedule_type": "INTERVAL",
"timezone": "America/New_York",
"trigger_at": "2026-02-01T09:00:00Z"
},
"description": "Sends a weekly reminder event to VIP participants",
"filter_hints": [{}],
"guard_condition": "participant.counters.purchases >= 1",
"participant_filter": "participant.tags.exists(t, t == 'vip')",
"participant_id": "550e8400-e29b-41d4-a716-446655440001",
"payload": {}
}
headers = {
"X-API-Key": "<api-key>",
"Content-Type": "application/json"
}

response = requests.post(url, json=payload, headers=headers)

print(response.text)
const options = {
method: 'POST',
headers: {'X-API-Key': '<api-key>', 'Content-Type': 'application/json'},
body: JSON.stringify({
event_name: 'weekly_reminder',
name: 'Weekly points reminder',
scope: 'participants',
trigger: {
type: 'cron',
cron_expression: '0 9 * * 1',
schedule_config: {},
schedule_type: 'INTERVAL',
timezone: 'America/New_York',
trigger_at: '2026-02-01T09:00:00Z'
},
description: 'Sends a weekly reminder event to VIP participants',
filter_hints: [{}],
guard_condition: 'participant.counters.purchases >= 1',
participant_filter: 'participant.tags.exists(t, t == \'vip\')',
participant_id: '550e8400-e29b-41d4-a716-446655440001',
payload: {}
})
};

fetch('https://api.scrip.dev/v1/programs/{programId}/automations', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));
<?php

$curl = curl_init();

curl_setopt_array($curl, [
CURLOPT_URL => "https://api.scrip.dev/v1/programs/{programId}/automations",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'event_name' => 'weekly_reminder',
'name' => 'Weekly points reminder',
'scope' => 'participants',
'trigger' => [
'type' => 'cron',
'cron_expression' => '0 9 * * 1',
'schedule_config' => [

],
'schedule_type' => 'INTERVAL',
'timezone' => 'America/New_York',
'trigger_at' => '2026-02-01T09:00:00Z'
],
'description' => 'Sends a weekly reminder event to VIP participants',
'filter_hints' => [
[

]
],
'guard_condition' => 'participant.counters.purchases >= 1',
'participant_filter' => 'participant.tags.exists(t, t == \'vip\')',
'participant_id' => '550e8400-e29b-41d4-a716-446655440001',
'payload' => [

]
]),
CURLOPT_HTTPHEADER => [
"Content-Type: application/json",
"X-API-Key: <api-key>"
],
]);

$response = curl_exec($curl);
$err = curl_error($curl);

curl_close($curl);

if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}
package main

import (
"fmt"
"strings"
"net/http"
"io"
)

func main() {

url := "https://api.scrip.dev/v1/programs/{programId}/automations"

payload := strings.NewReader("{\n \"event_name\": \"weekly_reminder\",\n \"name\": \"Weekly points reminder\",\n \"scope\": \"participants\",\n \"trigger\": {\n \"type\": \"cron\",\n \"cron_expression\": \"0 9 * * 1\",\n \"schedule_config\": {},\n \"schedule_type\": \"INTERVAL\",\n \"timezone\": \"America/New_York\",\n \"trigger_at\": \"2026-02-01T09:00:00Z\"\n },\n \"description\": \"Sends a weekly reminder event to VIP participants\",\n \"filter_hints\": [\n {}\n ],\n \"guard_condition\": \"participant.counters.purchases >= 1\",\n \"participant_filter\": \"participant.tags.exists(t, t == 'vip')\",\n \"participant_id\": \"550e8400-e29b-41d4-a716-446655440001\",\n \"payload\": {}\n}")

req, _ := http.NewRequest("POST", url, payload)

req.Header.Add("X-API-Key", "<api-key>")
req.Header.Add("Content-Type", "application/json")

res, _ := http.DefaultClient.Do(req)

defer res.Body.Close()
body, _ := io.ReadAll(res.Body)

fmt.Println(string(body))

}
HttpResponse<String> response = Unirest.post("https://api.scrip.dev/v1/programs/{programId}/automations")
.header("X-API-Key", "<api-key>")
.header("Content-Type", "application/json")
.body("{\n \"event_name\": \"weekly_reminder\",\n \"name\": \"Weekly points reminder\",\n \"scope\": \"participants\",\n \"trigger\": {\n \"type\": \"cron\",\n \"cron_expression\": \"0 9 * * 1\",\n \"schedule_config\": {},\n \"schedule_type\": \"INTERVAL\",\n \"timezone\": \"America/New_York\",\n \"trigger_at\": \"2026-02-01T09:00:00Z\"\n },\n \"description\": \"Sends a weekly reminder event to VIP participants\",\n \"filter_hints\": [\n {}\n ],\n \"guard_condition\": \"participant.counters.purchases >= 1\",\n \"participant_filter\": \"participant.tags.exists(t, t == 'vip')\",\n \"participant_id\": \"550e8400-e29b-41d4-a716-446655440001\",\n \"payload\": {}\n}")
.asString();
require 'uri'
require 'net/http'

url = URI("https://api.scrip.dev/v1/programs/{programId}/automations")

http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true

request = Net::HTTP::Post.new(url)
request["X-API-Key"] = '<api-key>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"event_name\": \"weekly_reminder\",\n \"name\": \"Weekly points reminder\",\n \"scope\": \"participants\",\n \"trigger\": {\n \"type\": \"cron\",\n \"cron_expression\": \"0 9 * * 1\",\n \"schedule_config\": {},\n \"schedule_type\": \"INTERVAL\",\n \"timezone\": \"America/New_York\",\n \"trigger_at\": \"2026-02-01T09:00:00Z\"\n },\n \"description\": \"Sends a weekly reminder event to VIP participants\",\n \"filter_hints\": [\n {}\n ],\n \"guard_condition\": \"participant.counters.purchases >= 1\",\n \"participant_filter\": \"participant.tags.exists(t, t == 'vip')\",\n \"participant_id\": \"550e8400-e29b-41d4-a716-446655440001\",\n \"payload\": {}\n}"

response = http.request(request)
puts response.read_body
{
  "created_at": "2024-01-15T10:30:00Z",
  "cron_expression": "0 9 * * 1",
  "description": "Sends a weekly reminder event to VIP participants",
  "error_message": "participant not found",
  "event_name": "weekly_reminder",
  "execution_completed_at": "2024-01-15T09:00:42Z",
  "execution_error": "fanout aborted: program is archived",
  "execution_started_at": "2024-01-15T09:00:00Z",
  "execution_status": "completed",
  "filter_hints": [
    {}
  ],
  "guard_condition": "participant.counters.purchases >= 1",
  "id": "990e8400-e29b-41d4-a716-446655440000",
  "last_error": "failed to enqueue event: queue unavailable",
  "last_evaluated_at": "2024-01-15T10:30:00Z",
  "last_run_at": "2024-01-15T09:00:00Z",
  "name": "Weekly points reminder",
  "next_run_at": "2024-01-22T09:00:00Z",
  "participant_filter": "participant.tags.exists(t, t == 'vip')",
  "participant_id": "550e8400-e29b-41d4-a716-446655440001",
  "participants_processed": 150,
  "participants_skipped_error": 0,
  "participants_total": 150,
  "payload": {},
  "processed_at": "2024-02-01T09:00:05Z",
  "program_id": "550e8400-e29b-41d4-a716-446655440000",
  "schedule_config": {},
  "schedule_type": "INTERVAL",
  "scope": "participants",
  "source": "api",
  "status": "active",
  "timezone": "America/New_York",
  "trigger_at": "2026-02-01T09:00:00Z",
  "trigger_type": "cron",
  "updated_at": "2024-01-15T10:30:00Z",
  "warnings": [
    {
      "code": "unknown_state_key",
      "key": "purchaseCnt",
      "kind": "counter",
      "message": "unknown counter \"purchaseCnt\" — no rule in this program writes it; did you mean \"purchase_count\"?",
      "scope": "participant",
      "suggestion": "purchase_count"
    }
  ]
}
{
"code": "bad_request",
"details": {
"expected": "uuid",
"field": "asset_id",
"fields": [
{
"expected": "<unknown>",
"field": "amount",
"message": "This field is required",
"reason": "required",
"received": "-10.00"
}
],
"reason": "invalid",
"received": "not-a-uuid"
},
"message": "Invalid request parameters"
}
{
"code": "unauthorized",
"details": {
"expected": "uuid",
"field": "asset_id",
"fields": [
{
"expected": "<unknown>",
"field": "amount",
"message": "This field is required",
"reason": "required",
"received": "-10.00"
}
],
"reason": "invalid",
"received": "not-a-uuid"
},
"message": "Missing or invalid credentials"
}
{
"code": "not_found",
"details": {
"expected": "uuid",
"field": "asset_id",
"fields": [
{
"expected": "<unknown>",
"field": "amount",
"message": "This field is required",
"reason": "required",
"received": "-10.00"
}
],
"reason": "invalid",
"received": "not-a-uuid"
},
"message": "Resource not found"
}
{
"code": "conflict",
"details": {
"expected": "uuid",
"field": "asset_id",
"fields": [
{
"expected": "<unknown>",
"field": "amount",
"message": "This field is required",
"reason": "required",
"received": "-10.00"
}
],
"reason": "invalid",
"received": "not-a-uuid"
},
"message": "Resource already exists or state conflict"
}
{
"code": "unsupported_media_type",
"details": {
"expected": "uuid",
"field": "asset_id",
"fields": [
{
"expected": "<unknown>",
"field": "amount",
"message": "This field is required",
"reason": "required",
"received": "-10.00"
}
],
"reason": "invalid",
"received": "not-a-uuid"
},
"message": "Content-Type must be application/json"
}
{
"code": "internal_error",
"message": "An internal error occurred"
}
Creates an automation scoped to a program. At minimum you must provide name, trigger.type, scope, and event_name. The trigger.type can be cron, one_time, immediate, or participant_state. The scope determines whether the automation fires once at the program level or fans out across individual participants. Not all trigger and scope combinations are valid. The immediate and participant_state trigger types only support participants scope. If you specify an invalid combination, the request will be rejected with a validation error. For one_time automations with scope set to program, you can optionally include participant_id to target a specific participant. This sends the event to that participant rather than to the program at large. When the automation fires, it generates an event with the specified event_name and optional payload. That event enters the rules engine like any other event, so you can attach rule logic to it without additional wiring.
For usage patterns and examples, see the Automations guide.

Authorizations

X-API-Key
string
header
required

API key passed in the X-API-Key header.

Path Parameters

programId
string<uuid>
required

Program ID

Body

application/json

Automation configuration

event_name
string
required

The event name generated when this automation fires (1-255 chars)

Required string length: 1 - 255
Example:

"weekly_reminder"

name
string
required

Human-readable label for this automation (1-255 chars)

Required string length: 1 - 255
Example:

"Weekly points reminder"

scope
enum<string>
required

Whether the automation fires once at the program level or fans out per participant: program or participants

Available options:
program,
participants
Example:

"participants"

trigger
object
required

Trigger configuration (type, schedule, timing)

description
string

Optional human-readable description of what this automation does

Example:

"Sends a weekly reminder event to VIP participants"

filter_hints
object[]

Optimization hints for the participant filter (e.g., has_tag, has_attribute, has_counter)

guard_condition
string

CEL expression evaluated at trigger time; skips the participant if false

Example:

"participant.counters.purchases >= 1"

participant_filter
string

CEL expression that determines which participants are enrolled (scope=participants only)

Example:

"participant.tags.exists(t, t == 'vip')"

participant_id
string<uuid>

Target participant for program-scoped one-time automations (scope=program, one_time trigger only)

Example:

"550e8400-e29b-41d4-a716-446655440001"

payload
object

Custom data included in the generated event

Response

Automation created

created_at
string<date-time>

When this automation was created

Example:

"2024-01-15T10:30:00Z"

cron_expression
string

Cron expression defining the recurring schedule (cron trigger only)

Example:

"0 9 * * 1"

description
string

Optional human-readable description of what this automation does

Example:

"Sends a weekly reminder event to VIP participants"

error_message
string

Error message if the one-time automation failed

Example:

"participant not found"

event_name
string

The event name generated when this automation fires

Example:

"weekly_reminder"

execution_completed_at
string<date-time>

When the current fan-out execution completed

Example:

"2024-01-15T09:00:42Z"

execution_error
string

Error message if the fan-out execution failed, or JSON-encoded diagnostics for completed runs with CEL eval skips

Example:

"fanout aborted: program is archived"

execution_started_at
string<date-time>

When the current fan-out execution started

Example:

"2024-01-15T09:00:00Z"

execution_status
string

Current fan-out execution state: idle, pending, executing, completed, or failed (participant-scoped only)

Example:

"completed"

filter_hints
object[]

Optimization hints for the participant filter (e.g., has_tag, has_attribute, has_counter)

guard_condition
string

CEL expression evaluated at trigger time; skips the participant if false

Example:

"participant.counters.purchases >= 1"

id
string<uuid>

Unique identifier for this automation

Example:

"990e8400-e29b-41d4-a716-446655440000"

last_error
string

Error message from the most recent cron execution, if any (cron trigger only)

Example:

"failed to enqueue event: queue unavailable"

last_evaluated_at
string<date-time>

When participant filters were last evaluated (participant_state trigger only)

Example:

"2024-01-15T10:30:00Z"

last_run_at
string<date-time>

When this automation last fired (cron trigger only)

Example:

"2024-01-15T09:00:00Z"

name
string

Human-readable label for this automation

Example:

"Weekly points reminder"

next_run_at
string<date-time>

When this automation will next fire (cron trigger only)

Example:

"2024-01-22T09:00:00Z"

participant_filter
string

CEL expression that determines which participants are enrolled

Example:

"participant.tags.exists(t, t == 'vip')"

participant_id
string<uuid>

Target participant for program-scoped one-time automations

Example:

"550e8400-e29b-41d4-a716-446655440001"

participants_processed
integer

Participants processed so far in the current fan-out run

Example:

150

participants_skipped_error
integer

Participants skipped because participant_filter or guard_condition CEL evaluation errored

Example:

0

participants_total
integer

Total participants to process in the current fan-out run

Example:

150

payload
object

Custom data included in the generated event

processed_at
string<date-time>

When this one-time automation was processed

Example:

"2024-02-01T09:00:05Z"

program_id
string<uuid>

The program this automation belongs to

Example:

"550e8400-e29b-41d4-a716-446655440000"

schedule_config
object

Configuration for the schedule type (participant_state trigger only)

schedule_type
string

How participant subscriptions are scheduled: ATTRIBUTE_DATE, INTERVAL, CRON, or THRESHOLD (participant_state trigger only)

Example:

"INTERVAL"

scope
string

Whether the automation fires once at the program level or fans out per participant: program or participants

Example:

"participants"

source
string

How this automation was created: api or rule_action

Example:

"api"

status
string

Current state: active, paused, completed, failed, or archived

Example:

"active"

timezone
string

IANA timezone used for scheduling (e.g., America/New_York)

Example:

"America/New_York"

trigger_at
string<date-time>

When this automation is scheduled to fire (one_time trigger only, RFC 3339)

Example:

"2026-02-01T09:00:00Z"

trigger_type
string

How this automation is triggered: cron, one_time, participant_state, or immediate

Example:

"cron"

updated_at
string<date-time>

When this automation was last updated

Example:

"2024-01-15T10:30:00Z"

warnings
object[]

Non-blocking advisories about participant_filter/guard_condition — e.g. a counter/tag/attribute key no rule in the program writes. Present on create/update only; never blocks the save.