Actions & Control
This page is the API reference for action submission and the legacy Control endpoints. For the full feature documentation — custom policies, approval workflows, the governance dashboard, and per-agent overrides — see the dedicated Control section:
- Custom Policies — author governance rules in YAML
- Approval Workflows — Solo / Team / Enterprise modes and the polling pattern
- Governance Dashboard — aggregated stats and per-agent violation history
- Agent-Scoped Policies — per-agent policy overrides
The Actions router evaluates agent actions against the active policy set — built-in policies (FinancialSafety, DataExfiltration) plus any custom policies authored at the tenant or agent scope. Actions resolve to one of three statuses: allowed, blocked, or pending_review. When a rule fires with on_violation: warn, the action status is allowed and the warning is appended to policy_result.warnings.
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
| Parameter | Type | Required | Description |
|---|---|---|---|
action | string | Yes | Action name (e.g., github.merge_pr, slack.post_message) |
params | object | No | Action parameters passed to the policy evaluator |
Response fields
| Field | Type | Description |
|---|---|---|
action | string | Action name |
status | string | allowed, blocked, or pending_review |
policy_result | object | null | Policy evaluation details (risk score, triggered policy, violations) |
message | string | Human-readable explanation |
Examples
- Python
- TypeScript
- curl
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']}")
import { Novyx } from "novyx";
const nx = new Novyx({ apiKey: "nram_your_key" });
const result = await nx.actionSubmit({
action: "github.merge_pr",
params: { repo: "myorg/myrepo", pr_number: 42 },
});
console.log(`Status: ${result.status}`);
curl -X POST https://novyx-ram-api.fly.dev/v1/actions \
-H "Authorization: Bearer nram_your_key" \
-H "Content-Type: application/json" \
-d '{
"action": "github.merge_pr",
"params": {"repo": "myorg/myrepo", "pr_number": 42}
}'
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
| Status | Code | Cause |
|---|---|---|
| 401 | UNAUTHORIZED | Invalid or missing API key |
| 403 | BLOCKED | Action 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
| Parameter | Type | Description |
|---|---|---|
action_id | string | The action identifier |
Response fields
| Field | Type | Description |
|---|---|---|
action_id | string | Action identifier |
action | string | Action name/operation |
agent_id | string | Agent that submitted the action |
connector | string | Connector used (github, slack, etc.) |
operation | string | Specific operation |
submitted_at | string | ISO 8601 timestamp |
policy_result | object | null | Policy evaluation result |
approval | object | null | Approval flow details |
memories_at_time | array | null | Agent memories at the moment of the action |
audit_trail | array | Cryptographic audit entries |
summary | string | Human-readable summary of the entire chain |
Examples
- Python
- TypeScript
- curl
explanation = nx.action_explain("action_abc123")
print(explanation["summary"])
for entry in explanation["audit_trail"]:
print(f" {entry['timestamp']}: {entry['event']}")
const explanation = await nx.actionExplain("action_abc123");
console.log(explanation.summary);
for (const entry of explanation.audit_trail) {
console.log(` ${entry.timestamp}: ${entry.event}`);
}
curl https://novyx-ram-api.fly.dev/v1/actions/action_abc123/explain \
-H "Authorization: Bearer nram_your_key"
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
| Status | Code | Cause |
|---|---|---|
| 404 | actions.not_found | No 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
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
limit | number | No | 50 | Max results |
status | string | No | — | Filter by status (e.g., pending_review) |
Response fields
| Field | Type | Description |
|---|---|---|
approvals | array | Array of pending approval objects |
total | number | Total count |
Each approval includes:
| Field | Type | Description |
|---|---|---|
approval_id | string | Approval/action identifier |
action | string | Action name |
connector | string | Connector used |
agent_id | string | Submitting agent |
status | string | Current status |
submitted_at | string | ISO 8601 timestamp |
risk_score | number | null | Risk score from policy evaluation |
Examples
- Python
- TypeScript
- curl
pending = nx.action_list()
for approval in pending["approvals"]:
print(f"{approval['action']} by {approval['agent_id']} — {approval['status']}")
const pending = await nx.actionList();
for (const approval of pending.approvals) {
console.log(`${approval.action} by ${approval.agent_id} — ${approval.status}`);
}
curl "https://novyx-ram-api.fly.dev/v1/approvals?limit=10" \
-H "Authorization: Bearer nram_your_key"
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
| Parameter | Type | Description |
|---|---|---|
approval_id | string | The approval/action identifier |
Query parameters
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
decision | string | No | approve | approve or deny |
reason | string | No | — | Reason for the decision |
approver_id | string | No | — | ID of the person making the decision (defaults to tenant) |
Response fields
| Field | Type | Description |
|---|---|---|
approval_id | string | Approval identifier |
decision | string | approve or deny |
reason | string | null | Decision reason |
status | string | approved or denied |
Examples
- Python
- TypeScript
- curl
result = nx.approve_action(
"approval_abc123",
decision="approve",
reason="Reviewed and safe to proceed"
)
print(f"Decision: {result['status']}")
const result = await nx.approveAction("approval_abc123", {
decision: "approve",
reason: "Reviewed and safe to proceed",
});
console.log(`Decision: ${result.status}`);
curl -X POST "https://novyx-ram-api.fly.dev/v1/approvals/approval_abc123/decision?decision=approve&reason=Reviewed" \
-H "Authorization: Bearer nram_your_key"
Response
{
"approval_id": "approval_abc123",
"decision": "approve",
"reason": "Reviewed and safe to proceed",
"status": "approved"
}
Errors
| Status | Code | Cause |
|---|---|---|
| 400 | control.invalid_decision | Decision must be approve or deny |
| 404 | NOT_FOUND | Approval 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
| Field | Type | Description |
|---|---|---|
policies | array | Active policy objects |
mode | string | Evaluation mode (enforcement or shadow) |
connectors | string[] | Supported connectors |
approval_modes | string[] | Available approval modes |
Each policy includes:
| Field | Type | Description |
|---|---|---|
name | string | Policy name |
enabled | boolean | Whether the policy is active |
description | string | Human-readable description |
Examples
- Python
- TypeScript
- curl
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'])}")
const policies = await nx.policyCheck();
for (const p of policies.policies) {
console.log(`${p.name}: ${p.enabled ? "enabled" : "disabled"}`);
}
curl https://novyx-ram-api.fly.dev/v1/control/policies \
-H "Authorization: Bearer nram_your_key"
Response
{
"policies": [
{
"name": "FinancialSafety",
"enabled": true,
"description": "Policy to prevent unauthorized financial operations.",
"source": "builtin",
"agent_id": null
},
{
"name": "DataExfiltration",
"enabled": true,
"description": "Policy to prevent data exfiltration attempts.",
"source": "builtin",
"agent_id": null
},
{
"name": "pii_protection",
"enabled": true,
"description": "Block PII exposure to external systems",
"source": "custom",
"agent_id": null,
"scope": "tenant",
"version": 1,
"created_at": "2026-04-10T14:30:00Z",
"updated_at": "2026-04-10T14:30:00Z"
}
],
"mode": "enforcement",
"connectors": ["github", "slack", "linear", "pagerduty", "http"],
"approval_modes": ["solo", "team", "enterprise"]
}
Built-in policies only return
name,enabled,description,source, andagent_id. Custom policies additionally includescope,version,created_at, andupdated_at.
Custom policies are first-class as of the Phases 1-5 release. To author your own, see Custom Policies. The full CRUD API (
POST/PUT/DELETE /v1/control/policies) and SDK methods (nx.create_policy,nx.update_policy,nx.delete_policy) are documented there.