decision_request_approval
Requests human approval for a decision that requires exception handling. This is typically used when a policy evaluation returns requires_exception.
Overview
The decision_request_approval method sends an approval request to human reviewers. Approval requests are delivered through configured approval routes (email, Slack, webhooks, etc.) and can be approved or rejected through the TraceMem dashboard or API.
Request
Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
decision_id | string | Yes | The decision ID (from decision_create) |
title | string | No | Approval request title (brief summary) |
message | string | No | Detailed explanation for the approver |
approval_route_id | string | No | Specific approval route to use (usually derived from policy if not specified) |
Example Request
{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": {
"name": "decision_request_approval",
"arguments": {
"decision_id": "TMEM_abc123...",
"title": "High-Value Discount Approval",
"message": "Customer 1001 requesting 25% discount on $10k order. Customer has been with us for 5 years with perfect payment history. Policy evaluation returned 'requires_exception'.",
"approval_route_id": "route_discount_manager"
}
}
}
Response
Success Response
{
"jsonrpc": "2.0",
"id": 1,
"result": {
"content": [
{
"type": "text",
"text": "{\"approval_id\": \"appr_...\", \"status\": \"pending\", \"delivery\": {\"status\": \"pending\", \"note\": \"Approval will be delivered by worker service\"}}"
}
]
}
}
Response Fields
| Field | Type | Description |
|---|---|---|
approval_id | string | Unique identifier for this approval request |
status | string | Current approval status: "pending", "approved", or "rejected" |
delivery | object | Delivery status information |
delivery.status | string | Delivery status: "pending", "delivered", or "failed" |
delivery.note | string | Additional information about delivery |
Example Response
{
"approval_id": "appr_abc123",
"status": "pending",
"delivery": {
"status": "pending",
"note": "Approval will be delivered by worker service"
}
}
Approval Status
After requesting approval, the decision status changes to needs_approval. You can check the approval status by:
- Polling
decision_getto check ifstatusis"approved"or if the decision was rejected - The decision will remain in
needs_approvalstatus until approved or rejected
Error Cases
Missing Decision ID
Error Code: -32600 (Invalid Request)
{
"jsonrpc": "2.0",
"id": 1,
"error": {
"code": -32600,
"message": "Invalid Request",
"data": "decision_id is required"
}
}
Decision Not Found
Error Code: -32603 (Internal error)
{
"jsonrpc": "2.0",
"id": 1,
"error": {
"code": -32603,
"message": "Internal error",
"data": "Decision not found"
}
}
Approval Route Not Found
Error Code: -32603 (Internal error)
{
"jsonrpc": "2.0",
"id": 1,
"error": {
"code": -32603,
"message": "Internal error",
"data": "Approval route 'route_discount_manager' not found or not accessible"
}
}
Common causes:
- Approval route doesn't exist
- Agent doesn't have permission to use this approval route
- Approval route ID is misspelled
Permission Denied
HTTP Status: 403 Forbidden
{
"jsonrpc": "2.0",
"id": 1,
"error": {
"code": -32603,
"message": "Internal error",
"data": "Permission denied: agent does not have permission to request approvals"
}
}
Authentication Errors
HTTP Status: 401 Unauthorized
Occurs when:
- API key is missing
- API key is invalid
- API key has been revoked
Usage Examples
Request Approval After Policy Evaluation
import requests
import json
import time
def request_approval(decision_id, title=None, message=None, approval_route_id=None, api_key=None):
args = {"decision_id": decision_id}
if title:
args["title"] = title
if message:
args["message"] = message
if approval_route_id:
args["approval_route_id"] = approval_route_id
response = requests.post('https://mcp.tracemem.com',
headers={'Authorization': f'Agent {api_key}'},
json={
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": {
"name": "decision_request_approval",
"arguments": args
}
})
result = response.json()
if "error" in result:
raise Exception(result["error"]["data"])
approval_data = json.loads(result["result"]["content"][0]["text"])
return approval_data
# Evaluate policy
policy_result = evaluate_policy(
decision_id=decision_id,
policy_id="discount_cap_v1",
inputs={"proposed_discount": 0.25, "customer_tier": "standard"},
api_key=api_key
)
if policy_result["outcome"] == "requires_exception":
# Request approval
approval = request_approval(
decision_id=decision_id,
title="Discount Approval Required",
message=f"Customer requesting 25% discount. {policy_result['rationale']['message']}",
api_key=api_key
)
print(f"Approval requested: {approval['approval_id']}")
# Poll for approval
for _ in range(30): # Poll up to 30 times
time.sleep(2)
status = get_decision_status(decision_id, api_key)
if status["status"] == "approved":
print("Approval granted!")
# Proceed with action
break
elif status["status"] == "aborted":
print("Approval rejected")
# Handle rejection
break
Complete Approval Workflow
# Create decision
decision = create_decision(
intent="customer.discount.evaluate",
automation_mode="propose",
api_key=api_key
)
decision_id = decision["decision_id"]
# Read customer data
customer = read_data(
decision_id=decision_id,
product="pg_customers_v1",
purpose="discount_evaluation",
query={"customer_id": "1001"},
api_key=api_key
)
# Evaluate policy
policy_result = evaluate_policy(
decision_id=decision_id,
policy_id="discount_cap_v1",
inputs={
"proposed_discount": 0.25,
"customer_tier": customer["records"][0]["tier"],
"order_value": 10000
},
api_key=api_key
)
# Handle policy outcome
if policy_result["outcome"] == "allow":
# Proceed without approval
apply_discount(decision_id, api_key)
close_decision(decision_id, "commit", api_key=api_key)
elif policy_result["outcome"] == "deny":
# Reject immediately
close_decision(decision_id, "abort",
reason=policy_result["rationale"]["message"],
api_key=api_key)
elif policy_result["outcome"] == "requires_exception":
# Request approval
approval = request_approval(
decision_id=decision_id,
title="High-Value Discount Approval",
message=f"""
Customer: {customer['records'][0]['name']} (ID: {customer['records'][0]['customer_id']})
Requested Discount: 25%
Order Value: $10,000
Customer Tier: {customer['records'][0]['tier']}
Policy Rationale: {policy_result['rationale']['message']}
""",
api_key=api_key
)
# Poll for approval
approved = wait_for_approval(decision_id, timeout=3600, api_key=api_key)
if approved:
apply_discount(decision_id, api_key)
close_decision(decision_id, "commit", api_key=api_key)
else:
close_decision(decision_id, "abort",
reason="Approval was rejected",
api_key=api_key)
def wait_for_approval(decision_id, timeout=3600, api_key=None):
"""Wait for approval with timeout"""
start_time = time.time()
while time.time() - start_time < timeout:
status = get_decision_status(decision_id, api_key)
if status["status"] == "approved":
return True
elif status["status"] == "aborted":
return False
time.sleep(5) # Poll every 5 seconds
raise TimeoutError("Approval request timed out")
Best Practices
-
Provide clear context: Include all relevant information in the
messagefield to help approvers make informed decisions -
Use descriptive titles: Make titles concise but informative (e.g., "25% Discount for Premium Customer")
-
Include policy rationale: When requesting approval after
requires_exception, include the policy's rationale message -
Poll appropriately: Don't poll too frequently (every 2-5 seconds is reasonable)
-
Set timeouts: Don't wait indefinitely for approval; set a reasonable timeout
-
Handle all outcomes: Be prepared for approval, rejection, or timeout
-
Log approval requests: Keep track of approval requests for debugging and audit purposes
-
Use specific approval routes: If you know which approval route to use, specify it explicitly
Important Notes
-
Decision status changes: After requesting approval, the decision status changes to
needs_approval -
Approval delivery: Approvals are delivered asynchronously through configured routes (email, Slack, webhooks, etc.)
-
Self-approval not allowed: Agents cannot approve their own requests
-
Approval routes: Approval routes are configured by administrators and determine how approvals are delivered
-
Expiration: Approval requests may expire if not acted upon within a configured time period
-
Single approval per decision: Typically, only one approval request can be active per decision
-
Approval is required: If a decision requires approval, writes and other operations may be blocked until approval is granted
Related Methods
decision_evaluate- Evaluate policy (often triggers approval requests)decision_get- Check approval statusdecision_close- Close decision after approval/rejectiondecision_create- Create a decision (required before requesting approval)