Approvals API
Review and decide on AI-proposed actions via the API
The Approvals API allows you to retrieve pending approvals and make decisions on AI-proposed actions such as sending replies or executing platform actions.
Overview
When Keva's AI proposes an action that requires human review (based on your autonomy settings), it creates an approval request. Use this API to:
- List pending approvals
- View approval details
- Approve or reject proposed actions
Endpoints
| Method | Endpoint | Description |
|---|---|---|
| GET | /api/approvals | List approvals |
| PATCH | /api/approvals/:id | Decide on an approval |
List Approvals
Retrieve approvals filtered by status.
GET /api/approvalsQuery Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
status | string | pending | Filter: pending, approved, rejected |
Example Request
curl "https://app.keva.support/api/approvals?status=pending" \
-H "Authorization: Bearer keva_live_your_api_key"Example Response
[
{
"id": "apr_abc123",
"ticketId": "tkt_xyz789",
"actionType": "send_reply",
"status": "pending",
"expiresAt": "2024-01-15T18:30:00Z",
"createdAt": "2024-01-15T10:30:00Z",
"decidedAt": null,
"ticketSubject": "Cannot access my account",
"customerEmail": "customer@example.com",
"customerName": "John Doe",
"draft": "Hi John,\n\nI understand you're having trouble accessing your account...",
"model": "claude-sonnet-4-20250514",
"classification": {
"category": "account_access",
"sentiment": "frustrated",
"urgency": "high"
},
"reasoning": {
"context": "Customer locked out of account",
"approach": "Provide password reset instructions",
"confidence": 0.92
}
},
{
"id": "apr_def456",
"ticketId": "tkt_abc123",
"actionType": "platform_action",
"status": "pending",
"platform": "shopify",
"actionId": "refund_order",
"description": "Refund order #12345 for $49.99",
"riskLevel": "medium",
"diff": [
{"field": "order_status", "before": "fulfilled", "after": "refunded"},
{"field": "refund_amount", "before": "$0.00", "after": "$49.99"}
]
}
]Approval Types
Send Reply (send_reply)
AI-drafted response to send to the customer.
| Field | Description |
|---|---|
draft | The proposed message text |
model | AI model used for generation |
classification | Ticket classification (category, sentiment, urgency) |
reasoning | AI's reasoning for the response |
Platform Action (platform_action)
Proposed action on a connected platform.
| Field | Description |
|---|---|
platform | Platform name (e.g., shopify, stripe) |
actionId | Action identifier |
description | Human-readable description |
riskLevel | low, medium, high |
diff | Before/after changes |
Browser Action (browser_action)
Proposed browser automation task.
| Field | Description |
|---|---|
siteUrl | Target website URL |
description | Task description |
previewUrl | Screenshot preview URL |
Action Plan (action_plan)
Multi-step action sequence.
| Field | Description |
|---|---|
planId | Plan identifier |
planTitle | Plan title |
planDescription | Overall description |
planSteps | Array of steps to execute |
overallRisk | Combined risk assessment |
Decide on Approval
Approve or reject a pending approval.
PATCH /api/approvals/:idRequest Body
| Field | Type | Required | Description |
|---|---|---|---|
decision | string | Yes | approved or rejected |
rejectionReason | string | No | Reason for rejection |
Example: Approve
curl -X PATCH https://app.keva.support/api/approvals/apr_abc123 \
-H "Authorization: Bearer keva_live_your_api_key" \
-H "Content-Type: application/json" \
-d '{"decision": "approved"}'Example: Reject
curl -X PATCH https://app.keva.support/api/approvals/apr_abc123 \
-H "Authorization: Bearer keva_live_your_api_key" \
-H "Content-Type: application/json" \
-d '{
"decision": "rejected",
"rejectionReason": "Tone is too informal for this customer"
}'Response
{
"id": "apr_abc123",
"status": "approved"
}Expiration
Approvals have an expiration time (typically 24 hours). Expired approvals:
- Are automatically filtered from the pending list
- Cannot be approved or rejected
- Result in no action being taken
Race Condition Handling
The API uses atomic database operations to prevent race conditions. If two users try to decide on the same approval simultaneously:
- Only one decision succeeds
- The second request receives a
404error - The approval's final state reflects only the first decision