Publish a meeting on demand
US Region: https://public-api.sessionboard.com · EU Region: https://public-api-eu.sessionboard.com
Asks to publish the meeting's draft courses (all of them, or lessonIds). Publishing waits for a person: the call answers 202 with status: needs_approval and a link, and nothing is published until a person approves it in Sessionboard Learning; it then runs as them. When it runs, a course whose faculty has no disclosure on file, or that still waits for its recording, stays a draft and is listed as held with the reason. Do not call again while the request is pending. The token's user needs the Lessons update permission. Requires write:learning; refused for a key restricted to particular events. Also at POST /v1/learning/workspace/on-demand/{eventId}/publish.
Request example
curl --request POST \ --url 'https://public-api.sessionboard.com/v1/organization/{orgId}/learning/workspace/on-demand/{eventId}/publish' \ --header 'x-access-token: <api-token>' \ --header 'Content-Type: application/json' \ --data '{ "lessonIds": [ "3c90c3cc-0d44-4b50-8888-8dd25736052a" ], "prompt": "<string>"}'const response = await fetch('https://public-api.sessionboard.com/v1/organization/{orgId}/learning/workspace/on-demand/{eventId}/publish', { method: 'POST', headers: { "x-access-token": "<api-token>", "Content-Type": "application/json" }, body: JSON.stringify({ "lessonIds": [ "3c90c3cc-0d44-4b50-8888-8dd25736052a" ], "prompt": "<string>" }),});
const data = await response.json();console.log(data);import requests
response = requests.request( "POST", "https://public-api.sessionboard.com/v1/organization/{orgId}/learning/workspace/on-demand/{eventId}/publish", headers={ "x-access-token": "<api-token>", "Content-Type": "application/json" }, json={ "lessonIds": [ "3c90c3cc-0d44-4b50-8888-8dd25736052a" ], "prompt": "<string>" },)
print(response.json())<?php
$curl = curl_init();
curl_setopt_array($curl, [ CURLOPT_URL => "https://public-api.sessionboard.com/v1/organization/{orgId}/learning/workspace/on-demand/{eventId}/publish", CURLOPT_RETURNTRANSFER => true, CURLOPT_CUSTOMREQUEST => "POST", CURLOPT_POSTFIELDS => '{ "lessonIds": [ "3c90c3cc-0d44-4b50-8888-8dd25736052a" ], "prompt": "<string>"}', CURLOPT_HTTPHEADER => [ "x-access-token: <api-token>", "Content-Type: application/json", ],]);
$response = curl_exec($curl);curl_close($curl);
echo $response;package main
import ( "fmt" "io" "net/http" "strings")
func main() { req, _ := http.NewRequest("POST", "https://public-api.sessionboard.com/v1/organization/{orgId}/learning/workspace/on-demand/{eventId}/publish", strings.NewReader(`{ "lessonIds": [ "3c90c3cc-0d44-4b50-8888-8dd25736052a" ], "prompt": "<string>"}`)) req.Header.Add("x-access-token", "<api-token>") req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req) defer res.Body.Close() body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))}HttpRequest request = HttpRequest.newBuilder() .uri(URI.create("https://public-api.sessionboard.com/v1/organization/{orgId}/learning/workspace/on-demand/{eventId}/publish")) .header("x-access-token", "<api-token>") .header("Content-Type", "application/json") .method("POST", HttpRequest.BodyPublishers.ofString("{\n \"lessonIds\": [\n \"3c90c3cc-0d44-4b50-8888-8dd25736052a\"\n ],\n \"prompt\": \"<string>\"\n}")) .build();
HttpResponse<String> response = HttpClient.newHttpClient() .send(request, HttpResponse.BodyHandlers.ofString());
System.out.println(response.body());Try it
Response headers
Authorizations
x-access-tokenstringheaderOrganization API token. Generate from Organization Settings → API Tokens.
AuthorizationBearer <token>headerorOAuth 2.1 access token. Obtained via the OAuth PKCE flow at
/oauth/token.
Send one of these. See Authentication.
Path parameters
orgIdstringpathrequiredYour organization ID. Any other organization returns
404.eventIdintegerpathrequiredThe Sessionboard event. Another organization's event answers
401.- Minimum
1
Request body
lessonIdsstring<uuid>[]Only these draft courses of the meeting. Omit for all of them.
- Max items
500
promptstringWhat the person asked for, shown on the approval request.
- Max length
2000
{ "lessonIds": [ "3c90c3cc-0d44-4b50-8888-8dd25736052a" ], "prompt": "<string>"}Responses
202application/json
Waiting for a person. Nothing was published or sent: a person approves or declines the request in Sessionboard Learning (payload.url), and it then runs as them. Do not call again.
successbooleanpayloadLearningApprovalRequestShow child attributes
statusstringapproval_idstring<uuid>urlstringWhere a person approves or declines it, in Sessionboard Learning.
messagestringWaiting for your OK in Sessionboard: <url>notestringSays nothing was sent or published and not to call again.
approvalLearningApprovalShow child attributes
idstring<uuid>statusstring- Allowed values
"pending", "approved", "declined", "failed"
actionstringpublish_course,publish_on_demandorpublish_course_draft.surfacestringcoursesfor these operations.titlestringThe approval card's headline, e.g.
Publish the course “Intro to Safety”.summarystringWhat the person asked the assistant, when given (
From “…”), else empty.targetobject | nullShow child attributes
typestringcourse,eventorcourse_draft.idstring
event_idinteger | nullassistantobjectShow child attributes
vendorstringlabelstringclientstring | nullviastring | null- Allowed values
"api_token", "oauth", null
requested_byobjectShow child attributes
user_idinteger | nullnamestring | null
decided_byobject | nullShow child attributes
user_idintegernamestring | null
decided_atstring<date-time> | nullerrorstring | nullremedyobject | nullSet only when a run failed for a reason a person can fix in one step.
can_retrybooleancreated_atstring<date-time>productstringurlstring
400application/json
A path, query or body value failed validation, or an unknown body property was sent. message names the field. (A source object naming the assistant, with the person's prompt, is accepted on every write and removed before validation.) For an {eventId} path that is not a whole number: error: VALIDATION_ERROR, eventId must be a valid integer.
Gateway errors carry error (a code) and message. Errors from Learning itself carry status, success: false, message, name, and sometimes code (and feature or paused_at).
errorstring | objectThe gateway's error code (
SCOPE_REQUIRED,ORG_WIDE_TOKEN_REQUIRED,NOT_FOUND, …).messagestringstatusintegersuccessbooleannamestringcodestringFEATURE_NOT_ENABLED,AGENT_WRITES_PAUSED, …featurestringpaused_atstring<date-time>
401
Missing, invalid or expired token, or the event does not belong to your organization (Event does not belong to your organization).
403application/json
As for every Learning workspace operation:
SCOPE_REQUIRED— the token lacksread:learning(reads) orwrite:learning(writes). Legacy tokens with no scopes cannot write.ORG_WIDE_TOKEN_REQUIRED— the token is restricted to particular events: "The Learning workspace covers every event and learner in the organization, so this API key (restricted to particular events) cannot use it. Use a key without an event restriction."EVENT_ARCHIVED— the event is archived.FEATURE_NOT_ENABLED(feature: lessons_credits) — Learning is not on for the organization.FORBIDDEN— the token's user is not an active member of the organization, or lacks the Lessons permission the operation needs.
Gateway errors carry error (a code) and message. Errors from Learning itself carry status, success: false, message, name, and sometimes code (and feature or paused_at).
errorstring | objectThe gateway's error code (
SCOPE_REQUIRED,ORG_WIDE_TOKEN_REQUIRED,NOT_FOUND, …).messagestringstatusintegersuccessbooleannamestringcodestringFEATURE_NOT_ENABLED,AGENT_WRITES_PAUSED, …featurestringpaused_atstring<date-time>
404application/json
orgId is not your organization (error: NOT_FOUND, message: Organization not found).
Gateway errors carry error (a code) and message. Errors from Learning itself carry status, success: false, message, name, and sometimes code (and feature or paused_at).
errorstring | objectThe gateway's error code (
SCOPE_REQUIRED,ORG_WIDE_TOKEN_REQUIRED,NOT_FOUND, …).messagestringstatusintegersuccessbooleannamestringcodestringFEATURE_NOT_ENABLED,AGENT_WRITES_PAUSED, …featurestringpaused_atstring<date-time>
423application/json
A person has paused connected assistants for the organization or the event (code: AGENT_WRITES_PAUSED). Ask them to resume it in Sessionboard before trying again.
Gateway errors carry error (a code) and message. Errors from Learning itself carry status, success: false, message, name, and sometimes code (and feature or paused_at).
errorstring | objectThe gateway's error code (
SCOPE_REQUIRED,ORG_WIDE_TOKEN_REQUIRED,NOT_FOUND, …).messagestringstatusintegersuccessbooleannamestringcodestringFEATURE_NOT_ENABLED,AGENT_WRITES_PAUSED, …featurestringpaused_atstring<date-time>
429application/json
- The token's request limit (100 requests per 15 minutes per bucket by default — see Rate Limiting). Wait
Retry-Afterseconds. QUOTA_EXCEEDED(writes) — the token's daily write quota (10,000 a day). Resets at midnight UTC.
Gateway errors carry error (a code) and message. Errors from Learning itself carry status, success: false, message, name, and sometimes code (and feature or paused_at).
errorstring | objectThe gateway's error code (
SCOPE_REQUIRED,ORG_WIDE_TOKEN_REQUIRED,NOT_FOUND, …).messagestringstatusintegersuccessbooleannamestringcodestringFEATURE_NOT_ENABLED,AGENT_WRITES_PAUSED, …featurestringpaused_atstring<date-time>
Retry-AfterintegerheaderSeconds to wait before retrying.
Response examples
{ "success": true, "payload": { "status": "needs_approval", "approval_id": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "url": "<string>", "message": "<string>", "note": "<string>", "approval": { "id": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "status": "pending", "action": "<string>", "surface": "<string>", "title": "<string>", "summary": "<string>", "target": { "type": "<string>", "id": "<string>" }, "event_id": 123, "assistant": { "vendor": "<string>", "label": "<string>", "client": "<string>", "via": "api_token" }, "requested_by": { "user_id": 123, "name": "<string>" }, "decided_by": { "user_id": 123, "name": "<string>" }, "decided_at": "2026-01-15T09:30:00Z", "error": "<string>", "remedy": {}, "can_retry": true, "created_at": "2026-01-15T09:30:00Z", "product": "learning", "url": "<string>" } }}{ "error": "<string>", "message": "<string>", "status": 123, "success": true, "name": "<string>", "code": "<string>", "feature": "<string>", "paused_at": "2026-01-15T09:30:00Z"}{ "error": "<string>", "message": "<string>", "status": 123, "success": true, "name": "<string>", "code": "<string>", "feature": "<string>", "paused_at": "2026-01-15T09:30:00Z"}{ "error": "NOT_FOUND", "message": "Organization not found"}{ "status": 423, "success": false, "message": "A person has paused connected assistants in Sessionboard. Ask them to resume it from their workspace before trying again.", "name": "AgentWritesPausedError", "code": "AGENT_WRITES_PAUSED", "paused_at": "2026-11-06T15:04:05.000Z"}{ "error": "<string>", "message": "<string>", "status": 123, "success": true, "name": "<string>", "code": "<string>", "feature": "<string>", "paused_at": "2026-01-15T09:30:00Z"}