Automations
Work the sandbox starts on its own, and the approvals it parks waiting for you
On this page(11 sections)
- Things that wake an agent on their own
- Create or edit an automation
- What can trigger an automation here
- Turn an automation on or off
- Delete an automation
- Rotate an automation's webhook token or intake key
- Fire an automation by hand
- Who has written to a listener source
- Automations waiting for a yes
- Let a held automation run
- Drop a held automation
Scheduled and triggered work: what can trigger one here, what is configured, and switching one on or off, deleting it or firing it by hand. The other half is the approval queue — an automation set to ask first lands there each time it would have run.
11 calls. Pick one to open it, or use the list on the right.
GET/automationsThings that wake an agent on their own
Every automation with its recent runs and when it fires next.
What you send
Nothing. Call it as it is.
What comes back
| Field | Type |
|---|---|
automations | object[] |
idThe automation's id | string |
triggerWhat sets it off: a schedule,… | object |
when kind is "schedule" | shape |
cronWhen, in cron notation | string |
tzWhich clock the times in the… | string |
afterSessionsFire only once at least this… | integer |
when kind is "once" | shape |
atThe moment it fires, in milliseconds | integer |
when kind is "event" | shape |
dailyMaxHow many webhook calls a day… | integer |
when kind is "listener" | shape |
providerWhich service to listen to | string |
channelIdNarrow it to one channel or… | string |
eventTypeNarrow it to one kind of… | string |
mentionedOnly when the agent is actually… | boolean |
branchNarrow it to one branch, for… | string |
allowedOriginsWhich websites may reach the public… | string[] |
when kind is "workspace" | shape |
eventWhich happening | "turn.settled" | "agent.landed" | "deps.broken" | "deps.fixed" |
repoNarrow it to one repository | string |
guardA command run before the wake… | string |
promptWhat the woken agent is told | string |
webchatSettings for the public chat widget,… | object |
accessWho may write to it | "public" | "google" |
requireNameAsk a visitor for a name… | boolean |
antiBotHow to keep bots out: a… | "turnstile" | "pow" |
turnstileSiteKeyThe public half of those keys,… | string |
turnstileSecretThe private half, which the sandbox… | string |
googleClientIdThe site's own sign-in client id | string |
title | string |
greeting | string |
accent | string |
position | "top-right" | "top-left" | "bottom-right" | "bottom-left" |
dailyMessageMax | integer |
conversationMessageMax | integer |
sessionTtlMinutes | integer |
issuesSettings for the bug reporter, for… | object |
keyFromBrowsersLet a browser report with the… | boolean |
dailyReportMaxHow many reports a day this… | integer |
escalateAfterHow many more times a known… | integer |
antiBotMake a person's browser solve a… | "pow" |
titleThe dialog's heading | string |
promptThe line above the box they… | string |
thanksWhat it says once they have… | string |
askEmailAsk for an address to reply… | boolean |
accent | string |
captureCrashesCatch uncaught errors automatically, as well… | boolean |
allowedToolsNarrow the woken turn to these… | string[] |
modelsWhich models this automation may run… | object[] |
providerWhich provider serves this work | string |
modelWhich of its models | string |
effortHow hard this model should think,… | string |
thinkingWhether this model reasons before it… | boolean |
fastAsk for this model's work at… | boolean |
harnessWhich agentic loop runs it | "native" | "claude-code" |
accountWhich account pays for it | string |
actsAsWhich persona it speaks as | string |
sendersWho may talk to it, and… | object |
rulesWalked in order; the first rule… | object[] |
labelWhat to call these people on… | string |
idsSender ids, as the service names… | string[] |
groupsGroup ids the service reports on… | string[] |
actsAsWhich persona their wakes speak as | string |
requireApprovalHold their wakes for a person,… | boolean |
othersWhat a sender no rule names… | "allow" | "hold" | "ignore" |
requireApprovalHold every fire for a person… | boolean |
holdForSecondsHold each fire this long before… | number |
choreThis automation is a maintenance job,… | boolean |
enabledWhether it fires at all | boolean |
runs | object[] |
at | number |
outcome | "completed" | "skipped" | "error" | "interrupted" |
detail | string |
conversationId | string |
nextRun | number |
webhookTokenWhat a caller presents at /automations/{id}/fire,… | string |
ingestKeyWhat a client with no website… | string |
curl "$SANDBOX/automations" \
-H "x-intentic-control: $INTENTIC_TOKEN"import { sandbox } from "@intentic/sandbox-client";
const result = await sandbox.automations.list();POST/automationsCreate or edit an automation
Writes an automation by id. Nothing needs provisioning: the scheduler picks it up on its next sweep.
What you send
| Field | Type | Where |
|---|---|---|
idrequiredThe automation's id | string | body |
triggerrequiredWhat sets it off: a schedule,… | object | body |
when kind is "schedule" | shape | body |
cronrequiredWhen, in cron notation | string | body |
tzWhich clock the times in the… | string | body |
afterSessionsFire only once at least this… | integer | body |
when kind is "once" | shape | body |
atrequiredThe moment it fires, in milliseconds | integer | body |
when kind is "event" | shape | body |
dailyMaxHow many webhook calls a day… | integer | body |
when kind is "listener" | shape | body |
providerrequiredWhich service to listen to | string | body |
channelIdNarrow it to one channel or… | string | body |
eventTypeNarrow it to one kind of… | string | body |
mentionedOnly when the agent is actually… | boolean | body |
branchNarrow it to one branch, for… | string | body |
allowedOriginsWhich websites may reach the public… | string[] | body |
when kind is "workspace" | shape | body |
eventrequiredWhich happening | "turn.settled" | "agent.landed" | "deps.broken" | "deps.fixed" | body |
repoNarrow it to one repository | string | body |
guardA command run before the wake… | string | body |
promptrequiredWhat the woken agent is told | string | body |
webchatSettings for the public chat widget,… | object | body |
accessWho may write to it | "public" | "google" | body |
requireNameAsk a visitor for a name… | boolean | body |
antiBotHow to keep bots out: a… | "turnstile" | "pow" | body |
turnstileSiteKeyThe public half of those keys,… | string | body |
turnstileSecretThe private half, which the sandbox… | string | body |
googleClientIdThe site's own sign-in client id | string | body |
title | string | body |
greeting | string | body |
accent | string | body |
position | "top-right" | "top-left" | "bottom-right" | "bottom-left" | body |
dailyMessageMax | integer | body |
conversationMessageMax | integer | body |
sessionTtlMinutes | integer | body |
issuesSettings for the bug reporter, for… | object | body |
keyFromBrowsersLet a browser report with the… | boolean | body |
dailyReportMaxHow many reports a day this… | integer | body |
escalateAfterHow many more times a known… | integer | body |
antiBotMake a person's browser solve a… | "pow" | body |
titleThe dialog's heading | string | body |
promptThe line above the box they… | string | body |
thanksWhat it says once they have… | string | body |
askEmailAsk for an address to reply… | boolean | body |
accent | string | body |
captureCrashesCatch uncaught errors automatically, as well… | boolean | body |
allowedToolsNarrow the woken turn to these… | string[] | body |
modelsrequiredWhich models this automation may run… | object[] | body |
providerrequiredWhich provider serves this work | string | body |
modelrequiredWhich of its models | string | body |
effortHow hard this model should think,… | string | body |
thinkingWhether this model reasons before it… | boolean | body |
fastAsk for this model's work at… | boolean | body |
harnessWhich agentic loop runs it | "native" | "claude-code" | body |
accountWhich account pays for it | string | body |
actsAsWhich persona it speaks as | string | body |
sendersWho may talk to it, and… | object | body |
rulesrequiredWalked in order; the first rule… | object[] | body |
labelWhat to call these people on… | string | body |
idsSender ids, as the service names… | string[] | body |
groupsGroup ids the service reports on… | string[] | body |
actsAsWhich persona their wakes speak as | string | body |
requireApprovalHold their wakes for a person,… | boolean | body |
othersrequiredWhat a sender no rule names… | "allow" | "hold" | "ignore" | body |
requireApprovalHold every fire for a person… | boolean | body |
holdForSecondsHold each fire this long before… | number | body |
choreThis automation is a maintenance job,… | boolean | body |
enabledrequiredWhether it fires at all | boolean | body |
What comes back
| Field | Type |
|---|---|
okAlways true | true |
curl -X POST "$SANDBOX/automations" \
-H "x-intentic-control: $INTENTIC_TOKEN" \
-H "content-type: application/json" \
-d '{"id":"a1b2c3d4","trigger":{"kind":"schedule","cron":"…","tz":"…","afterSessions":1},"guard":"…","prompt":"Update the changelog for the last five commits.","webchat":{"access":"public","requireName":true,"antiBot":"turnstile","turnstileSiteKey":"…","turnstileSecret":"…","googleClientId":"a1b2c3d4","title":"Update the changelog","greeting":"…","accent":"…","position":"top-right","dailyMessageMax":1,"conversationMessageMax":1,"sessionTtlMinutes":1},"issues":{"keyFromBrowsers":true,"dailyReportMax":1,"escalateAfter":1,"antiBot":"pow","title":"Update the changelog","prompt":"Update the changelog for the last five commits.","thanks":"…","askEmail":true,"accent":"…","captureCrashes":true},"allowedTools":["…","…"],"models":[{"provider":"claude","model":"claude-sonnet-4-6","effort":"…","thinking":true,"fast":true,"harness":"native"},{"provider":"claude","model":"claude-haiku-4-6","effort":"…","thinking":true,"fast":true,"harness":"claude-code"}],"account":"work","actsAs":"…","senders":{"rules":[{"label":"Nightly changelog","ids":["a1b2c3d4","e5f6a7b8"],"groups":["…","…"],"actsAs":"…","requireApproval":true},{"label":"Release notes","ids":["a1b2c3d4","e5f6a7b8"],"groups":["…","…"],"actsAs":"…","requireApproval":true}],"others":"allow"},"requireApproval":true,"holdForSeconds":1,"chore":true,"enabled":true}'import { sandbox } from "@intentic/sandbox-client";
const result = await sandbox.automations.upsert({
"id": "a1b2c3d4",
"trigger": {
"kind": "schedule",
"cron": "…",
"tz": "…",
"afterSessions": 1
},
"guard": "…",
"prompt": "Update the changelog for the last five commits.",
"webchat": {
"access": "public",
"requireName": true,
"antiBot": "turnstile",
"turnstileSiteKey": "…",
"turnstileSecret": "…",
"googleClientId": "a1b2c3d4",
"title": "Update the changelog",
"greeting": "…",
"accent": "…",
"position": "top-right",
"dailyMessageMax": 1,
"conversationMessageMax": 1,
"sessionTtlMinutes": 1
},
"issues": {
"keyFromBrowsers": true,
"dailyReportMax": 1,
"escalateAfter": 1,
"antiBot": "pow",
"title": "Update the changelog",
"prompt": "Update the changelog for the last five commits.",
"thanks": "…",
"askEmail": true,
"accent": "…",
"captureCrashes": true
},
"allowedTools": [
"…",
"…"
],
"models": [
{
"provider": "claude",
"model": "claude-sonnet-4-6",
"effort": "…",
"thinking": true,
"fast": true,
"harness": "native"
},
{
"provider": "claude",
"model": "claude-haiku-4-6",
"effort": "…",
"thinking": true,
"fast": true,
"harness": "claude-code"
}
],
"account": "work",
"actsAs": "…",
"senders": {
"rules": [
{
"label": "Nightly changelog",
"ids": [
"a1b2c3d4",
"e5f6a7b8"
],
"groups": [
"…",
"…"
],
"actsAs": "…",
"requireApproval": true
},
{
"label": "Release notes",
"ids": [
"a1b2c3d4",
"e5f6a7b8"
],
"groups": [
"…",
"…"
],
"actsAs": "…",
"requireApproval": true
}
],
"others": "allow"
},
"requireApproval": true,
"holdForSeconds": 1,
"chore": true,
"enabled": true
});GET/automations/catalogWhat can trigger an automation here
Every trigger this sandbox understands and every template worth starting from, the daemon's own merged with each installed extension's. Writing an automation is checked against this same list, so a screen and the daemon can never disagree about what is allowed.
What you send
Nothing. Call it as it is.
What comes back
| Field | Type |
|---|---|
sources | object[] |
provider | string |
label | string |
logo | string |
icon | string |
events | object[] |
value | string |
label | string |
channel | object |
label | string |
placeholder | string |
hint | string |
branchField | object |
label | string |
placeholder | string |
hint | string |
sender | object |
label | string |
placeholder | string |
hint | string |
senderGroup | object |
label | string |
placeholder | string |
hint | string |
mentionLabel | string |
starterPrompt | string |
requires | string[] |
enabled | boolean |
templates | object[] |
id | string |
title | string |
logo | string |
icon | string |
requires | string[] |
trigger | object |
when kind is "schedule" | shape |
cronWhen, in cron notation | string |
tzWhich clock the times in the… | string |
afterSessionsFire only once at least this… | integer |
when kind is "once" | shape |
atThe moment it fires, in milliseconds | integer |
when kind is "event" | shape |
dailyMaxHow many webhook calls a day… | integer |
when kind is "listener" | shape |
providerWhich service to listen to | string |
channelIdNarrow it to one channel or… | string |
eventTypeNarrow it to one kind of… | string |
mentionedOnly when the agent is actually… | boolean |
branchNarrow it to one branch, for… | string |
allowedOriginsWhich websites may reach the public… | string[] |
when kind is "workspace" | shape |
eventWhich happening | "turn.settled" | "agent.landed" | "deps.broken" | "deps.fixed" |
repoNarrow it to one repository | string |
guard | string |
holdForSeconds | integer |
prompt | string |
note | string |
setup | string |
description | string |
offer | "create" | "configure" |
chore | boolean |
curl "$SANDBOX/automations/catalog" \
-H "x-intentic-control: $INTENTIC_TOKEN"import { sandbox } from "@intentic/sandbox-client";
const result = await sandbox.automations.catalog();POST/automations/{id}/enabledTurn an automation on or off
Flips only the switch, so a row in a list can be toggled without rebuilding the whole record.
What you send
| Field | Type | Where |
|---|---|---|
idrequired | string | address |
enabledrequired | boolean | body |
What comes back
| Field | Type |
|---|---|
okAlways true | true |
curl -X POST "$SANDBOX/automations/a1b2c3d4/enabled" \
-H "x-intentic-control: $INTENTIC_TOKEN" \
-H "content-type: application/json" \
-d '{"enabled":true}'import { sandbox } from "@intentic/sandbox-client";
const result = await sandbox.automations.setEnabled({
"id": "a1b2c3d4",
"enabled": true
});DELETE/automations/{id}Delete an automation
Removes it, so nothing fires from it again.
What you send
| Field | Type | Where |
|---|---|---|
idrequired | string | address |
What comes back
| Field | Type |
|---|---|
okAlways true | true |
curl -X DELETE "$SANDBOX/automations/a1b2c3d4" \
-H "x-intentic-control: $INTENTIC_TOKEN"import { sandbox } from "@intentic/sandbox-client";
const result = await sandbox.automations.remove({
"id": "a1b2c3d4"
});POST/automations/{id}/rotate-tokenRotate an automation's webhook token or intake key
Mints a new credential for the door this automation opens and retires the old one at once. Every caller has to be handed the new URL; that is the point. Refused for an automation with no door.
What you send
| Field | Type | Where |
|---|---|---|
idrequired | string | address |
What comes back
| Field | Type |
|---|---|
tokenThe freshly minted credential | string |
curl -X POST "$SANDBOX/automations/a1b2c3d4/rotate-token" \
-H "x-intentic-control: $INTENTIC_TOKEN"import { sandbox } from "@intentic/sandbox-client";
const result = await sandbox.automations.rotateToken({
"id": "a1b2c3d4"
});POST/automations/{id}/runFire an automation by hand
The answer to writing something that runs at three in the morning and having no way to try it. It takes exactly the path the real trigger takes, including the check that decides whether there was anything to do, since skipped by the guard is the most useful thing this can tell you. A switched-off automation fires too, because trying it before switching it on is the main reason to press this. Not available for the trigger that listens for incoming messages, where a hand-fire would produce an agent asked to handle events and handed none; send the bot a message instead. Answers straight away and runs detached.
What you send
| Field | Type | Where |
|---|---|---|
idrequired | string | address |
What comes back
| Field | Type |
|---|---|
okAlways true | true |
curl -X POST "$SANDBOX/automations/a1b2c3d4/run" \
-H "x-intentic-control: $INTENTIC_TOKEN"import { sandbox } from "@intentic/sandbox-client";
const result = await sandbox.automations.run({
"id": "a1b2c3d4"
});GET/automations/senders/{provider}Who has written to a listener source
Everyone whose message reached one of this source's automations, newest first, admitted or not. What the sender rules picker offers by name while storing the id the service vouches for.
What you send
| Field | Type | Where |
|---|---|---|
providerrequiredWhich listener source | string | address |
What comes back
| Field | Type |
|---|---|
sendersNewest first | object[] |
idThe sender id the service vouches… | string |
nameWhat they were called on their… | string |
groupsThe group ids the service reported… | string[] |
firstSeenAtWhen they first reached an automation… | number |
lastSeenAtWhen they last did, in milliseconds | number |
messagesHow many of their messages reached… | number |
curl "$SANDBOX/automations/senders/claude" \
-H "x-intentic-control: $INTENTIC_TOKEN"import { sandbox } from "@intentic/sandbox-client";
const result = await sandbox.automations.senders({
"provider": "claude"
});GET/automations/pendingAutomations waiting for a yes
The queue an automation set to ask first lands in each time it would have fired.
What you send
Nothing. Call it as it is.
What comes back
| Field | Type |
|---|---|
approvalsEverything waiting for a yes | object[] |
idThis waiting item's own id, which… | string |
automationIdWhich automation it came from | string |
payloadWhat set it off, kept whole… | string |
originWhere the message came from, kept… | object |
automationId | string |
provider | string |
channelId | string |
author | string |
titleWhat the conversation would be called | string |
conversationIdThe thread this belongs to, when… | string |
sessionIdThe provider session that thread last… | string |
threadWhich inbound thread this belongs to,… | string |
actsAsWhich persona the approved run speaks… | string |
createdAtWhen it started waiting, in milliseconds | number |
autoRunAtWhen it goes ahead on its… | number |
curl "$SANDBOX/automations/pending" \
-H "x-intentic-control: $INTENTIC_TOKEN"import { sandbox } from "@intentic/sandbox-client";
const result = await sandbox.automations.pendingList();POST/automations/pending/{id}/approveLet a held automation run
Releases one waiting automation and runs the wake it was holding. Answers straight away and runs detached.
What you send
| Field | Type | Where |
|---|---|---|
idrequiredWhich waiting item | string | address |
What comes back
| Field | Type |
|---|---|
okAlways true | true |
curl -X POST "$SANDBOX/automations/pending/a1b2c3d4/approve" \
-H "x-intentic-control: $INTENTIC_TOKEN"import { sandbox } from "@intentic/sandbox-client";
const result = await sandbox.automations.approve({
"id": "a1b2c3d4"
});POST/automations/pending/{id}/rejectDrop a held automation
Throws one waiting fire away. The automation stays on, and the next trigger queues as usual.
What you send
| Field | Type | Where |
|---|---|---|
idrequiredWhich waiting item | string | address |
What comes back
| Field | Type |
|---|---|
okAlways true | true |
curl -X POST "$SANDBOX/automations/pending/a1b2c3d4/reject" \
-H "x-intentic-control: $INTENTIC_TOKEN"import { sandbox } from "@intentic/sandbox-client";
const result = await sandbox.automations.reject({
"id": "a1b2c3d4"
});