Cascaded settings¶
Many PlusPlus behaviors — when enrollment opens, whether self check-in is allowed, whether AI summaries show — are settings, and settings cascade. A value set on the workspace applies everywhere. A channel can override it for the content it holds. An event series can override it for its events. An individual item can override it for itself. The nearest level that holds a value wins.
flowchart LR
W[Workspace] --> C[Channel] --> S[Event series] --> E[Event]
C --> A[Article, video, course, …]
Every resource that has settings exposes them on a /settings/ sub-resource that reads and writes in the same shape, so one client covers all of them.
| Resource | Settings | Inherits from |
|---|---|---|
| Event | GET/PATCH /events/{public_id}/settings/ |
its event series, then its channel, then the workspace |
| Event series | GET/PATCH /event-series/{public_id}/settings/ |
its channel, then the workspace |
| Office hour series | GET/PATCH /programs/{public_id}/settings/ |
its channel, then the workspace |
| Article, video, course, track, scheduled track, guide, link | GET/PATCH /{articles,videos,courses,tracks,scheduled-tracks,guides,links}/{public_id}/settings/ |
its channel, then the workspace |
| Channel | GET/PATCH /channels/{public_id}/settings/ |
the workspace |
| Workspace | GET/PATCH /workspace/settings/ |
the platform default |
The API reference lists each resource's settings, their allowed values and what they do.
Channel settings are grouped¶
A channel holds two kinds of settings, so its settings resource is grouped: general applies to the channel and everything in it, and one section per content type (event, article, video, course, track, scheduled_track, guide, link) holds what that type's items in the channel inherit. Each section reads and writes exactly like an item's settings:
curl -X PATCH https://acme.plusplus.app/api/v2/channels/9f3e2d1c-…/settings/ \
-H "Authorization: Bearer pp_your_token_here" \
-H "Content-Type: application/json" \
-d '{
"general": { "anyone_can_add_content": { "value": true } },
"event": { "enrollment_closes_offset": { "value": "-P1D" } },
"article": { "content_feedback_is_public": { "inherited": true } }
}'
That closes enrollment a day before every event in the channel that has no value of its own (or whose event series has none), without touching the channel's articles or videos. A section holds only the settings the platform lets a channel set for that type, so it can be a subset of the item's own settings.
Reading a setting¶
curl https://acme.plusplus.app/api/v2/event-series/5b1d9c2e-…/settings/ \
-H "Authorization: Bearer pp_your_token_here"
{
"self_checkin_enabled": { "value": false, "inherited": false, "source": "event_series", "parent_value": true, "default": true },
"ai_summary_enabled": { "value": true, "inherited": true, "source": "channel", "parent_value": true, "default": false },
"enrollment_closes_offset": { "value": "PT0S", "inherited": true, "source": "workspace", "parent_value": "PT0S", "default": "PT0S" }
}
| Key | What it tells you |
|---|---|
value |
The value that applies to this resource right now. |
inherited |
false when the resource holds its own value (an override). |
source |
Which level supplied value: the resource itself (event, event_series, …), channel or workspace. |
parent_value |
What value becomes if you clear the override: the value the next level up supplies. |
default |
The platform default, before any level overrides it. |
An override is sticky: while inherited is false, changing the level above does not change this resource. That is the field to check before you bulk-edit a channel or an event series and expect every item to follow.
Changing a setting¶
PATCH the same URL with only the settings you want to change. Each takes one of two shapes:
| Send | Means |
|---|---|
{"value": ...} |
Give this resource its own value (an override). |
{"value": null} |
On a setting that allows null, store an explicit "no value" (for example, no enrollment deadline). This is still an override. |
{"inherited": true} |
Drop this resource's own value so it follows the level above again, including later changes to it. |
| omitted | Leave the setting as it is. |
curl -X PATCH https://acme.plusplus.app/api/v2/event-series/5b1d9c2e-…/settings/ \
-H "Authorization: Bearer pp_your_token_here" \
-H "Content-Type: application/json" \
-d '{
"self_checkin_enabled": { "value": true },
"ai_summary_enabled": { "inherited": true }
}'
The response is the full settings resource. Unknown settings, a bare value ("self_checkin_enabled": true) and a bare null are refused with 422, and nothing is written. Send If-Match with the ETag of your last read to refuse the write with 412 if the settings changed since — including a change further up the cascade.
A personal article, video or guide (one in its owner's personal library) keeps only its AI settings (ai_summary_enabled, ai_flashcards_enabled, ai_flashcards_count, ai_coach_enabled, ai_generated_covers_enabled) and, for a video, video_download_enabled. Giving it any other setting, on create or through /settings/, is refused with 400 validation_error and nothing is saved; {"inherited": true} is always accepted.
Writing settings requires permission to manage the resource itself; reading them requires only permission to see it.
Workspace defaults¶
/workspace/settings/ is the root of every cascade: change a value there and every channel, event series and item without its own value follows at once. On the workspace, {"inherited": true} restores the platform default, and parent_value is that default.
Workspace settings are admin-only. Both reading and writing need a token minted with the admin scope as well as content:read (to read) or content:write (to write), owned by a user with the Admin role; a token without either gets 403 insufficient_scope. A few settings exist only below the workspace (a channel's anyone_can_add_content, a video's ai_flashcards_count), so the workspace resource does not list them.
Setting values when you create a resource¶
The create endpoints (POST /events/, POST /event-series/, POST /programs/, POST /articles/, POST /videos/, POST /courses/, POST /tracks/, POST /guides/, POST /links/) accept the same object under settings, so a new resource never exists with the inherited values first. Each resource accepts only its own settings. This example creates an event series:
{
"name": "Security basics",
"settings": {
"ai_summary_enabled": { "value": true },
"content_feedback_is_public": { "value": false }
}
}
Settings you leave out follow the cascade. After creation, change them on the /settings/ sub-resource; the resource's own PATCH refuses settings with a 422 that points you there.
Settings by type¶
Values follow the setting's type:
- On/off settings take
trueorfalse. - Offsets (enrollment and check-in windows) take a signed ISO 8601 duration relative to the event's start:
-PT1His an hour before,PT30M30 minutes after. See Events for how they resolve. The office hour series cancellation deadline is relative to each session's start instead; see Office hour series. - Choices take one of the values the API reference lists for that setting.
- Numbers take a whole number within the bounds the API reference lists.