S
Scholé
Integration API
What you'll build

A reseller integration reuses building blocks documented elsewhere in this portal — the Partner SSO hand-off, the course catalogue, and xAPI tracking. This guide stitches them into one linear flow. Each step links to the authoritative reference.

1. Authenticate
Get an OAuth2 client-credentials app and exchange it for a bearer token.
2. Sync the catalogue
Pull the course templates and mirror them as courses on your side.
3. Provision learners
Upsert each user once, keyed by your own stable id.
4. Launch lessons (SSO)
Mint a one-time link that drops a learner straight into a lesson, already logged in.
5. Track completion
Receive xAPI statements in real time, or poll the analytics API.
Vocabulary
A template is an abstract lesson definition in the catalogue. When a learner opens it, Schole instantiates a personalised curriculum (the lesson tailored on the fly to that learner's language, role and profile). You resell templates; learners consume curricula.
1

Authenticate

Ask your Schole contact for an OAuth2 client-credentials application scoped to the organisation you are reselling for. You receive a client_id and client_secret. Exchange them for a bearer token; every call in this guide carries that token.

bash
curl -X POST https://app.schole.ai/oauth/token/ \
  -d grant_type=client_credentials \
  -d client_id=$SCHOLE_CLIENT_ID \
  -d client_secret=$SCHOLE_CLIENT_SECRET
# → { "access_token": "…", "token_type": "Bearer", "expires_in": 43200 }

Use the trailing slash on /oauth/token/ — some HTTP clients drop the body when following the redirect on a slash-less POST.

One account, or one per client?

Resellers typically manage several end-clients, each with their own user base. Two models:

One Schole org per client recommended
Each client gets its own client_id / client_secret and its own tenant. Cleanest separation of users, catalogue and reporting. Provisioned manually today, so best when you onboard clients gradually.
One shared org
All clients live in one tenant; you namespace users with provider_id (e.g. clientA-12345). Simpler to start, but mixes users — use only if you need a single account from day one.

There is no self-service provisioning yet, so coordinate with your Schole contact on the model and on creating each client's credentials.

2

Sync the catalogue

GET /api/v1/curricula/templates/ is the backbone of the browsing experience — it returns every template visible to your organisation. Mirror each one as a course (or an activity) on your side. The endpoint is filterable, sortable and paginated, so a nightly delta sync is cheap.

bash
# Full first pull (page through until `next` is null)
curl -G https://app.schole.ai/api/v1/curricula/templates/ \
  -H "Authorization: Bearer $SCHOLE_ACCESS_TOKEN" \
  --data-urlencode "page=1" \
  --data-urlencode "page_size=100"

# Nightly delta sync — only what changed since the last run
curl -G https://app.schole.ai/api/v1/curricula/templates/ \
  -H "Authorization: Bearer $SCHOLE_ACCESS_TOKEN" \
  --data-urlencode "modified_after=2026-06-01T00:00:00Z" \
  --data-urlencode "sort=-modified_date,title"
Query param Use
search Keyword match on title or description.
language Language code (en, de, fr, it).
lesson_type mandatory, premade, or custom.
sort Comma-separated; prefix - for descending. Allowed: title, creation_date, modified_date, lesson_type, language, category, participant_count. Default title.
modified_after ISO-8601 timestamp. Returns only templates changed since then — the basis of delta sync.

The response is the standard paginated envelope (count / next / previous / results) — see Pagination. For the exact, always-current field list of a template object, explore the live schema in Swagger UI rather than hard-coding fields.

Free vs. paid is not a template property
Access is gated per user, server-side, at launch time — there is no "free/premium" flag on the template. Treat the rule as: if a template appears in this endpoint, your learners may select it. So if the list comes back empty, the organisation simply has no catalogue assigned yet — talk to your Schole contact.
Retired templates & reconciliation

Templates can be retired (soft-deleted). A retired template is hidden from this list by default and can no longer be picked for new lessons, but existing learners who already started it keep working. Because retired rows simply drop out of the default list, your nightly reconciliation should treat a template that has disappeared as removed.

  • Pass ?include_inactive=true to also return retired templates, then read each row's is_active boolean to tell them apart.
3

Provision learners

Upsert each learner with POST /api/v1/users/ when they are onboarded on your side (and again whenever their details change — it is idempotent). Key every learner on provider + provider_id (your stable id) so re-syncs never create duplicates and so the SSO hand-off in Step 4 can find them.

bash
curl -X POST https://app.schole.ai/api/v1/users/ \
  -H "Authorization: Bearer $SCHOLE_ACCESS_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "provider": "totara",
    "provider_id": "clientA-12345",
    "email": "anna@acme.com",
    "first_name": "Anna",
    "last_name": "Keller",
    "preferred_language": "de",
    "user_summary": "Backend engineer, 3y; wants to learn Kubernetes.",
    "job_titles": ["Backend Engineer"],
    "department": "Platform"
  }'
