Set up CE Broker reporting
US Region: https://public-api.sessionboard.com · EU Region: https://public-api-eu.sessionboard.com
The provider number, a default profession for learners who have not given theirs, and a CE Broker course number per credited course (null removes one). Waits for a person's OK (202 needs_approval). Requires write:learning. Also at PUT /v1/learning/workspace/reporting/ce-broker.
Request example
curl --request PUT \ --url 'https://public-api.sessionboard.com/v1/organization/{orgId}/learning/workspace/reporting/ce-broker' \ --header 'x-access-token: <api-token>' \ --header 'Content-Type: application/json' \ --data '{ "providerNumber": "50-1234", "defaultProfession": "RN", "courseNumbers": { "key": "<string>" }, "uploadKey": "<string>"}'const response = await fetch('https://public-api.sessionboard.com/v1/organization/{orgId}/learning/workspace/reporting/ce-broker', { method: 'PUT', headers: { "x-access-token": "<api-token>", "Content-Type": "application/json" }, body: JSON.stringify({ "providerNumber": "50-1234", "defaultProfession": "RN", "courseNumbers": { "key": "<string>" }, "uploadKey": "<string>" }),});
const data = await response.json();console.log(data);import requests
response = requests.request( "PUT", "https://public-api.sessionboard.com/v1/organization/{orgId}/learning/workspace/reporting/ce-broker", headers={ "x-access-token": "<api-token>", "Content-Type": "application/json" }, json={ "providerNumber": "50-1234", "defaultProfession": "RN", "courseNumbers": { "key": "<string>" }, "uploadKey": "<string>" },)
print(response.json())<?php
$curl = curl_init();
curl_setopt_array($curl, [ CURLOPT_URL => "https://public-api.sessionboard.com/v1/organization/{orgId}/learning/workspace/reporting/ce-broker", CURLOPT_RETURNTRANSFER => true, CURLOPT_CUSTOMREQUEST => "PUT", CURLOPT_POSTFIELDS => '{ "providerNumber": "50-1234", "defaultProfession": "RN", "courseNumbers": { "key": "<string>" }, "uploadKey": "<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("PUT", "https://public-api.sessionboard.com/v1/organization/{orgId}/learning/workspace/reporting/ce-broker", strings.NewReader(`{ "providerNumber": "50-1234", "defaultProfession": "RN", "courseNumbers": { "key": "<string>" }, "uploadKey": "<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/reporting/ce-broker")) .header("x-access-token", "<api-token>") .header("Content-Type", "application/json") .method("PUT", HttpRequest.BodyPublishers.ofString("{\n \"providerNumber\": \"50-1234\",\n \"defaultProfession\": \"RN\",\n \"courseNumbers\": {\n \"key\": \"<string>\"\n },\n \"uploadKey\": \"<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.
Request body
providerNumberstring | null- Max length
20- Example
"50-1234"
defaultProfessionstring | null- Max length
8- Example
"RN"
courseNumbersobjectCourse id → CE Broker course number (20-123456).
uploadKeystring | nullThe CE Broker upload key, for a live account. Write-only; never returned.
- Max length
200
{ "providerNumber": "50-1234", "defaultProfession": "RN", "courseNumbers": { "key": "<string>" }, "uploadKey": "<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.
403application/json
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."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": "ORG_WIDE_TOKEN_REQUIRED", "message": "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."}{ "error": "SCOPE_REQUIRED", "message": "This operation requires the 'write:learning' scope."}{ "status": 403, "success": false, "message": "Feature 'lessons_credits' is not enabled for this organization", "name": "FeatureNotEnabledError", "code": "FEATURE_NOT_ENABLED", "feature": "lessons_credits"}{ "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"}