Users and roles
Everyone who acts in the warrant workflow is a member of an agency with a role.
The role decides what they may do, and it is what X-On-Behalf-Of resolves
against on every write.
The built-in roles
| Role | Typically | Can |
|---|---|---|
PHYSICIAN | Clinical staff | Create and submit applications, comment |
OFFICER | Law enforcement, clerks | Create and submit applications, comment |
JUDGE | The bench | Review, sign, reject, and be routed applications |
ADMIN | Agency administrators | Everything above, plus users, roles, templates, settings, and deletion |
These four exist in every agency and cannot be edited or removed. An agency that needs a different split of duties makes a custom role.
Adding a member
curl -s -X POST "$BASE/users" \
-H "x-api-key: $API_KEY" \
-H "X-On-Behalf-Of: admin.reyes@example.gov" \
-H "Content-Type: application/json" \
-d '{
"email": "clerk.hayes@example.gov",
"full_name": "Dana Hayes",
"title": "Records Clerk",
"role": "OFFICER"
}'
The record exists immediately, so work can be routed and attributed to them.
They sign in once they have completed identity setup, and is_verified
reflects that.
Listing members
curl -s "$BASE/users?role=JUDGE&active_only=true" -H "x-api-key: $API_KEY"
For a compact directory, suitable for filling a picker:
curl -s "$BASE/users/members" -H "x-api-key: $API_KEY"
[{"id": "a83f5c07-…", "full_name": "Hon. Maria Alvarez", "role": "JUDGE"}]
To find who can take a submitted application, use assignable judges, which also reports current workload.
Changing a role
curl -s -X PUT "$BASE/users/$USER_ID/role?role=ADMIN" \
-H "x-api-key: $API_KEY" \
-H "X-On-Behalf-Of: admin.reyes@example.gov"
The change applies immediately. It does not rewrite anything that person has already done: a draft they created stays theirs to submit, and every past action keeps the role it was taken under in the audit trail.
Deactivating
curl -s -X DELETE "$BASE/users/$USER_ID" \
-H "x-api-key: $API_KEY" \
-H "X-On-Behalf-Of: admin.reyes@example.gov"
Deactivation ends someone's ability to act. Their record and their history stay exactly where they are, because a warrant signed by a judge who has since retired is still a warrant signed by that judge. There is no way to delete a member out from under the audit trail.
Custom roles
A custom role is a named set of permissions, scoped to your agency.
curl -s "$BASE/permissions" -H "x-api-key: $API_KEY"
{
"categories": [
{
"category": "Warrants",
"permissions": [
{"key": "warrant:create", "label": "Create warrant applications", "description": "…"},
{"key": "warrant:sign", "label": "Sign warrants", "description": "…"}
]
}
]
}
Build the role from those keys:
curl -s -X POST "$BASE/roles" \
-H "x-api-key: $API_KEY" \
-H "X-On-Behalf-Of: admin.reyes@example.gov" \
-H "Content-Type: application/json" \
-d '{
"name": "Records Clerk",
"description": "Reads applications and the audit trail, and files attachments.",
"permissions": ["warrant:view_all", "file:upload", "audit:view"],
"color": "#3979AC"
}'
PUT /v1/roles/{roleId} changes a role, and the change applies at once to
everyone holding it. DELETE /v1/roles/{roleId} removes it, but only once
nobody holds it: move those members to another role first, or the call returns
409.
Built-in roles are returned by GET /v1/roles with is_system: true and
cannot be modified. Pass include_system=false to list only your own.
Permissions and scopes are different things
They combine, and both have to allow an action:
- A scope is on the API key. It limits what the integration can attempt.
- A permission is on the person in
X-On-Behalf-Of. It limits what that person may do.
A key with warrants:sign acting for a records clerk cannot sign. A judge
cannot sign through a key that lacks the scope. This is deliberate: the key
bounds the integration, the role bounds the person, and a legal signature
requires both.