Staff
Marcus works Tuesday to Saturday, takes lunch at one, and is off the last week of August. All of which booking needs to know.
Marcus cleans for Brightside. He works Tuesday to Saturday, 8am to 4pm, takes lunch at one, can manage four jobs a day, and he's off the last week of August.
Every one of those facts changes what you can safely book. Availability lives here, and the Bookings module checks against it the day it goes live — model the team properly now and scheduling inherits it for free.
Read it instead
Staff is the four things that decide whether someone can take a job: working hours, breaks, capacity, and time off. REST, a secret key, a location header.
Working hours carry a day_of_week, a start_time and an end_time, with effective_from and effective_until so a rota change has a date. Breaks sit inside them, capacity caps the jobs per day, and time off runs pending, approved or rejected.
Ask for everyone at once and a rota screen is one request. Subscribe to employees.time_off.requested to push approvals into whatever your managers already use, and employees.employee.deactivated to close accounts elsewhere the moment somebody leaves.
employees.view reads staff, hours, breaks, capacity and time off. Approving somebody's holiday needs employees.update, so a scheduling integration can read availability without granting it.
Staff: hours, breaks, capacity and time off on one record, which is everything booking needs to know. The guide is below.
Before you start
- The module switched on for the site. If it isn't, everything below returns
403regardless of your key — check the site's modules on the Locations page first. - A credential with the right scopes —
employees.viewto read,employees.createto add people. - The site's id, for
X-Location-Idon every request.
These are people inside a site, not your dashboard staff
A cleaner here is a record in Portland's database. The people who run your business through the dashboard — opening sites, issuing keys — are a different thing entirely, set up in the dashboard: see Staff and roles.
The four things that decide availability
Getting these straight saves a lot of confusion later, because they stack:
| What it says | Example | |
|---|---|---|
| Working hours | The pattern of a normal week | Tue–Sat, 08:00–16:00 |
| Break periods | Time out within a working day | Lunch, 13:00–13:30 |
| Capacity settings | How much someone can take on | Four jobs a day |
| Time off | Specific dates they're away | 24–31 August |
Working hours say when someone could work. Breaks and time off carve out of that. Capacity limits how much fits in what's left.
The endpoints
| For | Endpoint |
|---|---|
| List staff | GET /api/modules/employees/users |
| Add someone | POST /api/modules/employees/users |
| Get one | GET /api/modules/employees/users/{user} |
| Change one | PATCH /api/modules/employees/users/{user} |
| Switch someone off | POST /api/modules/employees/users/{user}/deactivate |
| Bring them back | POST /api/modules/employees/users/{user}/reactivate |
| Everyone's availability | GET /api/modules/employees/staff-availability |
| Working hours | GET /api/modules/employees/users/{user}/working-hours |
| Breaks | GET /api/modules/employees/users/{user}/break-periods |
| Capacity | GET /api/modules/employees/users/{user}/capacity-settings |
| Time off | GET /api/modules/employees/users/{user}/time-off |
| Approve time off | POST /api/modules/employees/users/{user}/time-off/{timeOff}/approve |
| Reject time off | POST /api/modules/employees/users/{user}/time-off/{timeOff}/reject |
| Invite someone | POST /api/modules/employees/invitations |
| Roles within the site | GET /api/modules/employees/user-roles |
Working hours
One record per day of the week. day_of_week is an integer, and is_available: false is how
you say "not this day" rather than omitting the record.
Prop
Type
Check which integer means which day
Whether the week starts at 0 or 1, and whether that's Sunday or Monday, is the sort of thing that silently books someone on their day off. Create one record you can verify against a real calendar before generating a whole team's hours from a loop.
curl -X POST "https://api.hyphabase.com/api/modules/employees/users/$MARCUS_ID/working-hours" \
-u sk_live_xxx: -H "X-Location-Id: $HYPHABASE_LOCATION_ID" \
-H "Content-Type: application/json" \
-d '{
"day_of_week": 2,
"start_time": "08:00",
"end_time": "16:00",
"is_available": true
}'effective_from and effective_until are the useful part. They let you change someone's
hours from a future date without destroying the record of what they used to be — so a
historic booking still makes sense against the pattern that applied at the time. Editing in
place loses that.
Breaks
Same idea, narrower. day_of_week, a start and end, and an optional label so a rota
screen can say "Lunch" rather than a bare time range.
curl -X POST "https://api.hyphabase.com/api/modules/employees/users/$MARCUS_ID/break-periods" \
-u sk_live_xxx: -H "X-Location-Id: $HYPHABASE_LOCATION_ID" \
-H "Content-Type: application/json" \
-d '{"day_of_week": 2, "break_start_time": "13:00", "break_end_time": "13:30", "label": "Lunch"}'Capacity
max_daily_capacity_units is how much someone can take on in a day. What a "unit" means is
yours to define — jobs, hours, rooms — but define it once and use it consistently, because
nothing enforces a meaning.
Sarah counts jobs, so Marcus is 4. A four-hour deep clean and a one-hour top-up both count
as one, which suits her because travel dominates her day anyway. If that stopped being true
she'd switch to hours and update everyone.
Like working hours, capacity settings carry effective_from/effective_until, so a seasonal
change is a new record rather than an edit.
Time off
Prop
Type
Requests arrive pending and become real on approve:
curl -X POST "https://api.hyphabase.com/api/modules/employees/users/$MARCUS_ID/time-off/$REQUEST_ID/approve" \
-u sk_live_xxx: -H "X-Location-Id: $HYPHABASE_LOCATION_ID"Omit the times for a full day, or include them for an afternoon at the dentist.
Approving time off does not cancel existing bookings
If Marcus is already booked in the week he's now off, those visits stand. Check for conflicts when you approve and reassign or reschedule them — nothing does it for you, and a crew not turning up is worse than an awkward phone call.
Everyone at once
GET /api/modules/employees/staff-availability is the whole team's availability in one request. That's what you build a rota screen from, rather than fetching four sub-resources per person.
One person's actual day — hours, breaks, time off and what's booked against them — arrives with the Bookings module, which reads the availability you set up here.
Adding people
Two ways, and they're for different situations.
Create the record directly with POST /api/modules/employees/users when you're importing or the person doesn't need to sign in.
Send an invitation with POST /api/modules/employees/invitations when they do — they set their own password rather than you inventing one and sending it over WhatsApp. Invitations can be resent and cancelled.
Prefer deactivate over delete when someone leaves. Their history stays intact, and reactivate handles the seasonal cleaner who comes back every summer.
What you get told about
| Event | When |
|---|---|
employees.employee.created | Someone is added |
employees.employee.deactivated | Someone is switched off |
employees.time_off.requested | Time off is requested |
time_off.requested is the one to wire up — it's how a manager finds out there's something
to approve without checking a screen.
What to grant
| Scope | Lets you |
|---|---|
employees.view | Read staff, hours, breaks, capacity and time off |
employees.create | Add people, invite them, request time off |
employees.update | Change records, approve and reject time off |
employees.delete | Delete records |
employees.view is safe for a publishable key — enough for a booking page to know who's
free, without exposing anything a customer shouldn't see.
Be careful with employees.update: it approves time off, which changes who can be booked.
What goes wrong
Recipes
Set up a new starter. Create or invite the user, add a working-hours record per working
day, add breaks, set capacity, then confirm with staff-availability that they show as
available when you expect.
Time off that actually works. On employees.time_off.requested, notify a manager. On
approval, list visits in that range and either reassign or reschedule each one — then tell
the customer.
A seasonal hours change. Don't edit. Add new working-hours records with effective_from
set to the changeover date, so past bookings still make sense.