Group classes API
Every Group classes action (12) and data model (4): endpoints, scopes, input, preconditions, events and examples.
A weekly class timetable with places, instructors, bookings and attendance.
Module code group_classes · 12 actions · 4 data models · 11 events. A key or token never does more here than the person behind it can; row-level security applies exactly as in the app. Scopes: group_classes (everything), group_classes:read (read only) or group_classes:<capability>.
Resources
| Resource | Table | List and read | POST | PATCH | DELETE |
|---|---|---|---|---|---|
group_class_joinings | group_class_joining | /api/v1/group_class_joinings | |||
group_class_schedules | group_class_schedule | /api/v1/group_class_schedules | |||
group_class_services | group_class_service | /api/v1/group_class_services | |||
group_classes | group_class | /api/v1/group_classes |
Lists take limit (up to 200), cursor, order (e.g. -created_at), fields and q; every other query parameter is a column filter: ?status=paid, ?total[gte]=100, ?id[in]=a,b, ?x=null.
Actions
| Action | Needs | What it does |
|---|---|---|
group_classes.add_schedule | group_classes:manage | Add a weekly time |
group_classes.archive_class | group_classes:manage | Retire a class |
group_classes.cancel_joining | group_classes:write | Cancel a class booking |
group_classes.cancel_session | group_classes:manage | Cancel one session |
group_classes.create_class | group_classes:manage | Create a class |
group_classes.end_schedule | group_classes:manage | End a series |
group_classes.join | group_classes:write | Book a place |
group_classes.join_online | group_classes:write | Book a class place online |
group_classes.mark_attendance | group_classes:write | Record attendance |
group_classes.set_services | group_classes:manage | Change the services |
group_classes.update_class | group_classes:manage | Edit a class |
group_classes.update_schedule | group_classes:manage | Edit a weekly time |
group_classes.add_schedule
Add a weekly time — Starts a new series: the class runs every week at this day and time.
Needs group_classes:manage · changes data
https://app.getera.io/api/v1/group_class_schedules/actions/add_schedule- Canonical address:
POST /api/v1/actions/group_classes.add_schedule
Input
| Field | Type | Required | Notes |
|---|---|---|---|
groupClassId | uuid | yes | Class · id of group_class |
weekday | number | yes | Day · min 0 · max 6 |
startTime | string | yes | Starts · max 8 |
duration | number | yes | Length (minutes) · min 1 · max 1440 |
instructorUserId | uuid | Instructor | |
startsOn | date | First session from |
Preconditions
The action is refused with 409 and one of these codes:
| Code | Refused when |
|---|---|
not_found | The class must exist. |
class_archived | A retired class cannot be scheduled. |
no_schedule | Day, time and length must be well-formed. |
schedule_exists | The class must not already run at that day and time. |
service_not_offered_that_day | The class’s services must be offered that day. |
provider_cannot_perform | The instructor must deliver every service in the class. |
Events it publishes: group_classes.series_created
What it writes: group_class_schedule (insert) — Writes the series
curl -X POST https://app.getera.io/api/v1/group_class_schedules/actions/add_schedule \
-H "Authorization: Bearer $ERA_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{"groupClassId":"GROUP_CLASS_ID","weekday":1,"startTime":"Starts","duration":1}'{
"ok": true,
"result": "…",
"events": [
"group_classes.series_created"
]
}import { createEra } from "@getera/sdk"
const era = createEra({ apiKey: process.env.ERA_API_KEY })
const res = await era.groupClassSchedules.addSchedule({
groupClassId: "GROUP_CLASS_ID",
weekday: 1,
startTime: "Starts",
duration: 1
})era group_class_schedules add_schedule \
--group-class-id "GROUP_CLASS_ID" \
--weekday 1 \
--start-time "Starts" \
--duration 1{
"name": "era__group_classes__add_schedule",
"arguments": {
"groupClassId": "GROUP_CLASS_ID",
"weekday": 1,
"startTime": "Starts",
"duration": 1
}
}Errors: 401 no or expired credential · 403 the credential does not hold group_classes:manage · 404 the record or module is outside what it may reach · 422 invalid input (problems[]) · 409 not_found, class_archived, no_schedule, schedule_exists, service_not_offered_that_day, provider_cannot_perform · 429 slow down
group_classes.archive_class
Retire a class — Stops taking bookings. The history stays.
Needs group_classes:manage · reaches outside (sends, publishes or charges) · asks a person to confirm when Era runs it
https://app.getera.io/api/v1/group_classes/{id}/actions/archive_class- Canonical address:
POST /api/v1/actions/group_classes.archive_class
Input
| Field | Type | Required | Notes |
|---|---|---|---|
id | uuid | yes | Filled from the path {id} · Class · id of group_class |
Preconditions
The action is refused with 409 and one of these codes:
| Code | Refused when |
|---|---|
not_found | The class must exist. |
class_archived | It must not already be retired. |
has_upcoming_joinings | Nobody may be booked on a coming session. |
no_workspace | The workspace must be readable, for its clock. |
Events it publishes: group_classes.class_archived
What it writes: group_class (update) — Stamps archived_at; group_class_schedule (update) — Ends every running series today
curl -X POST https://app.getera.io/api/v1/group_classes/GROUP_CLASSE_ID/actions/archive_class \
-H "Authorization: Bearer $ERA_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{}'{
"ok": true,
"result": "…",
"events": [
"group_classes.class_archived"
]
}import { createEra } from "@getera/sdk"
const era = createEra({ apiKey: process.env.ERA_API_KEY })
const res = await era.groupClasses.archiveClass("GROUP_CLASSE_ID")era group_classes archive_class GROUP_CLASSE_ID{
"name": "era__group_classes__archive_class",
"arguments": {
"id": "GROUP_CLASSE_ID"
}
}Errors: 401 no or expired credential · 403 the credential does not hold group_classes:manage · 404 the record or module is outside what it may reach · 422 invalid input (problems[]) · 409 not_found, class_archived, has_upcoming_joinings, no_workspace · 429 slow down
group_classes.cancel_joining
Cancel a class booking — Frees the place. A reason is required, as in the source.
Needs group_classes:write · removes or cannot be undone · asks a person to confirm when Era runs it
https://app.getera.io/api/v1/group_class_joinings/{id}/actions/cancel_joining- Canonical address:
POST /api/v1/actions/group_classes.cancel_joining
Input
| Field | Type | Required | Notes |
|---|---|---|---|
joiningId | uuid | yes | Filled from the path {id} · Booking · id of group_class_joining |
reason | string | yes | Reason · max 64 |
Preconditions
The action is refused with 409 and one of these codes:
| Code | Refused when |
|---|---|
joining_not_found | The booking must exist. |
already_cancelled | It must not already be cancelled. |
already_finished | Attendance must not already be recorded. |
unknown_reason | The reason must be one the workspace uses. |
Events it publishes: group_classes.joining_cancelled
What it writes: group_class_joining (update) — Marks it cancelled and records why
curl -X POST https://app.getera.io/api/v1/group_class_joinings/GROUP_CLASS_JOINING_ID/actions/cancel_joining \
-H "Authorization: Bearer $ERA_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{"reason":"Reason"}'{
"ok": true,
"result": "…",
"events": [
"group_classes.joining_cancelled"
]
}import { createEra } from "@getera/sdk"
const era = createEra({ apiKey: process.env.ERA_API_KEY })
const res = await era.groupClassJoinings.cancelJoining("GROUP_CLASS_JOINING_ID", {
reason: "Reason"
})era group_class_joinings cancel_joining GROUP_CLASS_JOINING_ID \
--reason "Reason"{
"name": "era__group_classes__cancel_joining",
"arguments": {
"joiningId": "GROUP_CLASS_JOINING_ID",
"reason": "Reason"
}
}Errors: 401 no or expired credential · 403 the credential does not hold group_classes:write · 404 the record or module is outside what it may reach · 422 invalid input (problems[]) · 409 joining_not_found, already_cancelled, already_finished, unknown_reason · 429 slow down
group_classes.cancel_session
Cancel one session — Takes one date off the series and cancels everyone booked on it.
Needs group_classes:manage · removes or cannot be undone · asks a person to confirm when Era runs it
https://app.getera.io/api/v1/group_class_joinings/actions/cancel_session- Canonical address:
POST /api/v1/actions/group_classes.cancel_session
Input
| Field | Type | Required | Notes |
|---|---|---|---|
scheduleId | uuid | yes | Series · id of group_class_schedule |
sessionDate | date | yes | Date |
reason | string | yes | Reason · max 64 |
Preconditions
The action is refused with 409 and one of these codes:
| Code | Refused when |
|---|---|
schedule_not_found | The series must exist. |
not_found | Its class must exist. |
unknown_reason | The reason must be one the workspace uses. |
no_such_session | The class must run on that date. |
session_cancelled | It must not already be cancelled. |
session_in_past | It must not have started. |
no_workspace | The workspace must be readable, for its clock. |
Events it publishes: group_classes.session_cancelled, group_classes.joining_cancelled
What it writes: group_class_session_cancellation (insert) — Records the cancelled date; group_class_joining (update) — Cancels everyone booked on it
curl -X POST https://app.getera.io/api/v1/group_class_joinings/actions/cancel_session \
-H "Authorization: Bearer $ERA_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{"scheduleId":"GROUP_CLASS_SCHEDULE_ID","sessionDate":"2026-11-02","reason":"Reason"}'{
"ok": true,
"result": "…",
"events": [
"group_classes.session_cancelled",
"group_classes.joining_cancelled"
]
}import { createEra } from "@getera/sdk"
const era = createEra({ apiKey: process.env.ERA_API_KEY })
const res = await era.groupClassJoinings.cancelSession({
scheduleId: "GROUP_CLASS_SCHEDULE_ID",
sessionDate: "2026-11-02",
reason: "Reason"
})era group_class_joinings cancel_session \
--schedule-id "GROUP_CLASS_SCHEDULE_ID" \
--session-date "2026-11-02" \
--reason "Reason"{
"name": "era__group_classes__cancel_session",
"arguments": {
"scheduleId": "GROUP_CLASS_SCHEDULE_ID",
"sessionDate": "2026-11-02",
"reason": "Reason"
}
}Errors: 401 no or expired credential · 403 the credential does not hold group_classes:manage · 404 the record or module is outside what it may reach · 422 invalid input (problems[]) · 409 schedule_not_found, not_found, unknown_reason, no_such_session, session_cancelled, session_in_past, no_workspace · 429 slow down
group_classes.create_class
Create a class — A class with its services, its capacity and its weekly times, in one go.
Needs group_classes:manage · changes data
https://app.getera.io/api/v1/group_classes/actions/create_class- Canonical address:
POST /api/v1/actions/group_classes.create_class
Input
| Field | Type | Required | Notes |
|---|---|---|---|
name | string | yes | Name · max 255 |
capacity | number | yes | Places · min 1 · max 10000 |
instructorUserId | uuid | Instructor | |
itemVariantIds | object / array | yes | Services · [itemVariantId, …] |
schedules | object / array | yes | Weekly times · [{ weekday: 0–6 (0 = Sunday), startTime: "HH:MM", duration: minutes, instructorUserId? }] |
Preconditions
The action is refused with 409 and one of these codes:
| Code | Refused when |
|---|---|
no_services | At least one service must be chosen. |
no_schedule | At least one well-formed weekly time must be given. |
service_not_found | Every service must exist. |
not_a_class_service | Only services set up as group classes may be used. |
service_not_offered_that_day | Every weekly time must fall on a day its services are offered. |
provider_cannot_perform | An instructor must deliver every service in the class. |
schedule_exists | The same day and time cannot be listed twice. |
Events it publishes: group_classes.class_created
What it writes: group_class (insert) — Creates the class; group_class_service (insert) — Links its services; group_class_schedule (insert) — Writes its weekly series
curl -X POST https://app.getera.io/api/v1/group_classes/actions/create_class \
-H "Authorization: Bearer $ERA_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{"name":"Name","capacity":1,"itemVariantIds":{},"schedules":{}}'{
"ok": true,
"result": "…",
"events": [
"group_classes.class_created"
]
}import { createEra } from "@getera/sdk"
const era = createEra({ apiKey: process.env.ERA_API_KEY })
const res = await era.groupClasses.createClass({
name: "Name",
capacity: 1,
itemVariantIds: {},
schedules: {}
})era group_classes create_class --data '{"name":"Name","capacity":1,"itemVariantIds":{},"schedules":{}}'{
"name": "era__group_classes__create_class",
"arguments": {
"name": "Name",
"capacity": 1,
"itemVariantIds": {},
"schedules": {}
}
}Errors: 401 no or expired credential · 403 the credential does not hold group_classes:manage · 404 the record or module is outside what it may reach · 422 invalid input (problems[]) · 409 no_services, no_schedule, service_not_found, not_a_class_service, service_not_offered_that_day, provider_cannot_perform, schedule_exists · 429 slow down
group_classes.end_schedule
End a series — The class stops running at this time after a date; later bookings are cancelled.
Needs group_classes:manage · reaches outside (sends, publishes or charges) · asks a person to confirm when Era runs it
https://app.getera.io/api/v1/group_class_schedules/{id}/actions/end_schedule- Canonical address:
POST /api/v1/actions/group_classes.end_schedule
Input
| Field | Type | Required | Notes |
|---|---|---|---|
scheduleId | uuid | yes | Filled from the path {id} · Series · id of group_class_schedule |
endsOn | date | yes | Last session on |
reason | string | yes | Reason · max 64 |
Preconditions
The action is refused with 409 and one of these codes:
| Code | Refused when |
|---|---|
schedule_not_found | The series must exist. |
schedule_ended | It must still be running. |
not_found | Its class must exist. |
unknown_reason | The reason must be one the workspace uses. |
ends_in_past | A series ends today or later, never in the past. |
no_workspace | The workspace must be readable, for its clock. |
Events it publishes: group_classes.series_ended, group_classes.joining_cancelled
What it writes: group_class_schedule (update) — Stamps ends_on; group_class_joining (update) — Cancels bookings after the last session
curl -X POST https://app.getera.io/api/v1/group_class_schedules/GROUP_CLASS_SCHEDULE_ID/actions/end_schedule \
-H "Authorization: Bearer $ERA_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{"endsOn":"2026-11-02","reason":"Reason"}'{
"ok": true,
"result": "…",
"events": [
"group_classes.series_ended",
"group_classes.joining_cancelled"
]
}import { createEra } from "@getera/sdk"
const era = createEra({ apiKey: process.env.ERA_API_KEY })
const res = await era.groupClassSchedules.endSchedule("GROUP_CLASS_SCHEDULE_ID", {
endsOn: "2026-11-02",
reason: "Reason"
})era group_class_schedules end_schedule GROUP_CLASS_SCHEDULE_ID \
--ends-on "2026-11-02" \
--reason "Reason"{
"name": "era__group_classes__end_schedule",
"arguments": {
"scheduleId": "GROUP_CLASS_SCHEDULE_ID",
"endsOn": "2026-11-02",
"reason": "Reason"
}
}Errors: 401 no or expired credential · 403 the credential does not hold group_classes:manage · 404 the record or module is outside what it may reach · 422 invalid input (problems[]) · 409 schedule_not_found, schedule_ended, not_found, unknown_reason, ends_in_past, no_workspace · 429 slow down
group_classes.join
Book a place — Puts a customer on one session of a class, while it has room.
Needs group_classes:write · changes data
https://app.getera.io/api/v1/group_class_joinings/actions/join- Canonical address:
POST /api/v1/actions/group_classes.join
Input
| Field | Type | Required | Notes |
|---|---|---|---|
scheduleId | uuid | yes | Series · id of group_class_schedule |
sessionDate | date | yes | Date |
customerId | uuid | yes | Customer · id of customer |
Preconditions
The action is refused with 409 and one of these codes:
| Code | Refused when |
|---|---|
schedule_not_found | The series must exist. |
not_found | Its class must exist. |
class_archived | A retired class takes no bookings. |
no_such_session | The class must run on that date. |
session_cancelled | The session must not be cancelled. |
inside_cutoff | The session must not have started (or be inside the cutoff). |
outside_window | The session must be inside the booking window. |
class_full | The session must have a free place. |
customer_not_found | The customer must exist in this workspace. |
customer_banned | The customer must not be banned. |
already_joined | The same person cannot be booked twice on one session. |
no_workspace | The workspace must be readable, for its clock. |
Events it publishes: group_classes.joined
What it writes: group_class_joining (insert) — Books the place, with its price frozen
curl -X POST https://app.getera.io/api/v1/group_class_joinings/actions/join \
-H "Authorization: Bearer $ERA_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{"scheduleId":"GROUP_CLASS_SCHEDULE_ID","sessionDate":"2026-11-02","customerId":"CUSTOMER_ID"}'{
"ok": true,
"result": "…",
"events": [
"group_classes.joined"
]
}import { createEra } from "@getera/sdk"
const era = createEra({ apiKey: process.env.ERA_API_KEY })
const res = await era.groupClassJoinings.join({
scheduleId: "GROUP_CLASS_SCHEDULE_ID",
sessionDate: "2026-11-02",
customerId: "CUSTOMER_ID"
})era group_class_joinings join \
--schedule-id "GROUP_CLASS_SCHEDULE_ID" \
--session-date "2026-11-02" \
--customer-id "CUSTOMER_ID"{
"name": "era__group_classes__join",
"arguments": {
"scheduleId": "GROUP_CLASS_SCHEDULE_ID",
"sessionDate": "2026-11-02",
"customerId": "CUSTOMER_ID"
}
}Errors: 401 no or expired credential · 403 the credential does not hold group_classes:write · 404 the record or module is outside what it may reach · 422 invalid input (problems[]) · 409 schedule_not_found, not_found, class_archived, no_such_session, session_cancelled, inside_cutoff, outside_window, class_full, customer_not_found, customer_banned, already_joined, no_workspace · 429 slow down
group_classes.join_online
Book a class place online — A visitor takes one place on a class session from the site timetable, while it has room.
Needs group_classes:write · changes data · Also callable from a published site (visitor)
/api/site/v1/{siteId}, e.g. with @getera/storefront). With an API key or a token it is refused (403 site_only).https://app.getera.io/api/v1/group_class_joinings/actions/join_online- Canonical address:
POST /api/v1/actions/group_classes.join_online
Input
| Field | Type | Required | Notes |
|---|---|---|---|
scheduleId | uuid | yes | Series · id of group_class_schedule |
sessionDate | date | yes | Date |
Preconditions
The action is refused with 409 and one of these codes:
| Code | Refused when |
|---|---|
guest_details_required | A guest leaves their details before booking. |
class_full | The session must have a free place. |
Events it publishes: group_classes.joined
What it writes: group_class_joining (insert) — Books the place, with its price frozen
Errors: 401 no or expired credential · 403 the credential does not hold group_classes:write · 404 the record or module is outside what it may reach · 422 invalid input (problems[]) · 409 guest_details_required, class_full · 429 slow down
group_classes.mark_attendance
Record attendance — Came, or did not come.
Needs group_classes:write · changes data
https://app.getera.io/api/v1/group_class_joinings/{id}/actions/mark_attendance- Canonical address:
POST /api/v1/actions/group_classes.mark_attendance
Input
| Field | Type | Required | Notes |
|---|---|---|---|
joiningId | uuid | yes | Filled from the path {id} · Booking · id of group_class_joining |
attended | boolean | yes | Attended |
Preconditions
The action is refused with 409 and one of these codes:
| Code | Refused when |
|---|---|
joining_not_found | The booking must exist. |
already_cancelled | A cancelled booking has no attendance. |
already_finished | Attendance is recorded once. |
not_yet_started | The session must have started. |
no_workspace | The workspace must be readable, for its clock. |
Events it publishes: group_classes.attended, group_classes.no_show
What it writes: group_class_joining (update) — Moves it to completed or no_show
curl -X POST https://app.getera.io/api/v1/group_class_joinings/GROUP_CLASS_JOINING_ID/actions/mark_attendance \
-H "Authorization: Bearer $ERA_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{"attended":true}'{
"ok": true,
"result": "…",
"events": [
"group_classes.attended",
"group_classes.no_show"
]
}import { createEra } from "@getera/sdk"
const era = createEra({ apiKey: process.env.ERA_API_KEY })
const res = await era.groupClassJoinings.markAttendance("GROUP_CLASS_JOINING_ID", {
attended: true
})era group_class_joinings mark_attendance GROUP_CLASS_JOINING_ID \
--attended true{
"name": "era__group_classes__mark_attendance",
"arguments": {
"joiningId": "GROUP_CLASS_JOINING_ID",
"attended": true
}
}Errors: 401 no or expired credential · 403 the credential does not hold group_classes:write · 404 the record or module is outside what it may reach · 422 invalid input (problems[]) · 409 joining_not_found, already_cancelled, already_finished, not_yet_started, no_workspace · 429 slow down
group_classes.set_services
Change the services — Which services make up the class — and so its price.
Needs group_classes:manage · removes or cannot be undone
https://app.getera.io/api/v1/group_class_services/actions/set_services- Canonical address:
POST /api/v1/actions/group_classes.set_services
Input
| Field | Type | Required | Notes |
|---|---|---|---|
id | uuid | yes | Class · id of group_class |
itemVariantIds | object / array | yes | Services · [itemVariantId, …] |
Preconditions
The action is refused with 409 and one of these codes:
| Code | Refused when |
|---|---|
not_found | The class must exist. |
class_archived | A retired class cannot be edited. |
no_services | At least one service must remain. |
service_not_found | Every service must exist. |
not_a_class_service | Only services set up as group classes may be used. |
service_not_offered_that_day | Every service must be offered on the days the class runs. |
Events it publishes: group_classes.class_updated
What it writes: group_class_service (upsert) — Sets the class’s services; group_class_service (delete) — Removes the ones no longer in it
curl -X POST https://app.getera.io/api/v1/group_class_services/actions/set_services \
-H "Authorization: Bearer $ERA_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{"id":"GROUP_CLASS_ID","itemVariantIds":{}}'{
"ok": true,
"result": "…",
"events": [
"group_classes.class_updated"
]
}import { createEra } from "@getera/sdk"
const era = createEra({ apiKey: process.env.ERA_API_KEY })
const res = await era.groupClassServices.setServices({
id: "GROUP_CLASS_ID",
itemVariantIds: {}
})era group_class_services set_services --data '{"id":"GROUP_CLASS_ID","itemVariantIds":{}}'{
"name": "era__group_classes__set_services",
"arguments": {
"id": "GROUP_CLASS_ID",
"itemVariantIds": {}
}
}Errors: 401 no or expired credential · 403 the credential does not hold group_classes:manage · 404 the record or module is outside what it may reach · 422 invalid input (problems[]) · 409 not_found, class_archived, no_services, service_not_found, not_a_class_service, service_not_offered_that_day · 429 slow down
group_classes.update_class
Edit a class — Name, places and the default instructor.
Needs group_classes:manage · changes data
https://app.getera.io/api/v1/group_classes/{id}/actions/update_class- Canonical address:
POST /api/v1/actions/group_classes.update_class
Input
| Field | Type | Required | Notes |
|---|---|---|---|
id | uuid | yes | Filled from the path {id} · Class · id of group_class |
name | string | Name · max 255 | |
capacity | number | Places · min 1 · max 10000 | |
instructorUserId | uuid | Instructor | |
clearInstructor | boolean | No default instructor |
Preconditions
The action is refused with 409 and one of these codes:
| Code | Refused when |
|---|---|
not_found | The class must exist. |
class_archived | A retired class cannot be edited. |
capacity_below_booked | Places cannot drop below a coming session’s bookings. |
provider_cannot_perform | The instructor must deliver every service in the class. |
no_workspace | The workspace must be readable, for its clock. |
Events it publishes: group_classes.class_updated
What it writes: group_class (update) — Updates the class
curl -X POST https://app.getera.io/api/v1/group_classes/GROUP_CLASSE_ID/actions/update_class \
-H "Authorization: Bearer $ERA_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{"name":"Name"}'{
"ok": true,
"result": "…",
"events": [
"group_classes.class_updated"
]
}import { createEra } from "@getera/sdk"
const era = createEra({ apiKey: process.env.ERA_API_KEY })
const res = await era.groupClasses.updateClass("GROUP_CLASSE_ID", {
name: "Name"
})era group_classes update_class GROUP_CLASSE_ID \
--name "Name"{
"name": "era__group_classes__update_class",
"arguments": {
"id": "GROUP_CLASSE_ID",
"name": "Name"
}
}Errors: 401 no or expired credential · 403 the credential does not hold group_classes:manage · 404 the record or module is outside what it may reach · 422 invalid input (problems[]) · 409 not_found, class_archived, capacity_below_booked, provider_cannot_perform, no_workspace · 429 slow down
group_classes.update_schedule
Edit a weekly time — Length and instructor always; day and time only while nobody is booked on it.
Needs group_classes:manage · changes data
https://app.getera.io/api/v1/group_class_schedules/{id}/actions/update_schedule- Canonical address:
POST /api/v1/actions/group_classes.update_schedule
Input
| Field | Type | Required | Notes |
|---|---|---|---|
scheduleId | uuid | yes | Filled from the path {id} · Series · id of group_class_schedule |
weekday | number | Day · min 0 · max 6 | |
startTime | string | Starts · max 8 | |
duration | number | Length (minutes) · min 1 · max 1440 | |
instructorUserId | uuid | Instructor | |
clearInstructor | boolean | Use the class’s instructor |
Preconditions
The action is refused with 409 and one of these codes:
| Code | Refused when |
|---|---|
schedule_not_found | The series must exist. |
schedule_ended | An ended series cannot be edited. |
class_archived | A retired class cannot be edited. |
no_schedule | Day, time and length must be well-formed. |
has_upcoming_joinings | Day and time cannot move while people are booked on the series. |
schedule_exists | The class must not already run at the new day and time. |
service_not_offered_that_day | The class’s services must be offered on the new day. |
provider_cannot_perform | The instructor must deliver every service in the class. |
Events it publishes: group_classes.series_updated
What it writes: group_class_schedule (update) — Updates the series
curl -X POST https://app.getera.io/api/v1/group_class_schedules/GROUP_CLASS_SCHEDULE_ID/actions/update_schedule \
-H "Authorization: Bearer $ERA_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{"weekday":1}'{
"ok": true,
"result": "…",
"events": [
"group_classes.series_updated"
]
}import { createEra } from "@getera/sdk"
const era = createEra({ apiKey: process.env.ERA_API_KEY })
const res = await era.groupClassSchedules.updateSchedule("GROUP_CLASS_SCHEDULE_ID", {
weekday: 1
})era group_class_schedules update_schedule GROUP_CLASS_SCHEDULE_ID \
--weekday 1{
"name": "era__group_classes__update_schedule",
"arguments": {
"scheduleId": "GROUP_CLASS_SCHEDULE_ID",
"weekday": 1
}
}Errors: 401 no or expired credential · 403 the credential does not hold group_classes:manage · 404 the record or module is outside what it may reach · 422 invalid input (problems[]) · 409 schedule_not_found, schedule_ended, class_archived, no_schedule, has_upcoming_joinings, schedule_exists, service_not_offered_that_day, provider_cannot_perform · 429 slow down
Data models
GroupClassJoining
Table group_class_joining · Resource group_class_joinings
GET /api/v1/group_class_joiningsGET /api/v1/group_class_joinings/{id}
| Column | Type | Nullable | Allowed values | References |
|---|---|---|---|---|
id | string (uuid) · uuid | |||
organization_id | string (uuid) · uuid | organization | ||
workspace_id | string (uuid) · uuid | workspace | ||
group_class_id | string (uuid) · uuid | group_class | ||
schedule_id | string (uuid) · uuid | group_class_schedule | ||
customer_id | string (uuid) · uuid | customer | ||
session_date | string (date) · date | |||
start_time | string (time) · time | |||
status | string · text | active, cancelled, completed, no_show | ||
price_amount | string (int64) · int8 | |||
price_currency | string · bpchar | yes | max 3 | |
cancelled_at | string (date-time) · timestamptz | yes | ||
cancellation_reason | string · text | yes | ||
attended_marked_at | string (date-time) · timestamptz | yes | ||
owner_user_id | string (uuid) · uuid | yes | app_user | |
created_at | string (date-time) · timestamptz | |||
updated_at | string (date-time) · timestamptz |
Primary key: id
Checks:
CHECK ((price_amount >= 0))
GroupClassSchedule
Table group_class_schedule · Resource group_class_schedules
GET /api/v1/group_class_schedulesGET /api/v1/group_class_schedules/{id}
| Column | Type | Nullable | Allowed values | References |
|---|---|---|---|---|
id | string (uuid) · uuid | |||
organization_id | string (uuid) · uuid | organization | ||
workspace_id | string (uuid) · uuid | workspace | ||
group_class_id | string (uuid) · uuid | group_class | ||
weekday | integer · int4 | |||
start_time | string (time) · time | |||
duration | integer · int4 | |||
instructor_user_id | string (uuid) · uuid | yes | app_user | |
starts_on | string (date) · date | yes | ||
ends_on | string (date) · date | yes | ||
created_at | string (date-time) · timestamptz |
Primary key: id
Checks:
CHECK (((starts_on IS NULL) OR (ends_on IS NULL) OR (ends_on >= starts_on)))CHECK ((duration > 0))CHECK (((weekday >= 0) AND (weekday <= 6)))
GroupClassService
Table group_class_service · Resource group_class_services
GET /api/v1/group_class_servicesGET /api/v1/group_class_services/{id}
| Column | Type | Nullable | Allowed values | References |
|---|---|---|---|---|
id | string (uuid) · uuid | |||
organization_id | string (uuid) · uuid | organization | ||
workspace_id | string (uuid) · uuid | workspace | ||
group_class_id | string (uuid) · uuid | group_class | ||
item_variant_id | string (uuid) · uuid | item_variant | ||
sort_order | integer · int4 | |||
created_at | string (date-time) · timestamptz |
Primary key: id
Unique: group_class_id, item_variant_id
GroupClass
Table group_class · Resource group_classes
GET /api/v1/group_classesGET /api/v1/group_classes/{id}
| Column | Type | Nullable | Allowed values | References |
|---|---|---|---|---|
id | string (uuid) · uuid | |||
organization_id | string (uuid) · uuid | organization | ||
workspace_id | string (uuid) · uuid | workspace | ||
name | string · text | |||
capacity | integer · int4 | |||
instructor_user_id | string (uuid) · uuid | yes | app_user | |
archived_at | string (date-time) · timestamptz | yes | ||
created_by | string (uuid) · uuid | yes | app_user | |
created_at | string (date-time) · timestamptz | |||
updated_at | string (date-time) · timestamptz | |||
is_public | boolean · bool | yes |
Primary key: id
Checks:
CHECK ((capacity > 0))CHECK (((length(btrim(name)) >= 1) AND (length(btrim(name)) <= 255)))
Events
Workflows and webhooks react to these events.
| Event | What happens | Payload |
|---|---|---|
group_classes.attended | A customer came to their class. | id, groupClassId, customerId, sessionDate |
group_classes.class_archived | A class was retired. | id |
group_classes.class_created | A class was created. | id, name, capacity |
group_classes.class_updated | A class changed. | id |
group_classes.joined | A customer booked a place. | id, groupClassId, customerId, sessionDate, startTime, priceAmount, priceCurrency, scheduleId |
group_classes.joining_cancelled | A class booking was cancelled. | id, groupClassId, customerId, sessionDate, reason |
group_classes.no_show | A customer did not come to their class. | id, groupClassId, customerId, sessionDate |
group_classes.series_created | A class started running at a new weekly time. | id, groupClassId, weekday, startTime |
group_classes.series_ended | A weekly series was ended. | id, groupClassId, endsOn, cancelled |
group_classes.series_updated | A weekly time changed. | id, groupClassId |
group_classes.session_cancelled | One date of a series was cancelled. | id, groupClassId, sessionDate, cancelled |