API GuidesMulti-tenancyUser Roles & Permissions

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
RoleDescriptionTypical User
SUPER_ADMINPlatform-level administrator (SALLY staff only)SALLY support team
ADMINTenant administrator with full accessIT manager, fleet manager
OWNERTenant owner (assigned at registration)Company owner, operations VP
DISPATCHEROperational user for route planning and monitoringDispatcher, operations coordinator
DRIVERDriver-only access to assigned routesCDL driver

Permission Matrix

The following table shows which operations each role can perform:

Fleet Management

OperationDRIVERDISPATCHEROWNERADMINSUPER_ADMIN
View own driver profileYes
View all driversNoYesYesYesYes
Create driversNoYesYesYesYes
Update driversNoYesYesYesYes
Deactivate driversNoNoYesYesYes
View vehiclesNoYesYesYesYes
Create/update vehiclesNoYesYesYesYes
Delete vehiclesNoNoYesYesYes
View loadsOwn onlyYesYesYesYes
Create/update loadsNoYesYesYesYes
Delete loadsNoNoYesYesYes

Route Planning

OperationDRIVERDISPATCHEROWNERADMINSUPER_ADMIN
View own active routeYes
View all routesNoYesYesYesYes
Plan routesNoYesYesYesYes
Activate routesNoYesYesYesYes
Cancel routesNoYesYesYesYes

Alerts

OperationDRIVERDISPATCHEROWNERADMINSUPER_ADMIN
View own alertsYes
View all alertsNoYesYesYesYes
Acknowledge alertsNoYesYesYesYes
Resolve alertsNoYesYesYesYes
Snooze alertsNoYesYesYesYes
Add notesNoYesYesYesYes
Bulk operationsNoYesYesYesYes
View analyticsNoYesYesYesYes

Administration

OperationDRIVERDISPATCHEROWNERADMINSUPER_ADMIN
View tenant settingsNoNoYesYesYes
Update tenant settingsNoNoYesYesYes
Manage integrationsNoNoYesYesYes
Create API keysNoNoYesYesYes
Revoke API keysNoNoYesYesYes
Invite usersNoNoYesYesYes
Manage user rolesNoNoNoYesYes
Suspend/reactivate tenantNoNoNoNoYes
Approve tenant registrationsNoNoNoNoYes

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

StatusDescription
PENDINGInvitation sent, awaiting acceptance
ACCEPTEDUser accepted and created their account
EXPIREDInvitation expired (7 days without acceptance)
REVOKEDInvitation 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:

  • OWNER is assigned automatically at registration (one per tenant)
  • ADMIN can be assigned to additional users by the OWNER
  • ADMIN can change user roles; OWNER can 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 OWNER in a tenant
  • SUPER_ADMIN can only be assigned by other SUPER_ADMIN users (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