Documentation Index
Fetch the complete documentation index at: https://docs.kaireonai.com/llms.txt
Use this file to discover all available pages before exploring further.
GET /api/v1/approvals
List approval requests filtered by status.
Query Parameters
| Parameter | Type | Default | Description |
|---|
status | string | "pending" | Filter by status: "pending", "approved", "rejected" |
Response
[
{
"id": "approval_001",
"entityType": "qualificationRule",
"entityId": "qr_001",
"entityName": "Credit Score Rule",
"action": "update",
"status": "pending",
"requesterId": "user_001",
"requesterName": "John Doe",
"payload": { "config": { "threshold": 650 } },
"createdAt": "2026-03-15T10:00:00.000Z"
}
]
POST /api/v1/approvals
Create a new approval request.
Request Body
| Field | Type | Required | Description |
|---|
entityType | string | Yes | Entity type (e.g., "qualificationRule", "contactPolicy", "decisionFlow", "offer") |
entityId | string | Yes | ID of the entity to modify |
entityName | string | Yes | Display name of the entity |
action | string | Yes | "create", "update", or "delete" |
payload | object | No | The proposed changes to apply on approval |
stages | Array<{ stageName, requiredRole }> | No | Optional multi-stage chain. Each stage has stageName: string and requiredRole: "viewer" | "editor" | "admin". Decisions walk the stages in order. When omitted, one default admin stage is created. See Four-eyes governance. |
Example
curl -X POST https://playground.kaireonai.com/api/v1/approvals \
-H "Content-Type: application/json" \
-H "X-Tenant-Id: my-tenant" \
-d '{
"entityType": "qualificationRule",
"entityId": "qr_001",
"entityName": "Credit Score Rule",
"action": "update",
"payload": { "config": { "threshold": 650 } }
}'
Response: 201 Created
GET /api/v1/approvals/
Get a single approval request.
POST /api/v1/approvals/
Resolve an approval request (approve or reject). Editors and admins
can decide; the per-stage requiredRole is then enforced inside the
walk. Viewers are 403’d at the route boundary.
When the last stage of the chain is approved, the stored payload
is automatically applied to the target entity. Supported entity types
for auto-application: algorithmModel, qualificationRule,
contactPolicy, decisionFlow, offer, creative, channel,
arbitrationProfile. An unsupported entityType causes the whole
transaction (stage update + parent flip + apply) to roll back —
returning a 409 — so an approval cannot flip to approved without the
entity actually changing.
Request Body
| Field | Type | Required | Description |
|---|
action | string | Yes | "approve" or "reject" |
comments | string | No | Reviewer comments |
Response (approved)
{
"id": "approval_001",
"status": "approved",
"approverId": "user_002",
"approverName": "Admin",
"comments": "Looks good, deploying to production",
"resolvedAt": "2026-03-16T14:30:00.000Z"
}
Response (rejected)
{
"id": "approval_001",
"status": "rejected",
"approverId": "user_002",
"approverName": "Admin",
"comments": "Threshold too aggressive, please revise",
"resolvedAt": "2026-03-16T14:30:00.000Z"
}
Roles
| Endpoint | Allowed Roles |
|---|
GET /approvals | any authenticated |
POST /approvals | any authenticated |
GET /approvals/{id} | any authenticated (returns parent + ordered stages array in one round-trip) |
POST /approvals/{id} (resolve) | editor or admin (per-stage requiredRole is enforced inside the walk) |
Auto-expiry
Pending approvals that sit unresolved for longer than
APPROVAL_MAX_AGE_HOURS (default 168 = 7 days) are auto-flipped to
status = "expired" by the
/api/v1/cron/approvals-expire
endpoint. Wire it into your scheduler at any cadence — every 15 minutes
is plenty since the operation is a single bulk UPDATE and idempotent.
The cutoff is configurable per-deployment via the
APPROVAL_MAX_AGE_HOURS env var. Expired requests retain their full
audit trail; only status and resolvedAt change.
See also: Compliance · Cron jobs