Edit
@learnhouse/sdk

The LearnHouse API, typed

Every endpoint, parameter and response is typed from the API itself, so your editor autocompletes LearnHouse. No dependencies: it only needs fetch.

$npm install @learnhouse/sdk
import { createClient } from '@learnhouse/sdk'const lh = createClient({ baseUrl, token })const course = await lh.courses.getMeta(id)// ^? CourseMeta, typed from the APIcourse.chapters[0].activitiesactivitiesActivity[]BrowserNodeBunDenoEdgeReact Native

Runs everywhere JavaScript does

Google ChromeBrowsersCookie or token auth
Node.jsNode 18+Servers, scripts, CI
BunBunSame build
DenoDenoESM import
CloudflareEdge workersfetch only, no Node APIs
ReactReact NativeHermes-safe

Quickstart

Install

npm install @learnhouse/sdk

Create a client

import { createClient } from '@learnhouse/sdk'

// Dashboard → Developers → API Access → Create Token. It starts with lh_.
const lh = createClient({
  baseUrl: process.env.LEARNHOUSE_URL!,   // your instance, without /api/v1
  token: process.env.LEARNHOUSE_TOKEN!,
})

Call the API

const org = await lh.orgs.get('your-school')
const courses = await lh.courses.list('your-school', { limit: 12 })
const course = await lh.courses.getMeta(courses[0].course_uuid!)   // chapters and activities

for (const chapter of course.chapters ?? []) {
  console.log(chapter.name, chapter.activities?.map((a) => a.name))
}

Responses are typed from the API's schema: course.chapters autocompletes, and a typo in a field name is a compile error, not a runtime surprise.

Server or browser?

On your server
createClient({ baseUrl, token: 'lh_…' })
  • An org API token, from Dashboard → Developers → API Access.
  • Acts on that org with the token’s permissions.
  • Next.js route handlers, workers, scripts, CI.
In a browser or app
createClient({ baseUrl, getToken })
  • The signed-in learner’s access token, or their cookie session.
  • Sees exactly what that learner can see.
  • Never ship an lh_ token to a browser.

More in Authentication.

Everything else

The resources (orgs, courses, activities, trail…) cover the common reads and progress. For anything else, call any endpoint by its path, still fully typed:

const meta = await lh.GET('/api/v1/courses/{course_uuid}/meta', {
  params: { path: { course_uuid: 'course_…' }, query: { slim: true } },
})

See Typed requests & errors, and the API reference for every endpoint.

Pairs with the React component

@learnhouse/react uses this SDK. Fetch on your server with an API token, render in the browser:

const activity = await lh.activities.get('activity_…')
return <LearnHouseActivity activity={activity} courseId="course_…" baseUrl={LEARNHOUSE_URL} />

The SDK's version is the LearnHouse release its types came from. Use the one that matches your instance; see Versions & releases.