Architecture
Multi-tenant data model, authentication, and integration architecture for Hopshift
This page describes the data model and architectural concepts you need to understand when integrating with Hopshift via the API. It covers the multi-tenant hierarchy, how authentication maps to data access, rate limiting, and which fields are available on each resource.
Multi-Tenant Data Model
Hopshift uses a three-level hierarchy to represent the structure of an organisation:
Group
└── Company (one or many per Group)
└── Employee (one or many per Company)Group
A Group is the top-level entity. It represents a business or brand owner: for example, a restaurant group that operates several brands. Groups contain:
- One or more Companies
- Group-level leave type definitions and entitlement policies
- Group-level public holiday calendars
- Group Admin user accounts
- API keys
Company
A Company is an operating entity within a group: a legal entity, brand, or outlet. Each company has:
- Its own set of employees
- Its own payroll runs
- Its own managers and company admin users
- Leave policy assignments (inheriting from group-level types)
Employee
An Employee belongs to exactly one Company. The employee record holds:
- Personal details (name, date of birth, national ID, gender, contact info)
- Employment details (position, department, start date, employment type)
- Payroll configuration (base salary, bank account, tax settings)
- Leave allocations and balances
- Clock-in/attendance records
API Key Authentication
API keys in Hopshift are group-scoped. A single key grants read/write access to all companies and employees within the group it belongs to.
API Key → Group → [Company A, Company B, Company C, ...]How it works
- You create an API key in Group Settings → API Keys as a Group Admin.
- Every API request must include the key as a Bearer token:
Authorization: Bearer hsk_live_xxxxxxxxxxxxxxxxxxxx- The API resolves your key to its group, then applies that group as the tenant context for all data access. You will never accidentally read or write data from another group.
Key management
- Keys are shown in full only once at creation time. Store them securely (e.g., in a secrets manager, not in source code).
- Keys can be revoked instantly from the Group Settings UI. Revoked keys receive a
401 Unauthorizedresponse immediately. - Multiple keys per group are supported: use separate keys for different integrations (e.g., one for your payroll exporter, one for your analytics dashboard) so each can be revoked independently.
Rate Limiting
| Limit | Value |
|---|---|
| Requests per minute (per API key) | 200 |
| Max page size | 100 records |
| Max response body | 10 MB |
When you exceed the rate limit, the API returns:
HTTP/1.1 429 Too Many Requests
Retry-After: 15The Retry-After value is in seconds. Implement exponential backoff in your integration to handle transient rate limit responses gracefully.
Data Model Overview
Below is a summary of the resources available through the API and their key fields.
Employee
| Field | Type | Notes |
|---|---|---|
id | string | Hopshift internal ID |
firstName | string | |
lastName | string | |
email | string | Unique per employee |
phone | string | |
dateOfBirth | date | ISO 8601 |
gender | enum | MALE, FEMALE, OTHER |
nationalIdNumber | string | Thai national ID (13 digits), required for payroll compliance |
employmentType | enum | FULL_TIME, PART_TIME, CONTRACT |
startDate | date | ISO 8601 |
endDate | date | ISO 8601, null if still employed |
status | enum | ACTIVE, INACTIVE, TERMINATED |
companyId | string | Parent company |
departmentId | string | |
positionId | string | |
managerId | string | Direct manager employee ID |
baseSalary | number | Monthly base salary (THB) |
Company
| Field | Type | Notes |
|---|---|---|
id | string | |
name | string | |
slug | string | URL-safe identifier |
groupId | string | Parent group |
taxId | string | Thai company tax ID |
branchCode | string | Used in PND1 filing |
country | enum | TH, SG |
Payroll Run
| Field | Type | Notes |
|---|---|---|
id | string | |
companyId | string | |
period | string | YYYY-MM format |
status | enum | DRAFT, PROCESSING, FINALIZED, CANCELLED |
totalGross | number | Sum of gross pay across all employees (THB) |
totalNetPay | number | Sum of net pay (THB) |
totalTaxWithheld | number | Total PND1 WHT (THB) |
totalEmployeeSso | number | Total employee SSO deductions (THB) |
totalEmployerSso | number | Total employer SSO contributions (THB) |
finalizedAt | datetime | ISO 8601, null if not yet finalised |
Leave Request
| Field | Type | Notes |
|---|---|---|
id | string | |
employeeId | string | |
leaveTypeId | string | References group leave type |
startDate | date | ISO 8601 |
endDate | date | ISO 8601 |
daysRequested | number | Working days calculated |
status | enum | PENDING, APPROVED, REJECTED, CANCELLED |
reason | string | Employee-provided reason |
approvedById | string | Manager/admin who approved |
Thailand Compliance Fields
For payroll compliance, the following employee fields are mandatory. Employees missing any of these fields are excluded from PND1 and SSO documents, and payroll finalisation is blocked until all employees in the run have them set:
nationalIdNumber: 13-digit Thai national IDgender: required for SSO filingdateOfBirth: required for SSO filing
These fields are also validated in the payroll wizard preview, which shows a missing_compliance warning for any affected employees before you attempt to finalise.
Webhooks (Coming Soon)
Webhooks will allow Hopshift to push real-time event notifications to your systems: eliminating the need to poll the API. Planned events include:
employee.createdemployee.updatedemployee.terminatedpayroll_run.finalizedleave_request.approvedleave_request.rejectedclock_event.recorded
Webhooks will be configurable per group with per-event subscriptions and HMAC-SHA256 request signing. Subscribe to updates or contact support to join the beta.
Internal Architecture (For Self-Hosters)
If you are running your own instance of Hopshift, the system is built on:
| Layer | Technology |
|---|---|
| Web application | Next.js 16 (App Router, React Server Components) |
| Mobile application | React Native / Expo |
| Database | PostgreSQL via Supabase |
| ORM | Prisma |
| Authentication | Supabase Auth |
| File storage | Supabase Storage |
| Hosting | Vercel |
| Resend | |
| Build system | Turborepo (monorepo) |
Row-Level Security (RLS) in Supabase enforces tenant isolation at the database layer: no application-level tenant filtering is relied on exclusively. See Deployment for self-hosting configuration.