# → 201 Created (new) or 200 OK (updated). The response carries Schole's internal user id.
  • provider is a free label you choose and use consistently (e.g. "totara"). It marks these users as partner-managed, so they skip Schole's own skills-selection onboarding.
  • Richer profile = better lessons. Because each lesson is personalised on the fly, the more context you pass (user_summary, job_titles, department, tools, daily_tasks), the more tailored the content. All optional.
  • IDs in responses are Schole-internal integers. Assume internal IDs everywhere unless a field is explicitly your provider_id.
4

Launch a lesson (single sign-on)

When a learner clicks a course in your UI, hand them off into Schole already logged in. Mint a one-time login token for them, then open Schole's /auto-login route pointed at the lesson launcher. This is the Partner SSO flow — summarised here for the reseller path.

bash — mint a one-time token
curl -X POST https://app.schole.ai/api/v1/auth/partner-exchange/ \
  -H "Authorization: Bearer $SCHOLE_ACCESS_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{ "external_id": "clientA-12345" }'
# → { "login_token": "eyJ…", "expires_in": 3600 }

Open the launcher in a new tab, passing the token and a percent-encoded next that targets the template you mirrored in Step 2:

text
https://app.schole.ai/auto-login?token=eyJ…&next=%2Fstart-lesson%3Ftemplate_id%3D123
Mint on click — don't bake the token into the page
The login_token is single-use and lives ~1 hour. In an LMS a learner reopens a course page many times, so a token baked into the rendered link breaks on the second click. Instead point each course link at a small redirect endpoint on your side that calls partner-exchange on every click and forwards to /auto-login. No change is required on Schole's side — this is the intended pattern.
Optional: pre-assign instead of launch-on-demand

Launching a template_id instantiates the lesson on the fly, so you do not need to pre-create anything. If you'd rather seed a learner's home with assigned courses ahead of time, create the curriculum explicitly with POST /api/v1/curricula/:

bash
curl -X POST https://app.schole.ai/api/v1/curricula/ \
  -H "Authorization: Bearer $SCHOLE_ACCESS_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{ "user_id": 4567, "template_id": 123 }'   # user_id = Schole internal id from Step 3
5

Track completion

Completion fires per lesson. You have two ways to get it back into your platform — use either or both.

Push — xAPI (real time)
Schole sends attempted / progressed / completed statements to your Learning Record Store as they happen.
Pull — analytics (on demand)
Read a learner's progress when you need it — a useful fallback if an xAPI delivery is ever missed.

xAPI: give your Schole contact your LRS endpoint and its auth. Schole supports both HTTP Basic Auth and OAuth2 client-credentials (Bearer) — for an LMS, provide the token endpoint, client id and secret, and Schole obtains and refreshes the Bearer token itself. Full setup in the xAPI section.

Analytics pull: GET /api/v1/analytics/users/<id>/summary/ (also /progress/ and /scores/), where <id> is Schole's internal user id. For a richer event feed, see Webhooks & Events.

Go-live checklist
  • Credentials issued and a token can be obtained (Step 1).
  • Catalogue sync runs and returns templates; nightly delta uses modified_after (Step 2).
  • User upsert is idempotent on provider_id (Step 3).
  • Course links mint a fresh token per click and land the learner in the lesson (Step 4).
  • Completion is flowing back via xAPI and/or the analytics API (Step 5).
Need a hand?
Test against a sandbox organisation before going live, and reach out to your Schole contact for credentials, catalogue population, or to report anything that behaves unexpectedly.