On this page
- Overview
- Resource Shape
- List Pending Actions
- Query Params
- Response
- Curl
- Get Pending Action
- Path Params
- Responses
- Curl
- Approve Pending Action
- Path Params
- Request Body
- Responses
- Response Example
- Curl
- Reject Pending Action
- Path Params
- Request Body
- Responses
- Response Example
- Curl
- Batch Approve
- Path Params
- Request Body
- Responses
- Curl
- Error Codes
- Related
Pending Actions
Approve, reject, or batch-approve AI-proposed writes queued by @gated tools.
Overview
Every write-classified tool call from the Praxiom agent is intercepted by the @gated decorator and persisted as a pending action with status = "pending" instead of executing. This endpoint group lets workspace members list, inspect, approve, reject, or batch-resolve those pending rows.
All routes are mounted under /api/pending-actions and require authentication. Every route verifies that the caller is a member of the owning workspace — non-members get 403 FORBIDDEN.
See the Pending Actions guide for the conceptual model.
Base URL: https://api.praxiomai.xyz
Authentication: Authorization: Bearer <token>
Content type: Request and response bodies are camelCase on the wire; the server accepts snake_case on input as well.
Resource Shape
{
"id": "uuid",
"workspaceId": "uuid",
"missionId": "uuid | null",
"sessionId": "string | null",
"batchId": "{missionId}:{toolName}",
"toolName": "save_recommendations",
"toolInput": { "...": "raw kwargs the agent passed" },
"preview": { "...": "render-ready preview for the approval UI" },
"status": "pending | approved | rejected | executed | failed",
"userEdits": { "...": "optional edits to merge into toolInput" } ,
"result": { "...": "populated when status=executed" },
"error": "string | null (populated when status=failed)",
"createdAt": "ISO-8601",
"resolvedAt": "ISO-8601 | null",
"executedAt": "ISO-8601 | null"
}
List Pending Actions
GET /api/pending-actions
List pending actions for a workspace, newest first. Optionally filter by status.
Query Params
| Name | Type | Required | Description |
|---|---|---|---|
workspace_id | UUID | Yes | Workspace to scope results to. Caller must be a member. |
status | string | No | Filter by status. One of pending, approved, rejected, executed, failed. |
Response
{
"items": [
{
"id": "fb93a0ea-2d1c-4f3d-8b3a-7e31d5f4bc11",
"workspaceId": "550e8400-e29b-41d4-a716-446655440000",
"missionId": "a1b2c3d4-e5f6-7890-abcd-ef0123456789",
"sessionId": "ses_abc123",
"batchId": "a1b2c3d4-e5f6-7890-abcd-ef0123456789:save_recommendations",
"toolName": "save_recommendations",
"toolInput": { "workspace_id": "550e...", "recommendations": [] },
"preview": { "count": 1, "items": [] },
"status": "pending",
"userEdits": null,
"result": null,
"error": null,
"createdAt": "2026-04-21T18:02:11.420Z",
"resolvedAt": null,
"executedAt": null
}
],
"total": 1
}
Curl
curl -H "Authorization: Bearer $TOKEN" \
"https://api.praxiomai.xyz/api/pending-actions?workspace_id=550e8400-e29b-41d4-a716-446655440000&status=pending"
Get Pending Action
GET /api/pending-actions/{pa_id}
Fetch a single pending action by id.
Path Params
| Name | Type | Description |
|---|---|---|
pa_id | UUID | Pending action id. |
Responses
200— the full pending action resource (see shape above).404 NOT_FOUND— no such id.403 FORBIDDEN— caller is not a member of the owning workspace.
Curl
curl -H "Authorization: Bearer $TOKEN" \
"https://api.praxiomai.xyz/api/pending-actions/fb93a0ea-2d1c-4f3d-8b3a-7e31d5f4bc11"
Approve Pending Action
POST /api/pending-actions/{pa_id}/approve
Approve a pending action and schedule its execution. The DB row is committed as approved before execution is scheduled; the HTTP response returns immediately without waiting for the downstream API call.
Path Params
| Name | Type | Description |
|---|---|---|
pa_id | UUID | Pending action id. Must currently be in pending status. |
Request Body
| Name | Type | Required | Description |
|---|---|---|---|
userEdits | object | No | Optional dict of fields to shallow-merge into toolInput before execution. Use to correct titles, trim text, or swap metadata. |
{
"userEdits": {
"recommendations": [
{ "title": "Streamline onboarding", "effort_weeks": 2 }
]
}
}
Responses
200— the updated pending action withstatus = "approved",resolvedAtset, anduserEditspersisted. Execution runs asynchronously; poll the row to observe the transition toexecutedorfailed.404 NOT_FOUND— no such id.403 FORBIDDEN— caller is not a member of the owning workspace.409 INVALID_STATE— the row is not inpendingstatus (already approved, rejected, or resolved).
Response Example
{
"id": "fb93a0ea-2d1c-4f3d-8b3a-7e31d5f4bc11",
"workspaceId": "550e8400-e29b-41d4-a716-446655440000",
"toolName": "save_recommendations",
"status": "approved",
"userEdits": {
"recommendations": [
{ "title": "Streamline onboarding", "effort_weeks": 2 }
]
},
"resolvedAt": "2026-04-21T18:04:55.011Z",
"executedAt": null,
"result": null,
"error": null
}
Curl
curl -X POST \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{"userEdits": {"recommendations": [{"title": "Streamline onboarding", "effort_weeks": 2}]}}' \
"https://api.praxiomai.xyz/api/pending-actions/fb93a0ea-2d1c-4f3d-8b3a-7e31d5f4bc11/approve"
Approval is commit-then-schedule. If the process restarts between the commit and the executor task firing, the row is orphaned in approved state with no result. A reconciler will re-enqueue such rows in a future iteration.
Reject Pending Action
POST /api/pending-actions/{pa_id}/reject
Reject a pending action. The row transitions to rejected and the underlying handler is never invoked. Rejected rows stay in the database as an audit trail.
Path Params
| Name | Type | Description |
|---|---|---|
pa_id | UUID | Pending action id. Must currently be in pending status. |
Request Body
None.
Responses
200— the updated pending action withstatus = "rejected"andresolvedAtset.404 NOT_FOUND— no such id.403 FORBIDDEN— caller is not a member of the owning workspace.409 INVALID_STATE— the row is not inpendingstatus.
Response Example
{
"id": "fb93a0ea-2d1c-4f3d-8b3a-7e31d5f4bc11",
"toolName": "save_recommendations",
"status": "rejected",
"resolvedAt": "2026-04-21T18:05:22.142Z",
"executedAt": null,
"result": null,
"error": null
}
Curl
curl -X POST \
-H "Authorization: Bearer $TOKEN" \
"https://api.praxiomai.xyz/api/pending-actions/fb93a0ea-2d1c-4f3d-8b3a-7e31d5f4bc11/reject"
Batch Approve
POST /api/pending-actions/batch/{batch_id}/approve
Resolve multiple pending actions in a single batch. A batch_id has the form {mission_id}:{tool_name} — for example, a1b2c3d4-e5f6-7890-abcd-ef0123456789:save_recommendations. Every row in a batch shares the same workspace_id, so authorization is checked once against the first row.
Path Params
| Name | Type | Description |
|---|---|---|
batch_id | string | Batch identifier in the form {mission_id}:{tool_name}. |
Request Body
| Name | Type | Required | Description |
|---|---|---|---|
items | array of object | Yes | Per-row instructions. Rows not listed here are left pending (default-skip). |
items[].pendingActionId | UUID | Yes | The target row id (must belong to this batch). |
items[].userEdits | object | No | Optional shallow-merge edits applied on approve. |
items[].exclude | boolean | No | When true, reject this row instead of approving. Default false. |
{
"items": [
{ "pendingActionId": "pa-1", "userEdits": { "priority": 2 } },
{ "pendingActionId": "pa-2" },
{ "pendingActionId": "pa-3", "exclude": true }
]
}
Rows that belong to the batch but are not listed in items are left pending (default-skip). This prevents silent data loss if the frontend omits an item — but it also means callers must explicitly list every row they want resolved.
Responses
200— a summary of what was resolved:
{
"batchId": "a1b2c3d4-e5f6-7890-abcd-ef0123456789:save_recommendations",
"approved": 2,
"rejected": 1,
"skipped": 0
}
-
skippedcounts rows that were resolved by another session between the list and the mutate. Partial progress is preserved instead of 500ing. -
Rows already in a non-
pendingstatus when the batch runs are silently left alone — they do not count towardapproved,rejected, orskipped. -
404 NOT_FOUND— batch is empty or does not exist. -
403 FORBIDDEN— caller is not a member of the owning workspace. -
500 INVARIANT_VIOLATION— rows in the batch span multiple workspaces (defense-in-depth; should never happen in practice).
After a successful batch, approved rows are scheduled for execution fire-and-forget. Rejected rows are final.
Curl
curl -X POST \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"items": [
{"pendingActionId": "pa-1", "userEdits": {"priority": 2}},
{"pendingActionId": "pa-2"},
{"pendingActionId": "pa-3", "exclude": true}
]
}' \
"https://api.praxiomai.xyz/api/pending-actions/batch/a1b2c3d4-e5f6-7890-abcd-ef0123456789:save_recommendations/approve"
Error Codes
| HTTP | Code | When |
|---|---|---|
403 | FORBIDDEN | Caller is not a member of the owning workspace. |
404 | NOT_FOUND | Pending action id or batch id does not exist. |
409 | INVALID_STATE | Attempted to approve or reject a row not in pending status. |
422 | validation | Bad status filter or malformed request body. |
500 | INVARIANT_VIOLATION | Batch unexpectedly spans multiple workspaces. |
Related
- Pending Actions guide — conceptual model,
@gateddecorator, gated tool list, lifecycle. - Streaming (SSE) —
briefingevents surface outstanding pending-action counts on conversation resumption. - Missions — pending actions queued during a mission subtask are grouped by
batch_id = {mission_id}:{tool_name}for bulk approval.
Was this helpful?