User Roles and Permissions
SALLY uses role-based access control (RBAC) to manage what each user can do within a tenant. Every user is assigned exactly one role, and that role determines their access to API endpoints and dashboard features.
Role Hierarchy
Roles are ranked in a hierarchy. Higher roles can perform everything lower roles can, plus additional administrative actions.
SUPER_ADMIN
|
ADMIN
|
OWNER
|
DISPATCHER
|
DRIVER| Role | Description | Typical User |
|---|---|---|
SUPER_ADMIN | Platform-level administrator (SALLY staff only) | SALLY support team |
ADMIN | Tenant administrator with full access | IT manager, fleet manager |
OWNER | Tenant owner (assigned at registration) | Company owner, operations VP |
DISPATCHER | Operational user for route planning and monitoring | Dispatcher, operations coordinator |
DRIVER | Driver-only access to assigned routes | CDL driver |
Permission Matrix
The following table shows which operations each role can perform:
Fleet Management
| Operation | DRIVER | DISPATCHER | OWNER | ADMIN | SUPER_ADMIN |
|---|---|---|---|---|---|
| View own driver profile | Yes | — | — | — | — |
| View all drivers | No | Yes | Yes | Yes | Yes |
| Create drivers | No | Yes | Yes | Yes | Yes |
| Update drivers | No | Yes | Yes | Yes | Yes |
| Deactivate drivers | No | No | Yes | Yes | Yes |
| View vehicles | No | Yes | Yes | Yes | Yes |
| Create/update vehicles | No | Yes | Yes | Yes | Yes |
| Delete vehicles | No | No | Yes | Yes | Yes |
| View loads | Own only | Yes | Yes | Yes | Yes |
| Create/update loads | No | Yes | Yes | Yes | Yes |
| Delete loads | No | No | Yes | Yes | Yes |
Route Planning
| Operation | DRIVER | DISPATCHER | OWNER | ADMIN | SUPER_ADMIN |
|---|---|---|---|---|---|
| View own active route | Yes | — | — | — | — |
| View all routes | No | Yes | Yes | Yes | Yes |
| Plan routes | No | Yes | Yes | Yes | Yes |
| Activate routes | No | Yes | Yes | Yes | Yes |
| Cancel routes | No | Yes | Yes | Yes | Yes |
Alerts
| Operation | DRIVER | DISPATCHER | OWNER | ADMIN | SUPER_ADMIN |
|---|---|---|---|---|---|
| View own alerts | Yes | — | — | — | — |
| View all alerts | No | Yes | Yes | Yes | Yes |
| Acknowledge alerts | No | Yes | Yes | Yes | Yes |
| Resolve alerts | No | Yes | Yes | Yes | Yes |
| Snooze alerts | No | Yes | Yes | Yes | Yes |
| Add notes | No | Yes | Yes | Yes | Yes |
| Bulk operations | No | Yes | Yes | Yes | Yes |
| View analytics | No | Yes | Yes | Yes | Yes |
Administration
| Operation | DRIVER | DISPATCHER | OWNER | ADMIN | SUPER_ADMIN |
|---|---|---|---|---|---|
| View tenant settings | No | No | Yes | Yes | Yes |
| Update tenant settings | No | No | Yes | Yes | Yes |
| Manage integrations | No | No | Yes | Yes | Yes |
| Create API keys | No | No | Yes | Yes | Yes |
| Revoke API keys | No | No | Yes | Yes | Yes |
| Invite users | No | No | Yes | Yes | Yes |
| Manage user roles | No | No | No | Yes | Yes |
| Suspend/reactivate tenant | No | No | No | No | Yes |
| Approve tenant registrations | No | No | No | No | Yes |
User Invitation Flow
New users are added to a tenant via the invitation system. Only users with OWNER, ADMIN, or SUPER_ADMIN roles can send invitations.
Send an Invitation
curl -X POST https://sally-api.apps.appshore.in/api/v1/user-invitations \
-H "X-API-Key: $SALLY_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"email": "tom.garcia@acmefreight.com",
"role": "DISPATCHER",
"firstName": "Tom",
"lastName": "Garcia"
}'JavaScript (fetch):
const response = await fetch(
"https://sally-api.apps.appshore.in/api/v1/user-invitations",
{
method: "POST",
headers: {
"X-API-Key": process.env.SALLY_API_KEY,
"Content-Type": "application/json",
},
body: JSON.stringify({
email: "tom.garcia@acmefreight.com",
role: "DISPATCHER",
firstName: "Tom",
lastName: "Garcia",
}),
}
);
const invitation = await response.json();Response:
{
"id": "inv_h8i9j0k1",
"email": "tom.garcia@acmefreight.com",
"role": "DISPATCHER",
"firstName": "Tom",
"lastName": "Garcia",
"status": "PENDING",
"invitedBy": {
"id": "usr_r1w2i3l4",
"name": "Robert Williams"
},
"tenantId": "tnt_acme001",
"expiresAt": "2026-02-17T10:00:00Z",
"createdAt": "2026-02-10T10:00:00Z"
}Invitation for a Driver
When inviting a driver, you can link the invitation to an existing driver profile:
curl -X POST https://sally-api.apps.appshore.in/api/v1/user-invitations \
-H "X-API-Key: $SALLY_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"email": "mike.johnson@acmefreight.com",
"role": "DRIVER",
"firstName": "Mike",
"lastName": "Johnson",
"driverId": "drv_a1b2c3d4"
}'Once the driver accepts the invitation, their user account is automatically linked to the driver profile. They can then view their assigned routes and HOS data through the driver interface.
Accept an Invitation
The invited user receives an email with an acceptance link containing a token. They accept by providing a password:
curl -X POST https://sally-api.apps.appshore.in/api/v1/user-invitations/accept \
-H "Content-Type: application/json" \
-d '{
"token": "inv_token_XXXXXXXXXXXXXXXX",
"password": "their_secure_password"
}'Response:
{
"user": {
"id": "usr_t5g6a7r8",
"firstName": "Tom",
"lastName": "Garcia",
"email": "tom.garcia@acmefreight.com",
"role": "DISPATCHER",
"tenantId": "tnt_acme001"
},
"accessToken": "eyJhbGciOiJSUzI1NiIs...",
"message": "Account created successfully. Welcome to SALLY."
}Invitation Lifecycle
| Status | Description |
|---|---|
PENDING | Invitation sent, awaiting acceptance |
ACCEPTED | User accepted and created their account |
EXPIRED | Invitation expired (7 days without acceptance) |
REVOKED | Invitation manually revoked by an admin |
List Pending Invitations
curl "https://sally-api.apps.appshore.in/api/v1/user-invitations?status=PENDING" \
-H "X-API-Key: $SALLY_API_KEY"Response:
{
"data": [
{
"id": "inv_h8i9j0k1",
"email": "tom.garcia@acmefreight.com",
"role": "DISPATCHER",
"status": "PENDING",
"expiresAt": "2026-02-17T10:00:00Z",
"createdAt": "2026-02-10T10:00:00Z"
}
],
"total": 1
}Role-Based API Behavior
DRIVER Role
Users with the DRIVER role have a restricted view. API responses are automatically filtered to show only their own data:
# As a DRIVER, this returns only the driver's own active route
curl https://sally-api.apps.appshore.in/api/v1/routes/driver/drv_a1b2c3d4/active \
-H "Authorization: Bearer DRIVER_JWT_TOKEN"Response:
{
"planId": "rte_f8e7d6c5",
"status": "ACTIVE",
"segments": [...],
"summary": {
"totalDistanceMiles": 360.0,
"estimatedCompletion": "2026-02-10T18:42:00Z"
}
}Drivers cannot:
- View other drivers’ routes or profiles
- Create or modify fleet resources
- Access alert management or analytics
- Manage integrations or tenant settings
DISPATCHER Role
Dispatchers have operational access to all fleet data within the tenant:
# As a DISPATCHER, this returns all active alerts for the fleet
curl "https://sally-api.apps.appshore.in/api/v1/alerts?status=ACTIVE" \
-H "Authorization: Bearer DISPATCHER_JWT_TOKEN"Dispatchers can:
- View and manage all drivers, vehicles, loads, and routes
- Plan and activate routes
- Acknowledge, resolve, and manage alerts
- View analytics and history
Dispatchers cannot:
- Manage tenant settings or integrations
- Create or revoke API keys
- Invite users or change roles
- Delete fleet resources (soft deletes only)
OWNER / ADMIN Roles
These roles have full access to all tenant operations including administration:
# As an OWNER, configure tenant settings
curl -X PUT https://sally-api.apps.appshore.in/api/v1/tenant/settings/alerts \
-H "X-API-Key: $SALLY_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"hosApproachingThresholdHours": 1.0,
"enableWeatherAlerts": true
}'The difference between OWNER and ADMIN:
OWNERis assigned automatically at registration (one per tenant)ADMINcan be assigned to additional users by the OWNERADMINcan change user roles;OWNERcan do everything an ADMIN can
Changing User Roles
Admins and above can change a user’s role (except their own):
curl -X PUT https://sally-api.apps.appshore.in/api/v1/users/usr_t5g6a7r8/role \
-H "X-API-Key: $SALLY_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"role": "ADMIN"
}'JavaScript (fetch):
const response = await fetch(
"https://sally-api.apps.appshore.in/api/v1/users/usr_t5g6a7r8/role",
{
method: "PUT",
headers: {
"X-API-Key": process.env.SALLY_API_KEY,
"Content-Type": "application/json",
},
body: JSON.stringify({ role: "ADMIN" }),
}
);
const updated = await response.json();Response:
{
"id": "usr_t5g6a7r8",
"firstName": "Tom",
"lastName": "Garcia",
"email": "tom.garcia@acmefreight.com",
"role": "ADMIN",
"previousRole": "DISPATCHER",
"updatedAt": "2026-02-10T15:00:00Z"
}Role Change Rules
- You can only assign roles equal to or below your own level
- You cannot change your own role
- There must always be at least one
OWNERin a tenant SUPER_ADMINcan only be assigned by otherSUPER_ADMINusers (SALLY staff)
Error Responses
403 Forbidden — Insufficient Role
{
"statusCode": 403,
"message": "DISPATCHER role cannot access tenant settings. Required: OWNER or ADMIN.",
"error": "Forbidden"
}400 Bad Request — Invalid Role Assignment
{
"statusCode": 400,
"message": "Cannot assign SUPER_ADMIN role. Only SALLY administrators can assign this role.",
"error": "Bad Request"
}400 Bad Request — Last Owner
{
"statusCode": 400,
"message": "Cannot change role of the last OWNER. Assign another user as OWNER first.",
"error": "Bad Request"
}409 Conflict — Duplicate Invitation
{
"statusCode": 409,
"message": "An active invitation already exists for tom.garcia@acmefreight.com",
"error": "Conflict"
}Next Steps
- Tenant Setup — Register and configure your organization
- API Keys — Generate keys for your integrations
- Drivers API — Start building your fleet