Skip to main content

Actions & Control

The Actions router evaluates agent actions against security policies (FinancialSafetyPolicy, DataExfiltrationPolicy) via the Sentinel circuit breaker. Actions are either allowed, blocked, or flagged for review. The Control endpoints manage approval workflows and policy configuration.

Base URL: https://novyx-ram-api.fly.dev

Tier: All tiers can submit actions. Approval workflows available on all tiers.

Connectors: github, slack, linear, pagerduty, http

Approval modes: solo, team, enterprise


Submit Action

POST /v1/actions

Submit an action for policy evaluation via Sentinel. The action is evaluated against all active policies and returns one of three outcomes: allowed, blocked, or pending_review.

Request body

ParameterTypeRequiredDescription
actionstringYesAction name (e.g., github.merge_pr, slack.post_message)
paramsobjectNoAction parameters passed to the policy evaluator

Response fields

FieldTypeDescription
actionstringAction name
statusstringallowed, blocked, or pending_review
policy_resultobject | nullPolicy evaluation details (risk score, triggered policy, violations)
messagestringHuman-readable explanation

Examples

from novyx import Novyx

nx = Novyx(api_key="nram_your_key")

result = nx.action_submit(
action="github.merge_pr",
params={"repo": "myorg/myrepo", "pr_number": 42}
)
print(f"Status: {result['status']}")
print(f"Message: {result['message']}")

Response

{
"action": "github.merge_pr",
"status": "allowed",
"policy_result": {
"risk_score": 0.12,
"evaluation_time_ms": 3.4
},
"message": "Action permitted by policy evaluation"
}

Blocked response example:

{
"action": "http.transfer_funds",
"status": "blocked",
"policy_result": {
"triggered_policy": "FinancialSafetyPolicy",
"reason": "High-value financial operation requires approval",
"risk_score": 0.85,
"severity": "high"
},
"message": "Action blocked: High-value financial operation requires approval"
}

Errors

StatusCodeCause
401UNAUTHORIZEDInvalid or missing API key
403BLOCKEDAction blocked by policy

Explain Action

GET /v1/actions/{action_id}/explain

Get the full causal chain for an action: policy evaluation, approval flow, agent memories at the time, and cryptographic audit trail. One API call to answer "why did my agent do that?"

Path parameters

ParameterTypeDescription
action_idstringThe action identifier

Response fields

FieldTypeDescription
action_idstringAction identifier
actionstringAction name/operation
agent_idstringAgent that submitted the action
connectorstringConnector used (github, slack, etc.)
operationstringSpecific operation
submitted_atstringISO 8601 timestamp
policy_resultobject | nullPolicy evaluation result
approvalobject | nullApproval flow details
memories_at_timearray | nullAgent memories at the moment of the action
audit_trailarrayCryptographic audit entries
summarystringHuman-readable summary of the entire chain

Examples

explanation = nx.action_explain("action_abc123")
print(explanation["summary"])
for entry in explanation["audit_trail"]:
print(f" {entry['timestamp']}: {entry['event']}")

Response

{
"action_id": "action_abc123",
"action": "github.merge_pr",
"agent_id": "deploy-bot",
"connector": "github",
"operation": "merge_pr",
"submitted_at": "2026-03-15T14:30:00Z",
"policy_result": {
"status": "allowed",
"policies_evaluated": ["FinancialSafetyPolicy", "DataExfiltrationPolicy"],
"risk_score": 0.12,
"violations": null
},
"approval": null,
"memories_at_time": [
{
"memory_id": "mem_xyz",
"observation": "PR #42 passed all CI checks",
"importance": 7,
"tags": ["ci", "deploy"],
"created_at": "2026-03-15T14:25:00Z"
}
],
"audit_trail": [
{
"sequence_number": 1,
"timestamp": "2026-03-15T14:30:00Z",
"event": "action_executed",
"entry_hash": "sha256:abc123...",
"metadata": {"connector": "github", "operation": "merge_pr"}
}
],
"summary": "Agent 'deploy-bot' submitted a github.merge_pr action at 2026-03-15T14:30:00Z. Action was approved. Agent had 42 memories at the time."
}

Errors

StatusCodeCause
404actions.not_foundNo audit trail found for the action

List Approvals

GET /v1/approvals

List pending action approvals for the current tenant. Used by the Vault dashboard to show the approval queue.

Query parameters

ParameterTypeRequiredDefaultDescription
limitnumberNo50Max results
statusstringNoFilter by status (e.g., pending_review)

Response fields

FieldTypeDescription
approvalsarrayArray of pending approval objects
totalnumberTotal count

Each approval includes:

FieldTypeDescription
approval_idstringApproval/action identifier
actionstringAction name
connectorstringConnector used
agent_idstringSubmitting agent
statusstringCurrent status
submitted_atstringISO 8601 timestamp
risk_scorenumber | nullRisk score from policy evaluation

Examples

pending = nx.action_list()
for approval in pending["approvals"]:
print(f"{approval['action']} by {approval['agent_id']}{approval['status']}")

Approve / Reject Action

POST /v1/approvals/{approval_id}/decision

Approve or deny a pending action. Records the decision in the cryptographic audit trail and emits an event bus notification.

Path parameters

ParameterTypeDescription
approval_idstringThe approval/action identifier

Query parameters

ParameterTypeRequiredDefaultDescription
decisionstringNoapproveapprove or deny
reasonstringNoReason for the decision
approver_idstringNoID of the person making the decision (defaults to tenant)

Response fields

FieldTypeDescription
approval_idstringApproval identifier
decisionstringapprove or deny
reasonstring | nullDecision reason
statusstringapproved or denied

Examples

result = nx.approve_action(
"approval_abc123",
decision="approve",
reason="Reviewed and safe to proceed"
)
print(f"Decision: {result['status']}")

Response

{
"approval_id": "approval_abc123",
"decision": "approve",
"reason": "Reviewed and safe to proceed",
"status": "approved"
}

Errors

StatusCodeCause
400control.invalid_decisionDecision must be approve or deny
404NOT_FOUNDApproval not found

List Policies

GET /v1/control/policies

List active Control policies and their configuration. Returns which policies are active, supported connectors, and approval modes.

Response fields

FieldTypeDescription
policiesarrayActive policy objects
modestringEvaluation mode (enforcement or shadow)
connectorsstring[]Supported connectors
approval_modesstring[]Available approval modes

Each policy includes:

FieldTypeDescription
namestringPolicy name
enabledbooleanWhether the policy is active
descriptionstringHuman-readable description

Examples

policies = nx.policy_check()
for p in policies["policies"]:
print(f"{p['name']}: {'enabled' if p['enabled'] else 'disabled'}")
print(f"Connectors: {', '.join(policies['connectors'])}")

Response

{
"policies": [
{
"name": "FinancialSafetyPolicy",
"enabled": true,
"description": "Blocks high-value financial operations without approval"
},
{
"name": "DataExfiltrationPolicy",
"enabled": true,
"description": "Prevents unauthorized data export"
}
],
"mode": "enforcement",
"connectors": ["github", "slack", "linear", "pagerduty", "http"],
"approval_modes": ["solo", "team", "enterprise"]
}