Workforce registry
Provision human servicing users and register AI workers in one workforce registry, bound by queue, task-type, capacity, fact, tool, and action grants.
A person and an AI agent are hired differently and are held to the same rules once hired. One registry, so nothing about who did the work depends on which kind of worker it was.
Routing, reservation, autonomy, and attribution all resolve against a worker record. The two kinds are provisioned differently and then held to the same eligibility rules.
/v1/servicing/users
- A login plus the person’s worker record
- Presence, and the eligibility profile the router reads
- Read back through /users and /users/{userId}
/v1/servicing/workers
- A registration bound to an adapter contract
- Fact, tool and action grants that set the ceiling
- Read back through /workers and /workers/{workerId}
Adding a person
Creating a user happens in one step. It creates the login, the HUMAN worker, initial presence, and the queue and task-type eligibility the router reads:
curl -X POST "$BASE/v1/servicing/users" \
-H "Authorization: Bearer $TOKEN" \
-H "LendEasy-Tenant: demo-lender" \
-H "Content-Type: application/json" \
-d '{
"username": "maria.agent",
"temporaryPassword": "<write-only>",
"firstName": "Maria",
"lastName": "Agent",
"email": "maria@example.invalid",
"officeId": 1,
"roleIds": [7],
"workerProfile": {
"queueCodes": ["COLLECTIONS"],
"taskTypeCodes": ["COLLECTIONS_OUTREACH"],
"languages": ["en"],
"capacity": 8
}
}'
{
"userId": 4101,
"username": "maria.agent",
"displayName": "Maria Agent",
"active": true,
"resourceId": 4101
}
temporaryPassword is write-only and never appears in a read. Reads return a safe projection — identity, office, roles, active state, credentialResetRequired, and the worker profile — without internal login keys or credential material.
PUT /v1/servicing/users/{userId} replaces the mutable administration and worker-profile fields. username and the public user ID are immutable; deactivation is active: false, not deletion, so historical attribution survives.
Register an AI worker
An AI registration declares the adapter contract it speaks and the exact authority ceiling it may exercise:
curl -X POST "$BASE/v1/servicing/workers" \
-H "Authorization: Bearer $TOKEN" \
-H "LendEasy-Tenant: demo-lender" \
-H "Content-Type: application/json" \
-d '{
"workerCode": "COLLECTIONS_VOICE_PRIMARY",
"displayName": "Collections voice agent",
"adapterCode": "OUTBOUND_VOICE_V1",
"contractVersion": "1.0",
"credentialRef": "voice-agent-client",
"readinessEvidenceRef": "eval-2027-05-04",
"queueCodes": ["COLLECTIONS"],
"taskTypeCodes": ["COLLECTIONS_OUTREACH"],
"languages": ["en"],
"capacity": 20,
"factGroupGrants": ["LOAN", "OVERDUE", "PAYMENT", "PAYMENT_INSTRUMENT", "CONTACT", "RESTRICTION"],
"toolGrants": ["CHECK_CONTACT_ELIGIBILITY", "SUBMIT_VOICE_DISPOSITION"],
"eligibleActionCodes": ["AR_002_CREATE_PROMISE_TO_PAY", "AR_007_PREPARE_BORROWER_AUTHORIZED_PAYMENT"],
"active": true
}'
Three grant lists define the ceiling, and each is enforced separately at runtime:
| Grant | Bounds | Example |
|---|---|---|
factGroupGrants |
Which fact groups may enter the agent’s work packet. | RESTRICTION without PAYMENT_INSTRUMENT. |
toolGrants |
Which declared tools the session may call. | CHECK_CONTACT_ELIGIBILITY. |
eligibleActionCodes |
Which actions the agent may prepare at all. | AR_002_CREATE_PROMISE_TO_PAY. |
credentialRef and readinessEvidenceRef are references, not secrets: reads return the registration without resolving credential material or the agent’s connection settings. PUT /v1/servicing/workers/{workerId} replaces every mutable field and revalidates the whole contract before the registration is activated again — a partial edit cannot leave a worker active against a contract that no longer validates.
Administering the workforce is not doing the work
| Operation | Permission |
|---|---|
| Read users | READ_SERVICING_USER |
| Create a user | CREATE_SERVICING_USER |
| Replace a user profile | UPDATE_SERVICING_USER |
| Read AI workers | READ_SERVICING_WORKER |
| Register or replace an AI worker | CREATE_SERVICING_WORKER / UPDATE_SERVICING_WORKER |
| Read own worker context | READ_SERVICING_TASK |
| Set own presence | UPDATE_SERVICING_WORKER_PRESENCE |
Administering the workforce and doing the work are separate authorities. Holding UPDATE_SERVICING_WORKER does not let an operator raise their own eligibility to reach restricted work, and no route lets a worker widen their own profile.
Continue with How agents are governed for the session model, and Queues, routing & who gets the work for how these records rank and reserve work.