Skip to main content

Approval Matrix

The approval matrix governs who can approve what across the platform. It combines authority profiles (what a user is allowed to do), referral rules (when to escalate), and approval records (the decision trail). The system is implemented across two API route groups: apps/api/src/routes/authority.ts for profile and rule management, and apps/api/src/routes/approvals.ts for the approval workflow.

Authority Profiles

An authority profile defines the underwriting limits for a group of users. Profiles are scoped to an organization and ordered by level (1 = most junior, 10 = most senior).

Profile Fields

FieldTypeDescription
namestringProfile name (e.g., "Junior Underwriter", "VP Underwriting")
level1--10Authority tier -- higher levels can approve larger risks
maxTivnumberMaximum total insured value this profile can bind
maxLimitnumberMaximum policy limit this profile can bind
maxPremiumnumberMaximum premium this profile can bind
authorizedLobsstring[]Lines of business the profile can underwrite
prohibitedStatesstring[]States where this profile cannot write
canOverridebooleanWhether violations can be overridden (senior authority)
constraintsJSONAdditional org-specific constraints

CRUD Operations

# List all active profiles for an org
GET /v1/authority/profiles?orgId={orgId}

# Include inactive profiles
GET /v1/authority/profiles?orgId={orgId}&includeInactive=true

# Create a new profile
POST /v1/authority/profiles
{
"orgId": "uuid",
"name": "Senior Underwriter",
"level": 3,
"maxTiv": 5000000,
"maxLimit": 2000000,
"maxPremium": 100000,
"authorizedLobs": ["commercial_auto", "general_liability"],
"prohibitedStates": []
}

# Update a profile
PATCH /v1/authority/profiles/:id
{
"maxPremium": 150000,
"canOverride": true
}

User Assignment

Each user is assigned to exactly one active authority profile at a time. Assigning a user to a new profile automatically deactivates their previous assignment.

POST /v1/authority/profiles/:id/assign
{
"userId": "uuid",
"effectiveFrom": "2026-03-24T00:00:00Z",
"effectiveTo": "2026-12-31T23:59:59Z",
"notes": "Promoted to senior tier"
}

Assignments have optional effectiveFrom and effectiveTo dates. Expired assignments are automatically excluded from authority checks.

Profile Detail

The GET /v1/authority/profiles/:id endpoint returns the profile with its currently assigned users (userId, name, email, assignedAt, assignedBy).

Authority Check

The POST /v1/authority/check endpoint evaluates whether a specific user can perform a given action in context. This is called during submission processing to determine whether the underwriter can bind directly or must refer.

Request

{
"userId": "uuid",
"action": "bind",
"context": {
"tiv": 3500000,
"premium": 75000,
"limit": 1000000,
"lob": "commercial_auto",
"state": "FL"
}
}

Evaluation Logic

The check evaluates five dimensions against the user's assigned authority profile:

CheckConditionViolation Message
TIVcontext.tiv > profile.maxTiv"TIV $X exceeds limit of $Y"
Premiumcontext.premium > profile.maxPremium"Premium $X exceeds limit of $Y"
Limitcontext.limit > profile.maxLimit"Limit $X exceeds authority of $Y"
LOBcontext.lob not in profile.authorizedLobs"LOB 'X' not authorized"
Statecontext.state in profile.prohibitedStates"State 'X' is prohibited"

Decision Rules

  • Allowed: No violations found.
  • Allowed (override): Violations exist, but the profile has canOverride: true.
  • Allowed (refer): The action is refer -- referrals are always permitted regardless of violations.
  • Denied: Violations exist and the profile cannot override.

Response

{
"data": {
"allowed": false,
"violations": ["TIV $3,500,000 exceeds limit of $2,000,000"],
"authority": {
"level": 2,
"name": "Junior Underwriter",
"canOverride": false,
"maxTiv": 2000000,
"maxPremium": 50000,
"maxLimit": 1000000
}
}
}

Authority Matrix View

The GET /v1/authority/matrix?orgId={orgId} endpoint returns the complete authority grid for an organization -- all active profiles with their assigned users and the full set of lines of business in use. This powers the matrix view in the admin UI.

