Skip to main content

Step 4 — Actions

An action is what happens when a monitoring condition fires. It is the delivery mechanism — where does the alert go, and in what form?

You register a library of available actions via the API. When monitoring tasks are created, they bind to a specific action. You can have as many actions as you need — a Slack alert for one team, a webhook to your CRM for another, a workflow trigger for a third.


How Actions Are Registered

Actions are registered via POST /actions and stored in the database. There is no actions section in memintel_config.yaml.

curl -X POST https://api.memsdl.ai/v1/actions \
-H "X-Elevated-Key: your-elevated-key" \
-H "Content-Type: application/json" \
-d '{
"action_id": "slack_customer_success",
"version": "v1",
"config": {
"type": "notification",
"channel": "slack-cs-alerts",
"message_template": "Churn risk alert for {entity} — active user rate dropped to {decision_value}"
},
"trigger": {
"fire_on": "true",
"condition_id": "cond_churn_risk",
"condition_version": "v1"
},
"namespace": "org"
}'

The Action Structure

Every action definition has four required fields:

action_id — the action's name

A unique identifier for this action. Make it descriptive — it's what your team sees when tasks are created.

slack_customer_success
pagerduty_critical
crm_churn_webhook
workflow_credit_review

version — the action version

Actions are versioned and immutable. Once registered, an (action_id, version) pair is permanent. To update an action, register a new version.

"version": "v1"

config — the action type and delivery parameters

The config object defines the action type and how it delivers. The type field is the discriminator — see Four Action Types below.

trigger — when the action fires

The trigger defines when the action fires and which condition it is bound to:

"trigger": {
"fire_on": "true",
"condition_id": "cond_churn_risk",
"condition_version": "v1"
}

fire_on options:

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

Four Action Types

notification — push alerts to a channel

Use for Slack messages, PagerDuty, or any named notification channel. Memintel sends the message to the configured channel.

{
"type": "notification",
"channel": "slack-cs-alerts",
"message_template": "Churn risk: {entity} active rate {decision_value}"
}
FieldRequiredDescription
typeYes"notification"
channelYesNamed notification channel
message_templateNoMessage format string — omit for default decision summary

webhook — HTTP POST to an external system

Use for CRMs, ticketing systems, incident management tools, or any system with an API endpoint.

{
"type": "webhook",
"endpoint": "https://myapp.com/hooks/alert",
"method": "POST",
"headers": {
"Authorization": "Bearer ${CRM_WEBHOOK_SECRET}"
},
"payload_template": {
"entity": "{entity}",
"alert_type": "churn_risk"
}
}
FieldRequiredDescription
typeYes"webhook"
endpointYesTarget URL
methodNoHTTP method — defaults to "POST"
headersNoHTTP headers — use ${ENV_VAR} for secrets
payload_templateNoRequest body template — omit for default decision payload
No automatic retries

Actions are best-effort — at-most-once per evaluation. A failed action is recorded as failed in the decision record; the pipeline returns HTTP 200 regardless. Design your downstream systems to be idempotent.

workflow — trigger an external workflow engine

Use to trigger a registered workflow in a connected workflow engine.

{
"type": "workflow",
"workflow_id": "credit_review_workflow",
"input_mapping": {
"borrower": "entity",
"dscr_value": "decision_value"
}
}
FieldRequiredDescription
typeYes"workflow"
workflow_idYesID of the registered workflow to trigger
input_mappingNoMaps workflow input parameter names to decision fields — omit to forward the full decision payload

register — write the decision result back to a primitive

Use to close the loop — write a decision outcome back into the Memintel primitive registry so future concept evaluations can consume it.

{
"type": "register",
"primitive_id": "account.churn_risk_flag",
"entity_field": "entity"
}
FieldRequiredDescription
typeYes"register"
primitive_idYesThe primitive to update (format: namespace.field)
entity_fieldNoWhich field from the decision carries the entity ID — defaults to "entity"

Using Environment Variables for Secrets

Never put real API keys, webhook secrets, or tokens directly in an action config. Use ${VARIABLE_NAME} references instead — the server resolves these from environment variables at startup.

// Wrong — secret hardcoded
"headers": { "Authorization": "Bearer sk-real-secret-token" }

// Right — secret stored as environment variable
"headers": { "Authorization": "Bearer ${CRM_WEBHOOK_SECRET}" }

Ask your data engineer to set the corresponding environment variables on the server.


Testing an Action

To verify an action before go-live, trigger it directly for a test entity:

curl -X POST https://api.memsdl.ai/v1/actions/slack_customer_success/trigger \
-H "X-API-Key: your-api-key" \
-H "Content-Type: application/json" \
-d '{
"version": "v1",
"entity": "test_entity_001",
"dry_run": true
}'

With dry_run: true, the action is simulated without making any real HTTP calls or external side effects. The response shows status: "would_trigger".

Remove dry_run to trigger the action for real against the test entity.


Complete Examples

SaaS Platform

