Permissions Guide
DeePsy uses a bitfield-based permission system that provides granular control over API access. Each user can have different permission levels for different companies, and API keys inherit these permissions with additional company-specific authorization.
Permission Levels
The DeePsy API uses six distinct permission levels, each with a specific bitfield value:
| Permission | Value | Description |
|---|---|---|
FOUNDER | 1 | Full access to everything, including company deletion and ownership transfer |
ADMINISTRATOR | 2 | Company administration rights, user management, and most operations |
MANAGE_CAMPAIGN | 4 | Campaign creation, management, and candidate operations |
FINANCE | 8 | Financial operations, billing, and subscription management |
REPORT | 16 | Report generation, data export, and analytics access |
EMAIL | 32 | Email management, sending notifications, and communication features |
Permission Hierarchy
Permissions are not hierarchical. Each permission grants access to specific functionality:
- FOUNDER has all permissions by default
- ADMINISTRATOR can manage users and company settings but needs additional permissions for campaigns, finance, reports, or emails
- Other permissions are specific to their functional areas
Bitfield Operations
Understanding Bitfield Values
Permissions are stored as integers using bitwise operations. Multiple permissions are combined using bitwise OR:
ADMINISTRATOR + MANAGE_CAMPAIGN = 2 + 4 = 6
ADMINISTRATOR + MANAGE_CAMPAIGN + REPORT = 2 + 4 + 16 = 22
Interactive Permissions Calculator
Use this interactive tool to calculate permission bitfield values. Click on the permission tags to toggle them on/off and see the resulting bitfield value.
Click on the permission tags above to toggle them on or off.
Note: FOUNDER (1) gives all permissions. ADMINISTRATOR (2) gives all permissions except FOUNDER.
Checking Permissions
Here's the actual permission checking code used in the DeePsy application:
- JavaScript
- TypeScript
// Permission constants from DeePsy codebase
export const permissions = {
1: 'FOUNDER',
2: 'ADMINISTRATOR',
4: 'MANAGE_CAMPAIGN',
8: 'FINANCE',
16: 'REPORT',
32: 'EMAIL',
};
// Calculate permissions from bitfield
export const calculatePermissions = (bitfield) => {
const userPermissions = [];
// FOUNDER has all permissions
if (bitfield & 1) return Object.values(permissions);
// ADMINISTRATOR has all permissions except FOUNDER
if (bitfield & 2) {
const adminPermissions = Object.values(permissions).filter(perm => perm !== 'FOUNDER');
return adminPermissions;
}
// Check each permission bit
for (const bit in permissions) {
if (bitfield & bit) {
userPermissions.push(permissions[bit]);
}
}
return userPermissions;
};
// Example usage:
const userBitfield = 6; // ADMINISTRATOR + MANAGE_CAMPAIGN
const userPermissions = calculatePermissions(userBitfield);
// Returns: ['ADMINISTRATOR', 'MANAGE_CAMPAIGN', 'FINANCE', 'REPORT', 'EMAIL']
// Check if user has specific permission
const hasManageCampaign = userPermissions.includes('MANAGE_CAMPAIGN'); // true
const hasFounder = userPermissions.includes('FOUNDER'); // false
// Permission types and constants from DeePsy codebase
type PermissionKey = 1 | 2 | 4 | 8 | 16 | 32;
type PermissionName = 'FOUNDER' | 'ADMINISTRATOR' | 'MANAGE_CAMPAIGN' | 'FINANCE' | 'REPORT' | 'EMAIL';
export const permissions: Record<PermissionKey, PermissionName> = {
1: 'FOUNDER',
2: 'ADMINISTRATOR',
4: 'MANAGE_CAMPAIGN',
8: 'FINANCE',
16: 'REPORT',
32: 'EMAIL',
};
// Calculate permissions from bitfield
export const calculatePermissions = (bitfield: number): PermissionName[] => {
const userPermissions: PermissionName[] = [];
// FOUNDER has all permissions
if (bitfield & 1) return Object.values(permissions);
// ADMINISTRATOR has all permissions except FOUNDER
if (bitfield & 2) {
const adminPermissions = Object.values(permissions).filter(perm => perm !== 'FOUNDER');
return adminPermissions;
}
// Check each permission bit
for (const bit in permissions) {
const numericBit = Number(bit) as PermissionKey;
if (bitfield & numericBit) {
userPermissions.push(permissions[numericBit]);
}
}
return userPermissions;
};
// Example usage:
const userBitfield = 6; // ADMINISTRATOR + MANAGE_CAMPAIGN
const userPermissions = calculatePermissions(userBitfield);
// Returns: ['ADMINISTRATOR', 'MANAGE_CAMPAIGN', 'FINANCE', 'REPORT', 'EMAIL']
// Check if user has specific permission
const hasManageCampaign: boolean = userPermissions.includes('MANAGE_CAMPAIGN'); // true
const hasFounder: boolean = userPermissions.includes('FOUNDER'); // false
React Permission Checking Hook
This is an actual example that's used in the DeePsy dashboard to mainly check if the user has the required permissions to access a specific route:
- JavaScript
- TypeScript
// Permission checking hook from DeePsy codebase
export const useCheckUserPermissions = (requiredPermissions) => {
const selectedCompany = useSelectedCompanyStore((state) => state.selectedCompany);
const companies = useUserStore((state) => state.companies);
return useMemo(() => {
if (!selectedCompany || !selectedCompany.company_id || !requiredPermissions || !requiredPermissions.length) {
return { hasPermissions: true, userPermissions: [] };
}
const userCompany = companies.find(company => company.company_id === selectedCompany.company_id);
if (!userCompany || !userCompany.permissions) {
return { hasPermissions: false, userPermissions: [] };
}
const userPermissions = calculatePermissions(userCompany.permissions);
const hasAllPermissions = requiredPermissions.every(permission =>
userPermissions.includes(permission)
);
return {
hasPermissions: hasAllPermissions,
userPermissions
};
}, [selectedCompany, companies, requiredPermissions]);
};
// Example usage in React component:
const MyComponent = () => {
const { hasPermissions, userPermissions } = useCheckUserPermissions(['MANAGE_CAMPAIGN', 'REPORT']);
if (!hasPermissions) {
return <div>You don't have permission to view this content</div>;
}
return <div>Campaign management interface</div>;
};
import { useMemo } from 'react';
import { PermissionName } from '../types/permissions';
interface Company {
company_id: string;
permissions: number;
// other company properties
}
interface SelectedCompany {
company_id: string;
// other selected company properties
}
// Permission checking hook from DeePsy codebase
export const useCheckUserPermissions = (requiredPermissions: PermissionName[]) => {
const selectedCompany = useSelectedCompanyStore((state) => state.selectedCompany as SelectedCompany);
const companies = useUserStore((state) => state.companies as Company[]);
return useMemo(() => {
if (!selectedCompany || !selectedCompany.company_id || !requiredPermissions || !requiredPermissions.length) {
return { hasPermissions: true, userPermissions: [] as PermissionName[] };
}
const userCompany = companies.find(company => company.company_id === selectedCompany.company_id);
if (!userCompany || !userCompany.permissions) {
return { hasPermissions: false, userPermissions: [] as PermissionName[] };
}
const userPermissions = calculatePermissions(userCompany.permissions);
const hasAllPermissions = requiredPermissions.every(permission =>
userPermissions.includes(permission)
);
return {
hasPermissions: hasAllPermissions,
userPermissions
};
}, [selectedCompany, companies, requiredPermissions]);
};
// Example usage in React component:
const MyComponent: React.FC = () => {
const { hasPermissions, userPermissions } = useCheckUserPermissions(['MANAGE_CAMPAIGN', 'REPORT']);
if (!hasPermissions) {
return <div>You don't have permission to view this content</div>;
}
return <div>Campaign management interface</div>;
};
Common Permission Combinations
| Value | Permissions |
|---|---|
| 1 | All permissions including FOUNDER |
| 2 | All permissions except FOUNDER |
| 60 | All permissions except FOUNDER and ADMINISTRATOR |
| 4 | MANAGE_CAMPAIGN |
| 8 | FINANCE |
| 16 | REPORT |
| 32 |
API Key Permissions
Two-Level Authorization
API keys require two levels of authorization:
- API Key Permissions: API keys have permissions independent from the user's permissions
- API Key Authorization: Company administrators must authorize your API key and grant specific permissions
API Key Creation Process
- Create API Key: Generate an API key in your developer settings
- Select Companies: Choose which companies the key should access
- Admin Authorization: Company administrators authorize the key and select permissions
- API Access: Use the authorized key to access company resources
Permission Inheritance
API keys do not automatically inherit all user permissions. Company administrators can grant a subset of permissions to API keys for security purposes.
Endpoint Permission Requirements
User Management
- GET /user/me: Any valid API key
- GET /user/companies: Any valid API key
Company Management
- GET /companies/{id}/get-details: Company membership (any permission)
- GET /companies/{id}/users: ADMINISTRATOR or FOUNDER
- POST /companies/{id}/invitations/create: ADMINISTRATOR or FOUNDER
Campaign Management
- GET /campaign/{id}/list: MANAGE_CAMPAIGN or higher
- POST /campaign/{id}/create: MANAGE_CAMPAIGN or higher
- PUT /campaign/{id}/{campaign_id}/update: MANAGE_CAMPAIGN or higher
Candidate Management
- GET /candidates/{id}/{campaign_id}/list: MANAGE_CAMPAIGN or REPORT
- POST /candidates/{id}/{campaign_id}/{candidate_id}/unlock-test: MANAGE_CAMPAIGN
- POST /candidates/{id}/{campaign_id}/{candidate_id}/followup-email: EMAIL
White Label Management
- GET /whitelabels/{id}/list: ADMINISTRATOR or FOUNDER
- POST /whitelabels/{id}/create: ADMINISTRATOR or FOUNDER
- PUT /whitelabels/{id}/{logo_id}/update: ADMINISTRATOR or FOUNDER
Reports and Analytics
- GET /candidates/{id}/{campaign_id}/{candidate_id}/get-attempt-details: REPORT
- POST /candidates/{id}/{campaign_id}/{candidate_id}/{attempt_ref}/generate-pdf: REPORT
Permission Checking in API Responses
User Profile Response
In /user/me, permissions are returned as bitfield integers:
{
"companies": [
{
"company_id": "c193a06f-1c25-4e65-84a7-95faaae7ae7b",
"permissions": 6, // ADMINISTRATOR + MANAGE_CAMPAIGN
"company": {
"name": "Acme Corporation"
}
}
]
}
Company List Response
In /user/companies, permissions are also returned as bitfield integers:
{
"items": [
{
"company_id": "c193a06f-1c25-4e65-84a7-95faaae7ae7b",
"permissions": 6, // ADMINISTRATOR + MANAGE_CAMPAIGN
"company": {
"name": "Acme Corporation"
}
}
]
}
Managing API Key Permissions
For API Key Creators
- Request Access: Create an API key and select companies
- Wait for Authorization: Company administrators must authorize your key
- Check Permissions: Use
/user/companiesto see granted permissions - Request Changes: Contact company administrators for permission updates
For Company Administrators
- Review Requests: Check pending API key authorization requests
- Grant Permissions: Select appropriate permissions based on user needs
- Monitor Usage: Regularly review API key permissions and usage
- Revoke Access: Remove authorization when no longer needed
Security Best Practices
Principle of Least Privilege
- Grant only the minimum permissions required for the intended use case
- Regularly review and audit API key permissions
- Remove unused or unnecessary permissions
Permission Separation
- Use different API keys for different purposes
- Separate development and production API keys
- Limit campaign-specific keys to relevant campaigns only
Regular Audits
- Review API key permissions quarterly
- Monitor API key usage and access patterns
- Remove inactive or unused API keys
Example Permission Scenarios
Campaign Manager Role
Permissions: MANAGE_CAMPAIGN + REPORT (Value: 20)
- Create and manage campaigns
- View candidate results and generate reports
- Cannot manage company users or finances
HR Administrator Role
Permissions: ADMINISTRATOR (Value: 2)
- Manage company users and invitations
- Create and manage recruitment campaigns
- Send follow-up emails to candidates
Finance Manager Role
Permissions: FINANCE + REPORT (Value: 24)
- Access billing and subscription information
- Generate financial reports
- Cannot manage campaigns or users
Administrator Permissions Management
Only users with the FOUNDER permission can modify the permissions of an ADMINISTRATOR. The FOUNDER permission is automatically assigned to the person who created the company and cannot be assigned by regular administrators.
If you need to assign a new FOUNDER for a company, at the moment it's not possible by yourself. In the meantime you can contact DeePsy's administrators through the contact form at https://deepsy.fr/contact.
Error Responses
Insufficient Permissions
{
"error": "You do not have the required permissions to access this resource",
"error_code": "INSUFFICIENT_PERMISSIONS"
}
No Company Access
{
"error": "User is not within this company",
"error_code": "USER_NOT_IN_COMPANY"
}
API Key Not Authorized
{
"error": "API key is not authorized for this company",
"error_code": "API_KEY_NOT_AUTHORIZED"
}
Related Guides
- Authentication Guide - Set up API keys and authorization
- Company Users Guide - Understand user profiles and company memberships
- Campaign Management Guide - Create and manage campaigns
- Error Handling Guide - Handle permission-related errors