Hopshift
Developer Docs

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

  1. You create an API key in Group Settings → API Keys as a Group Admin.
  2. Every API request must include the key as a Bearer token:
Authorization: Bearer hsk_live_xxxxxxxxxxxxxxxxxxxx
  1. 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 Unauthorized response 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

LimitValue
Requests per minute (per API key)200
Max page size100 records
Max response body10 MB

When you exceed the rate limit, the API returns:

HTTP/1.1 429 Too Many Requests
Retry-After: 15

The 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

FieldTypeNotes
idstringHopshift internal ID
firstNamestring
lastNamestring
emailstringUnique per employee
phonestring
dateOfBirthdateISO 8601
genderenumMALE, FEMALE, OTHER
nationalIdNumberstringThai national ID (13 digits), required for payroll compliance
employmentTypeenumFULL_TIME, PART_TIME, CONTRACT
startDatedateISO 8601
endDatedateISO 8601, null if still employed
statusenumACTIVE, INACTIVE, TERMINATED
companyIdstringParent company
departmentIdstring
positionIdstring
managerIdstringDirect manager employee ID
baseSalarynumberMonthly base salary (THB)

Company

FieldTypeNotes
idstring
namestring
slugstringURL-safe identifier
groupIdstringParent group
taxIdstringThai company tax ID
branchCodestringUsed in PND1 filing
countryenumTH, SG

Payroll Run

FieldTypeNotes
idstring
companyIdstring
periodstringYYYY-MM format
statusenumDRAFT, PROCESSING, FINALIZED, CANCELLED
totalGrossnumberSum of gross pay across all employees (THB)
totalNetPaynumberSum of net pay (THB)
totalTaxWithheldnumberTotal PND1 WHT (THB)
totalEmployeeSsonumberTotal employee SSO deductions (THB)
totalEmployerSsonumberTotal employer SSO contributions (THB)
finalizedAtdatetimeISO 8601, null if not yet finalised

Leave Request

FieldTypeNotes
idstring
employeeIdstring
leaveTypeIdstringReferences group leave type
startDatedateISO 8601
endDatedateISO 8601
daysRequestednumberWorking days calculated
statusenumPENDING, APPROVED, REJECTED, CANCELLED
reasonstringEmployee-provided reason
approvedByIdstringManager/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 ID
  • gender: required for SSO filing
  • dateOfBirth: 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.created
  • employee.updated
  • employee.terminated
  • payroll_run.finalized
  • leave_request.approved
  • leave_request.rejected
  • clock_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:

LayerTechnology
Web applicationNext.js 16 (App Router, React Server Components)
Mobile applicationReact Native / Expo
DatabasePostgreSQL via Supabase
ORMPrisma
AuthenticationSupabase Auth
File storageSupabase Storage
HostingVercel
EmailResend
Build systemTurborepo (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.

On this page