Scheduling track cohorts (Scheduled Tracks)¶
A scheduled track is a time-bound instance of a track, run for a specific cohort. Where a track is a reusable template — "Engineering Onboarding" — a scheduled track is one delivery of it: "Engineering Onboarding, Q2 2025", with real dates, a location, a capacity, and concrete event sessions in place of the template's event-series placeholders.
This guide creates a scheduled track from a template, picks the events for it, and (optionally) links a Slack channel.
How it differs from a track¶
- A scheduled track is created from a template track and keeps a read-only reference to it (
original_track). - It snapshots the template's items at creation time. Editing the template afterward does not change an existing scheduled track.
- It carries scheduling fields a plain track doesn't:
starts_at,ends_at,location,is_online,is_local, andcapacity. - Template tracks usually contain event-series placeholders ("Weekly Sync" as a type). A scheduled track replaces each placeholder with a concrete event — a specific session on a specific date — via the swap-events action.
1. Schedule a track¶
Turn a template track into a cohort instance with the schedule action on the source track:
curl -X POST https://acme.plusplus.app/api/v2/tracks/7a8b9c0d-…/schedule/ \
-H "Authorization: Bearer pp_your_token_here" \
-H "Content-Type: application/json" \
-d '{
"name": "Engineering Onboarding (Q2 2025)",
"starts_at": "2025-04-01T09:00:00Z",
"ends_at": "2025-04-30T17:00:00Z",
"location_id": 42,
"is_online": true,
"is_local": true,
"capacity": 20
}'
{
"public_id": "f1e2d3c4-…",
"name": "Engineering Onboarding (Q2 2025)",
"content_type": "scheduled_track",
"original_track": { "public_id": "7a8b9c0d-…", "name": "Engineering Onboarding" },
"starts_at": "2025-04-01T09:00:00Z",
"ends_at": "2025-04-30T17:00:00Z",
"location": { "id": 42, "name": "San Francisco HQ", "timezone": "America/Los_Angeles" },
"capacity": 20,
"is_capacity_full": false,
"track_items_count": 6,
"slack_channel": null
}
A few things to know:
- Every field is optional. Omit
nameand it inherits the template's name; omit the scheduling fields and they stay empty. The new scheduled track still snapshots the template's items. capacityis0for unlimited. When set,is_capacity_fullflips totrueonce assignments reach it.location_idis the location's numeric id (the same id you see in an event series'location), not apublic_id.- The template is untouched. Scheduling reads the template's items and copies them onto the new scheduled track.
2. Pick events for each event-series slot¶
Right after scheduling, any event-series placeholder in the track is still a type, not a real session. Use swap-events to choose the concrete event for each slot:
curl -X POST https://acme.plusplus.app/api/v2/scheduled-tracks/f1e2d3c4-…/swap-events/ \
-H "Authorization: Bearer pp_your_token_here" \
-H "Content-Type: application/json" \
-d '{
"swapped_events": [
{
"old_event": "e1111111-…",
"new_event": "e6666666-…",
"enrollment_action": "move"
}
]
}'
old_eventis thepublic_idof the slot you're filling — either the event-series placeholder currently in the track (first-time scheduling) or a concrete event already in it (re-pointing the cohort at a new date).new_eventis thepublic_idof the concrete event to drop into that slot.enrollment_actiondecides what happens to people already enrolled on the old slot:keep— leave their enrollments on the old event; don't enroll them in the new one.move— migrate their enrollments to the new event, preserving each attendee's method (in person vs. online).
You can swap several slots in one call. The response is the updated scheduled track.
Running the next cohort
To stand up the next cohort, schedule the template again and swap in that cohort's event dates. The first cohort's scheduled track keeps its own events — the two cohorts are fully independent.
3. Link a Slack channel (optional)¶
If your account has Slack connected, you can attach a channel that everyone assigned to the cohort is auto-invited to:
curl -X POST https://acme.plusplus.app/api/v2/scheduled-tracks/f1e2d3c4-…/slack-channel/ \
-H "Authorization: Bearer pp_your_token_here" \
-H "Content-Type: application/json" \
-d '{ "name": "q2-2025-onboarding" }'
{ "id": "C0123456789", "name": "q2-2025-onboarding", "url": "https://acme.slack.com/archives/C0123456789" }
Posting a channel that doesn't exist creates it; posting an existing one links it. To remove the link without deleting the channel:
curl -X DELETE https://acme.plusplus.app/api/v2/scheduled-tracks/f1e2d3c4-…/slack-channel/ \
-H "Authorization: Bearer pp_your_token_here"
When Slack isn't configured for the account, the create call returns 400 slack_not_configured.
4. Read and list scheduled tracks¶
# One scheduled track
curl https://acme.plusplus.app/api/v2/scheduled-tracks/f1e2d3c4-…/ \
-H "Authorization: Bearer pp_your_token_here"
# All of them, newest first
curl "https://acme.plusplus.app/api/v2/scheduled-tracks/?ordering=-starts_at" \
-H "Authorization: Bearer pp_your_token_here"
The list supports search (by name), is_archived, and is_hidden filters, and ordering by name, created, modified, starts_at, or ends_at.
Assigning a scheduled track and reading per-learner progress work exactly as they do for tracks — see Building learning paths and Assignments & completion.
Common pitfalls¶
- Swapping an event that isn't in the track.
old_eventmust reference a slot currently in this scheduled track, otherwise you get400 event_not_in_track. List the track's items first if you're unsure which slots exist. - Pointing
new_eventat an event series.new_eventmust be a concrete event, not an event series — the series is the placeholder you're replacing. - Editing the template to change a running cohort. It won't. A scheduled track is a snapshot; change the cohort through its own swap-events action.
- Expecting
keepto enroll people in the new event.keepdeliberately leaves existing attendees on the old event. Usemoveto bring them across.