Get Learning results
US Region: https://public-api.sessionboard.com · EU Region: https://public-api-eu.sessionboard.com
Results for the workspace: completions by month (last 6 months), credit claimed by credit type (last 12 months), up to 20 certifications with holders, expiring within 90 days and expired, the home counts, the door (companies read completions and certifications first, associations read credit first), and claude_prompt, a ready-made prompt with these numbers for building a dashboard in Claude. Nothing is sent anywhere. Reads only. Requires read:learning; refused for a key restricted to particular events. Also at GET /v1/learning/workspace/results.
Request example
curl --request GET \ --url 'https://public-api.sessionboard.com/v1/organization/{orgId}/learning/workspace/results' \ --header 'x-access-token: <api-token>'const response = await fetch('https://public-api.sessionboard.com/v1/organization/{orgId}/learning/workspace/results', { method: 'GET', headers: { "x-access-token": "<api-token>" },});
const data = await response.json();console.log(data);import requests
response = requests.request( "GET", "https://public-api.sessionboard.com/v1/organization/{orgId}/learning/workspace/results", headers={ "x-access-token": "<api-token>" },)
print(response.json())<?php
$curl = curl_init();
curl_setopt_array($curl, [ CURLOPT_URL => "https://public-api.sessionboard.com/v1/organization/{orgId}/learning/workspace/results", CURLOPT_RETURNTRANSFER => true, CURLOPT_CUSTOMREQUEST => "GET", CURLOPT_HTTPHEADER => [ "x-access-token: <api-token>", ],]);
$response = curl_exec($curl);curl_close($curl);
echo $response;package main
import ( "fmt" "io" "net/http")
func main() { req, _ := http.NewRequest("GET", "https://public-api.sessionboard.com/v1/organization/{orgId}/learning/workspace/results", nil) req.Header.Add("x-access-token", "<api-token>")
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/results")) .header("x-access-token", "<api-token>") .method("GET", HttpRequest.BodyPublishers.noBody()) .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.
Responses
200application/json
OK
successbooleanpayloadLearningWorkspaceResultsShow child attributes
doorstring- Allowed values
"associations", "companies"
credits_enabledbooleanmonthlyobject[]Course completions by month, last 6 months.
Show child attributes
monthstringYYYY-MMcompletionsinteger
credit_by_typeobject[]Live credit claimed by credit type, last 12 months.
Show child attributes
credit_typestring | nullamountnumberclaimsintegerpeopleinteger
certificationsobject[]Up to 20 certifications that are not retired, most holders first.
Show child attributes
idstring<uuid>namestringvalidity_monthsinteger | nullholdersintegerexpiring_90dintegerexpiredinteger
countsLearningWorkspaceCountsShow child attributes
courses_publishedintegercourses_draftintegercertificationsintegerPublished certifications.
learnersintegerPeople with any course progress.
active_learners_30dintegercertifiedintegerActive
certified_30dintegerexpiring_30dintegeroverdueintegerAssignments past due and not completed.
assignedintegerassigned_doneintegerdrafts_readyintegerCourse drafts ready for review.
drafts_workingintegerCourse drafts queued or generating.
sitesintegerLearning Sites.
credit_30dnumberCredit claimed in the last 30 days
claims_30dintegertranscriptsintegerPeople with at least one credit claim.
claude_promptstringA prompt with these numbers for building a dashboard in Claude. Nothing is sent.
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>
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": { "door": "associations", "credits_enabled": true, "monthly": [ { "month": "<string>", "completions": 123 } ], "credit_by_type": [ { "credit_type": "<string>", "amount": 123.45, "claims": 123, "people": 123 } ], "certifications": [ { "id": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "name": "<string>", "validity_months": 123, "holders": 123, "expiring_90d": 123, "expired": 123 } ], "counts": { "courses_published": 123, "courses_draft": 123, "certifications": 123, "learners": 123, "active_learners_30d": 123, "certified": 123, "certified_30d": 123, "expiring_30d": 123, "overdue": 123, "assigned": 123, "assigned_done": 123, "drafts_ready": 123, "drafts_working": 123, "sites": 123, "credit_30d": 123.45, "claims_30d": 123, "transcripts": 123 }, "claude_prompt": "<string>" }}{ "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"}{ "error": "<string>", "message": "<string>", "status": 123, "success": true, "name": "<string>", "code": "<string>", "feature": "<string>", "paused_at": "2026-01-15T09:30:00Z"}