Office hour series¶
This guide shows how to create an office hour series, give it managers, read its sessions and set its cancellation deadline.
An office hour series is a set of bookable sessions. Hosts run the sessions: one-on-one mentoring, open Q&A hours, design reviews. People book a session, not the series. Your organization can show the series under a different name. In the API, the resource is /programs/ and its content_type is program.
How the pieces fit¶
graph LR
S[Office hour series<br/>/programs/] -->|has many| SE[Sessions]
M[Managers] -->|edit| S
H[Host] -->|runs| SE
U[User] -->|books| SE
- The series holds the shared data: name, description, topics, the default attendance limit and the managers.
- A session is one time slot. It has its own start time, host, location and attendance limit.
- Managers can edit the series and its sessions. Admins and organizers can always edit them.
The API creates and edits the series. Hosts add sessions in PlusPlus. The API reads the sessions but does not create them.
Mentorship programs are a different resource. /programs/ does not return them.
1. Create a series¶
The Public API accepts only tokens that belong to an admin, so an admin token can create a series. A token that belongs to any other user gets 401 on every request.
curl -X POST https://acme.plusplus.app/api/v2/programs/ \
-H "Authorization: Bearer your_token_here" \
-H "Content-Type: application/json" \
-d '{
"name": "Architecture office hours",
"body_markdown": "Bring a design doc or a hard problem.",
"session_topics": "System design, code reviews, APIs",
"attendance_limit": 1,
"manager_ids": ["c8a7f1e2-4a3b-4e5f-8c9d-0123456789ab"]
}'
{
"public_id": "7d3f9a10-…",
"name": "Architecture office hours",
"content_type": "program",
"session_topics": "System design, code reviews, APIs",
"attendance_limit": 1,
"is_session_calendar_event_private": true,
"hide_attendees": false,
"managers": [
{ "public_id": "c8a7f1e2-…", "name": "Priya Patel", "email": "priya.patel@acme.com" }
],
"engaged_users_count": 0,
"bookable_sessions_count": 0,
"next_bookable_session_starts_at": null,
"is_hidden": false,
"facilitators": [
{ "user": { "public_id": "c8a7f1e2-…", "name": "Priya Patel", "email": "priya.patel@acme.com" }, "role": "program_manager" }
]
}
The response has more fields than this example. The API reference lists all of them.
| Field | What it does |
|---|---|
attendance_limit |
How many people can book each session. 1 is a one-on-one. 0 is unlimited. New sessions start with this value. |
is_session_calendar_event_private |
Makes the session calendar events private. Default: true. |
hide_attendees |
Hides who booked a session. Admins, organizers, managers and hosts still see the attendees. |
manager_ids |
The managers. If you leave it out, the token's user is the only manager. Send [] for no managers. null returns 400. |
2. Hosts add sessions¶
Hosts add sessions to the series in PlusPlus. Each session gets its own time, location and attendance limit. The series' attendance_limit is only the start value for a new session.
3. Read the sessions¶
curl "https://acme.plusplus.app/api/v2/programs/7d3f9a10-…/sessions/?starts_after=2026-11-02T00:00:00Z&is_available=true" \
-H "Authorization: Bearer your_token_here"
{
"data": [
{
"public_id": "0b6c2a4e-…",
"host": { "public_id": "4e1d…", "name": "Sam Rivera", "email": "sam.rivera@acme.com" },
"starts_at": "2026-11-03T10:00:00-08:00",
"ends_at": "2026-11-03T10:30:00-08:00",
"timezone": "US/Pacific",
"duration_minutes": 30,
"is_local": false,
"is_online": true,
"location": null,
"room": "",
"extra_info": "",
"online_extra_info": "Camera on, please.",
"attendance_limit": 1,
"enrollments_count": 0,
"is_available": true
}
],
"meta": { "page": 1, "page_size": 25, "total_count": 1 }
}
The list starts with the earliest session. It includes past sessions. Send starts_after to get only the upcoming ones.
timezone is the timezone of the session's location. A session without a location, like the online one above, uses the platform default US/Pacific, not your organization's timezone.
| Filter | Keeps |
|---|---|
starts_after, starts_before |
Sessions that start in that range. |
is_available |
true: sessions with a free spot. false: full sessions. |
host_id |
Sessions that this user hosts. |
The session does not show who booked it or its meeting link.
The series also shows a summary: bookable_sessions_count and next_bookable_session_starts_at. These count the upcoming sessions that have a free spot and are inside your organization's booking window.
4. Change the series or its managers¶
PATCH changes only the fields you send. Send If-Match with the ETag of your last read. If the series changed since then, you get 412.
curl -X PATCH https://acme.plusplus.app/api/v2/programs/7d3f9a10-…/ \
-H "Authorization: Bearer your_token_here" \
-H "If-Match: \"a1b2c3…\"" \
-H "Content-Type: application/json" \
-d '{
"attendance_limit": 3,
"manager_ids": ["c8a7f1e2-…", "9f8e7d6c-…"]
}'
manager_ids replaces all managers. Send the full list each time. Facilitators in other roles, for example maintainers, stay on the series. A change to attendance_limit does not change the sessions that exist.
5. Set the cancellation deadline¶
The series has cascaded settings at /programs/{public_id}/settings/. booking_cancellation_closes_offset is the latest time attendees should cancel a booking, relative to the session start.
curl -X PATCH https://acme.plusplus.app/api/v2/programs/7d3f9a10-…/settings/ \
-H "Authorization: Bearer your_token_here" \
-H "Content-Type: application/json" \
-d '{ "booking_cancellation_closes_offset": { "value": "-P1D" } }'
-P1D is one day before the session. null is no deadline. The deadline is informational: booking emails and calendar invites show it. PlusPlus does not stop a later cancellation.
You can also send settings when you create the series. PATCH /programs/{public_id}/ does not accept settings.
6. Archive, clone or delete¶
| To | Send |
|---|---|
| Archive or unarchive | POST /content-items/{public_id}/archive/ or /unarchive/ |
| Copy the series | POST /content-items/{public_id}/clone/. The copy has no sessions. |
| Delete | DELETE /programs/{public_id}/. This also deletes the sessions. |
A delete returns 409 when a track uses the series.
Common pitfalls¶
manager_idsreplaces the managers. It does not add to them. If a manager removes themselves, they can no longer edit the series, unless they are an admin, an organizer, the channel's owner or a facilitator of the series in another role.- You cannot create sessions with the API. Hosts add them in PlusPlus.
- A new series has no bookable sessions.
bookable_sessions_countis0until hosts add sessions. - The session list includes past sessions. Send
starts_afterwith the current time to get only upcoming sessions. engaged_users_countis not live. PlusPlus recomputes it on a schedule.- Mentorship programs are not office hour series.
/programs/{public_id}/returns404for them.
See Errors for the error format and Core concepts for how content items relate.