{
"data": {
"profiles": [
{ "level": 1, "name": "Assistant UW", "maxTiv": 1000000, "assigned_users": [...] },
{ "level": 2, "name": "Underwriter", "maxTiv": 3000000, "assigned_users": [...] },
{ "level": 3, "name": "Senior UW", "maxTiv": 10000000, "assigned_users": [...] }
],
"lineOfBusinesses": ["commercial_auto", "general_liability", "cargo"]
}
}

Referral Rules

Referral rules define the conditions under which a submission is automatically escalated. Rules are evaluated in priority order (lower number = higher priority) and can trigger referral, auto-approval, or auto-rejection.

Rule Fields

FieldTypeDescription
namestringRule name
prioritynumberEvaluation order (lower = first)
conditionsJSONCondition object evaluated against submission data
actionenumrefer, auto_approve, or auto_reject
targetAuthorityLevelnumberMinimum authority level required to handle the referral
targetProfileIduuidSpecific profile to route to (optional)
notifyChannelsarrayNotification channels: slack, email, in_app
slackChannelstringSlack channel for notifications
notifyEmailsarrayEmail addresses to notify
escalationEnabledbooleanWhether to auto-escalate after timeout
escalationHoursnumberHours before escalation (default: 24)
escalationLevelnumberAuthority level to escalate to

Example: High-TIV Referral Rule

POST /v1/authority/rules
{
"orgId": "uuid",
"name": "High TIV Referral",
"priority": 10,
"conditions": { "tiv": { "$gt": 5000000 } },
"action": "refer",
"targetAuthorityLevel": 4,
"notifyChannels": ["slack", "email"],
"slackChannel": "#uw-referrals",
"notifyEmails": ["senior-uw@mga.com"],
"escalationEnabled": true,
"escalationHours": 12,
"escalationLevel": 5
}

Rules are soft-deleted -- DELETE /v1/authority/rules/:id sets is_active to false.

Approval Workflow

When a submission exceeds an underwriter's authority or a referral rule triggers, an approval record is created in the approvals table.

Approval Types

TypeEntity TypeTrigger
bindsubmissionBind request exceeds underwriter's authority limits
siu_referralclaimSpecial Investigations Unit referral
reserve_changeclaimReserve change exceeds adjuster's authority
bordereaux_submitbordereauxBordereaux submission requires sign-off

Creating an Approval

Approvals are created programmatically by the system (role: system or org_admin) when an action requires escalation:

{
"orgId": "uuid",
"type": "bind",
"entityType": "submission",
"entityId": "uuid",
"workflowId": "workflow-instance-id",
"requestedBy": "uuid",
"metadata": { "submissionId": "uuid", "premium": 120000 },
"expiresAt": "2026-04-01T00:00:00Z"
}

Decision Endpoint

POST /v1/approvals/:id/decide
{
"decision": "approved",
"decidedBy": "uuid",
"notes": "Reviewed loss history, acceptable risk"
}

The endpoint enforces:

  • Idempotency: Already-decided approvals return 409.
  • Expiry: Expired approvals return 409.

Side Effects

Bind rejection: When a bind approval is rejected, the system reverts both the policy and the linked submission to declined status.

Workflow resumption: If the approval is tied to a Cloudflare Workflow instance (workflowId), the decision event is sent to the workflow to resume processing:

  • bind approvals send to BIND_WORKFLOW with event type underwriter-bind-approval.
  • reserve_change approvals send to CLAIM_WORKFLOW with event type claim.reserve_approved.

API Reference

Authority Endpoints

MethodPathDescription
GET/v1/authority/profilesList authority profiles
POST/v1/authority/profilesCreate authority profile
GET/v1/authority/profiles/:idGet profile with assigned users
PATCH/v1/authority/profiles/:idUpdate profile limits
POST/v1/authority/profiles/:id/assignAssign user to profile
GET/v1/authority/rulesList referral rules
POST/v1/authority/rulesCreate referral rule
PATCH/v1/authority/rules/:idUpdate referral rule
DELETE/v1/authority/rules/:idSoft-delete referral rule
GET/v1/authority/matrixFull authority matrix grid
POST/v1/authority/checkCheck user authority for action

Approval Endpoints

MethodPathDescription
GET/v1/approvalsList approvals (paginated, filtered by status)
POST/v1/approvalsCreate approval record
POST/v1/approvals/:id/decideApprove or reject