Smart queues & routing
Turn workflow obligations into atomic tasks, rank them by explicit policy, reserve them without double work, and route only to workers whose skills, permissions, capacity, and autonomy qualify.
Cases preserve why work exists. Tasks specify the next unit of work. Queues rank eligible tasks; they do not own case state or silently complete outcomes.
Task lifecycle
Completing a task can request a workflow transition; the case still checks exit criteria. “Call completed” does not mean “collections case resolved.”
Eligibility before ranking
A task is first filtered by hard qualifications:
- tenant and queue access;
- named permission and role;
- case/task type skill;
- language and accessibility skill;
- sensitive-content clearance;
- human-only, AI-assist, AI-prepare, or AI-execute policy;
- worker presence and active-task capacity;
- separation-of-duties conflicts;
- suppression, conflict, and assignment rules.
Only eligible work is ranked. High priority cannot route a bankruptcy-review task to an unqualified general worker.
Explainable priority
Ranking can combine configured severity, service-level time remaining, customer vulnerability, promised follow-up time, regulatory deadline, monetary exposure, aging, and fairness controls. The task exposes the factors that produced its score; opaque model output cannot be the sole reason urgent regulated work moved down a queue.
{
"taskId": "task_HBR_CALL_8",
"status": "available",
"priority": 82,
"queueId": "queue_early_collections",
"dueAt": "2027-05-01T17:00:00-07:00",
"rankingFactors": [
{ "factor": "service_level_remaining", "points": 35 },
{ "factor": "days_past_due", "points": 22 },
{ "factor": "customer_callback_window", "points": 25 }
]
}
Worker context and the task-type catalog
Two self-serve reads keep the workspace grounded in the authenticated worker’s real eligibility instead of client-side assumptions. GET /v1/servicing/me returns the worker’s own context in one call — identity, queue memberships, task-type eligibility, presence, the live reservation if one exists, active assignments, and whether the worker is at capacity:
{
"workerId": 4101,
"displayName": "Maria Agent",
"active": true,
"capacity": 8,
"taskTypeCodes": ["COLLECTIONS_OUTREACH"],
"queueCodes": ["COLLECTIONS"],
"presence": { "state": "AVAILABLE", "channels": ["PHONE", "GENERAL"], "since": "2027-05-05T18:00:00Z", "setBy": "AGENT_TOGGLE" },
"activeReservation": { "taskId": 2001, "reservationExpiresAt": "2027-05-05T18:40:00Z" },
"activeAssignments": [
{ "taskId": 2002, "status": "IN_PROGRESS", "taskTypeCode": "COLLECTIONS_OUTREACH", "queueCode": "COLLECTIONS", "priority": "HIGH", "dueAt": "2027-05-06T17:00:00Z" }
],
"activeAssignmentCount": 1,
"atCapacity": false
}
GET /v1/servicing/task-types returns the presentation-safe task-type catalog for enabled queues — code, display name, default queue, and default priority — without exposing AI-eligibility or worker-type internals.
Atomic reservation
The implemented route derives the worker, skills, capacity, and reservation duration from the authenticated workforce record and queue policy:
curl -X POST "$BASE/v1/servicing/tasks/reserve-next" \
-H "Authorization: Bearer $TOKEN" \
-H "LendEasy-Tenant: demo-lender" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: reserve-next-ana-4-2027-05-01T1000" \
-d '{
"queueCode": "COLLECTIONS",
"taskTypeCodes": ["COLLECTIONS_OUTREACH"]
}'
{
"taskId": 2001,
"reservationExpiresAt": "2027-05-01T10:02:00-07:00"
}
Selection and reservation happen atomically, so two workers cannot receive the same task. The reservation is a short offer, not permanent ownership.
Queue-addressed variant (roadmap)
The following queue-addressed form is retained as product direction:
curl -X POST "$BASE/v1/servicing/queues/queue_early_collections/tasks/reserve-next" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: reserve-next-ana-4-2027-05-01T1000" \
-d '{
"workerId": "worker_ANA_4",
"skills": ["collections", "english"],
"reservationSeconds": 120
}'
Accept, decline, complete, release, cancel
Reservation is only the offer. Five commands carry a task the rest of the way, and each records the decision that ended it:
| Command | Body | Permission |
|---|---|---|
POST /tasks/{taskId}/accept |
None — it accepts the caller’s own live reservation. | ACCEPT_SERVICING_TASK |
POST /tasks/{taskId}/decline |
Turns down the caller’s own live offer so it requeues immediately. | DECLINE_SERVICING_TASK |
POST /tasks/{taskId}/complete |
outcomeCode required; note, fields, followUp optional. |
COMPLETE_SERVICING_TASK |
POST /tasks/{taskId}/release |
The full unable/requeue decision. | ACCEPT_SERVICING_TASK |
POST /tasks/{taskId}/cancel |
reason required. |
CANCEL_SERVICING_TASK |
Completion carries the evidence the task type demands:
curl -X POST "$BASE/v1/servicing/tasks/2001/complete" \
-H "Authorization: Bearer $TOKEN" \
-H "LendEasy-Tenant: demo-lender" \
-H "Content-Type: application/json" \
-d '{
"outcomeCode": "CUSTOMER_REACHED",
"note": "Customer agreed to a promise to pay.",
"fields": { "identity_verified": true, "contact_channel": "PHONE" },
"followUp": { "taskTypeCode": "REVIEW_PROMISE_OUTCOME", "dueDate": "2026-08-02" }
}'
fields must satisfy the task type’s configured completion-field definitions, so “record whether identity was verified” is enforced by the platform rather than by a client-side form — see Servicing configuration. followUp creates the next task only where policy allows it; it is not a way to invent arbitrary work.
Releasing is not a silent undo. Every field is required, because returning work to a queue is an operational decision that has to be attributable:
{
"unableReason": "SHIFT_ENDED",
"note": "Returning unstarted work to the queue.",
"requeueDecision": "RETURN_TO_QUEUE",
"createReplacementTask": false,
"managerReviewRequired": false
}
Cancel is different again: it ends work that has become obsolete — usually because the owning case resolved. Where the workflow required that task, cancelling blocks case progression or creates replacement work rather than quietly removing an obligation.
Reassignment and escalation
Reassignment records source and destination, actor, reason, eligibility result, and service-level impact. GET /v1/servicing/tasks/{taskId}/reassignment-options gives the manager valid destinations first: eligible queues for the task, and under-capacity eligible workers in its current queue. The read requires the same reassign authority as the command, and terminal tasks return empty lists.
POST /v1/servicing/tasks/{taskId}/reassign then moves the work under REASSIGN_SERVICING_TASK:
{
"targetType": "QUEUE",
"targetRef": "HARDSHIP",
"reason": "Specialist skill is required."
}
{
"resourceId": 2001,
"changes": { "queueCode": "HARDSHIP", "status": "AVAILABLE" }
}
The command revalidates the chosen target rather than trusting the option list — a stale option fails closed. Reassigning to a queue returns the task to AVAILABLE for ranking; it does not hand ownership to a worker who has not reserved it. Escalation is a case control that can create a higher-priority specialist task; it is not a way to bypass permissions or review requirements.
Fairness and operability
Monitor time-to-first-action, deadline misses, reassignments, expired reservations, workload by worker and language, AI/human fall-through, ranking drift, and subgroup outcomes. Do not optimize only throughput at the expense of customer access or regulated-work timeliness.