Skip to main content

Actions

Actions define what happens when a condition fires — Slack notifications, webhook calls, workflow triggers, or write-back to a primitive. Actions are registered independently and bound to conditions via the trigger config.

Actions are immutable once registered. To update an action, register a new version.


Register an Action

POST /actions

Registers a new action. Requires the elevated key.

Request Body — ActionDefinition

ParameterTypeRequiredDescription
action_idstringRequiredUnique identifier for this action.
versionstringRequiredVersion string (e.g. "v1"). Once registered, (action_id, version) is permanent.
configActionConfigRequiredAction type and delivery parameters. See Action Types below.
triggerTriggerConfigRequiredWhen the action fires and which condition it is bound to.
namespacestringRequiredOrganisation namespace (e.g. "org").

TriggerConfig

ParameterTypeRequiredDescription
fire_onenumRequired"true" | "false" | "any". When to fire relative to the condition decision.
condition_idstringRequiredThe condition this action is bound to.
condition_versionstringRequiredThe specific condition version.

fire_on values:

ValueWhen the action fires
"true"When the condition evaluates to true (or the matched label for equals strategy)
"false"When the condition evaluates to false
"any"On every evaluation, regardless of outcome

Response Codes

StatusDescription
200Action registered.
400Invalid request body or unknown action type.
401Unauthorised.
403Elevated key required.
409(action_id, version) already exists.

TypeScript Example

await client.actions.register({
actionId: "slack_cs_alert",
version: "v1",
config: {
type: "notification",
channel: "slack-customer-success",
messageTemplate: "Churn risk: {entity} active rate {decision_value}",
},
trigger: {
fireOn: "true",
conditionId: "cond_churn_risk",
conditionVersion: "v1",
},
namespace: "org",
});

List Actions

GET /actions

Returns a paginated list of registered actions for a namespace.

Query Parameters

ParameterTypeRequiredDescription
namespacestringOptionalFilter by namespace. Defaults to "org".
limitintegerOptionalDefault 50. Maximum 200.
cursorstringOptionalPagination cursor from previous response.

Response

ParameterTypeDescription
itemsarrayArray of ActionDefinition records.
has_morebooleanWhether more results are available.
next_cursorstring | nullPass as cursor on the next request.
total_countintegerTotal number of registered actions in this namespace.

Response Codes

StatusDescription
200Action list.
401Unauthorised.

TypeScript Example

const actions = await client.actions.list({ namespace: "org" });

actions.items.forEach(a => {
console.log(a.action_id, a.version, a.config.type);
});

Trigger an Action

POST /actions/{action_id}/trigger

Triggers a registered action directly for a given entity, bypassing the full pipeline. Use for testing action configuration before go-live. Supports dry run mode.

Path Parameters

ParameterTypeRequiredDescription
action_idstringRequiredThe action to trigger.

Request Body

ParameterTypeRequiredDescription
versionstringRequiredThe action version to trigger.
entitystringRequiredThe entity to use when constructing the action payload.
timestampdatetimeOptionalISO 8601 UTC. Used in the action payload.
dry_runbooleanOptionalDefault false. Simulate without making external calls. Returns status: "would_trigger".

Response — ActionResult

ParameterTypeDescription
action_idstringThe triggered action.
action_versionstringThe version triggered.
statusenumtriggered | skipped | failed | would_trigger
payload_sentobject | nullThe actual payload delivered (populated when triggered).
errorobject | nullError details (populated when status: "failed").

Response Codes

StatusDescription
200Action triggered, skipped, or simulated.
401Unauthorised.
404Action not found.

TypeScript Example

// Dry run — simulate without external calls
const result = await client.actions.trigger("slack_cs_alert", {
version: "v1",
entity: "account_xyz789",
dryRun: true,
});

console.log(result.status); // "would_trigger"

// Real trigger
const live = await client.actions.trigger("slack_cs_alert", {
version: "v1",
entity: "account_xyz789",
});

console.log(live.status); // "triggered"

Action Types

The config object is a discriminated union keyed on type.

notification

Push alert to a named notification channel (Slack, PagerDuty, etc.).

{
"type": "notification",
"channel": "slack-customer-success",
"message_template": "Churn risk: {entity} active rate {decision_value}"
}
FieldRequiredDescription
channelRequiredNamed notification channel.
message_templateOptionalFormat string. Omit for default decision summary.

webhook

HTTP POST to an external endpoint.

{
"type": "webhook",
"endpoint": "https://myapp.com/hooks/alert",
"method": "POST",
"headers": { "Authorization": "Bearer ${CRM_SECRET}" },
"payload_template": { "entity": "{entity}" }
}
FieldRequiredDescription
endpointRequiredTarget URL.
methodOptionalHTTP method. Default "POST".
headersOptionalHTTP headers. Use ${ENV_VAR} for secrets.
payload_templateOptionalRequest body template. Omit for default decision payload.
At-most-once delivery

Actions are best-effort — no automatic retry. A failed webhook is recorded as failed in the decision record; the pipeline returns HTTP 200 regardless. Design downstream systems to be idempotent.

workflow

Trigger a registered workflow engine.

{
"type": "workflow",
"workflow_id": "credit_review_workflow",
"input_mapping": { "borrower": "entity", "score": "decision_value" }
}
FieldRequiredDescription
workflow_idRequiredID of the registered workflow.
input_mappingOptionalMaps workflow input names to decision fields. Omit to forward the full decision payload.

register

Write the decision result back to a primitive (closed-loop feedback).

{
"type": "register",
"primitive_id": "account.churn_risk_flag",
"entity_field": "entity"
}
FieldRequiredDescription
primitive_idRequiredThe primitive to update (namespace.field format).
entity_fieldOptionalWhich decision field carries the entity ID. Default "entity".