# Slack alert — customer success team
curl -X POST .../v1/actions \
-H "X-Elevated-Key: your-elevated-key" \
-d '{
"action_id": "slack_cs_team",
"version": "v1",
"config": { "type": "notification", "channel": "slack-cs-alerts" },
"trigger": { "fire_on": "true", "condition_id": "cond_churn_risk", "condition_version": "v1" },
"namespace": "org"
}'

# CRM webhook — trigger outreach sequence
curl -X POST .../v1/actions \
-H "X-Elevated-Key: your-elevated-key" \
-d '{
"action_id": "crm_churn_webhook",
"version": "v1",
"config": {
"type": "webhook",
"endpoint": "https://crm.myapp.com/hooks/churn",
"headers": { "Authorization": "Bearer ${CRM_SECRET}" }
},
"trigger": { "fire_on": "true", "condition_id": "cond_churn_risk", "condition_version": "v1" },
"namespace": "org"
}'

# Write-back — update churn risk flag primitive
curl -X POST .../v1/actions \
-H "X-Elevated-Key: your-elevated-key" \
-d '{
"action_id": "write_churn_flag",
"version": "v1",
"config": { "type": "register", "primitive_id": "account.churn_risk_flag" },
"trigger": { "fire_on": "any", "condition_id": "cond_churn_risk", "condition_version": "v1" },
"namespace": "org"
}'

Financial Services / Compliance

# Compliance notification
curl -X POST .../v1/actions \
-H "X-Elevated-Key: your-elevated-key" \
-d '{
"action_id": "compliance_alert",
"version": "v1",
"config": { "type": "notification", "channel": "slack-compliance" },
"trigger": { "fire_on": "true", "condition_id": "cond_aml_signal", "condition_version": "v1" },
"namespace": "org"
}'

# Compliance system webhook — high priority
curl -X POST .../v1/actions \
-H "X-Elevated-Key: your-elevated-key" \
-d '{
"action_id": "compliance_system_webhook",
"version": "v1",
"config": {
"type": "webhook",
"endpoint": "https://compliance.myapp.com/hooks/aml",
"headers": {
"Authorization": "Bearer ${COMPLIANCE_SECRET}",
"X-Alert-Priority": "high"
}
},
"trigger": { "fire_on": "true", "condition_id": "cond_aml_signal", "condition_version": "v1" },
"namespace": "org"
}'

Clinical Trials / Healthcare

# Safety alert — medical monitor
curl -X POST .../v1/actions \
-H "X-Elevated-Key: your-elevated-key" \
-d '{
"action_id": "safety_alert",
"version": "v1",
"config": { "type": "notification", "channel": "slack-medical-monitor" },
"trigger": { "fire_on": "true", "condition_id": "cond_ae_severity", "condition_version": "v1" },
"namespace": "org"
}'

# Pharmacovigilance system webhook
curl -X POST .../v1/actions \
-H "X-Elevated-Key: your-elevated-key" \
-d '{
"action_id": "safety_system_webhook",
"version": "v1",
"config": {
"type": "webhook",
"endpoint": "https://safety.myapp.com/hooks/ae-alert",
"headers": { "Authorization": "Bearer ${SAFETY_SECRET}" }
},
"trigger": { "fire_on": "true", "condition_id": "cond_ae_severity", "condition_version": "v1" },
"namespace": "org"
}'

DevOps / SRE

# PagerDuty — critical SLO breach
curl -X POST .../v1/actions \
-H "X-Elevated-Key: your-elevated-key" \
-d '{
"action_id": "pagerduty_critical",
"version": "v1",
"config": {
"type": "webhook",
"endpoint": "https://events.pagerduty.com/v2/enqueue",
"headers": { "Authorization": "Token token=${PAGERDUTY_KEY}" }
},
"trigger": { "fire_on": "true", "condition_id": "cond_slo_breach", "condition_version": "v1" },
"namespace": "org"
}'

# CI/CD deployment block workflow
curl -X POST .../v1/actions \
-H "X-Elevated-Key: your-elevated-key" \
-d '{
"action_id": "block_deployment",
"version": "v1",
"config": {
"type": "workflow",
"workflow_id": "deployment_block_workflow",
"input_mapping": { "service": "entity", "risk_score": "decision_value" }
},
"trigger": { "fire_on": "true", "condition_id": "cond_deployment_risk", "condition_version": "v1" },
"namespace": "org"
}'

Common Mistakes

Using log_only as an action type. This type does not exist. If you want a decision recorded without any external delivery, use a webhook pointing to an internal audit endpoint, or rely on the decision record that Memintel creates for every evaluation automatically.

Expecting automatic retries. Actions are at-most-once. If a webhook fails, it is recorded as failed but not retried. Design your downstream systems to handle this — use idempotency keys based on (condition_id, condition_version, entity, timestamp).

Putting secrets directly in the config. Use ${ENV_VAR} references for all credentials. Ask your data engineer to set the corresponding environment variables on the server.

Not testing actions before go-live. Use POST /actions/{id}/trigger with dry_run: true to verify each action is reachable and configured correctly before users start creating tasks.

Using one action for everything. A critical safety signal and a low-priority early warning should not go to the same channel. Register separate actions for different priority levels and condition types.