Lessonspace provides a resource library that can be used by teachers to insert content into a space. Usually it comes pre-filled with some useful content, and it can be updated by using the Library tab from your dashboard. It's also possible to provide a custom API endpoint from which the resource library will fetch data from.

You'll need to ensure your endpoints all allow CORS access for go.room.sh, and you may need to allow some specific headers if you choose to use the header method below.
Each request will contain two headers:
X-Holodeck-JWT The current user's JWT which is signed with the space (secret returned by the Launch API).X-Holodeck-Room The current space ID. This is Lessonspace's internal UUID that you get back from the Launch API.You can use these to validate the provided JWT against the returned secret to ensure the user has the expected permissions.
X-Holodeck-JWT and X-Holodeck-Room in the allowed headers, e.g. Access-Control-Allow-Headers: X-Holodeck-JWT, X-Holodeck-Roomcustom_jwt_parameters parameter set as appropriate.The resource library currently supports three types of files:
The resource library works in three steps. On page load, a GET request is done to fetch a list of tabs and the URL associated with each one.
When the resource library is opened, two GET requests are made to the folder and tab endpoint respectively. The tab endpoint is just the URL specified in the tabs response, while the folders endpoint is derived from the tab's foldersUrl (see Step 2).
resource parameter multiple times (or an array via the Launch API's resource_url) and the returned tab lists will be fetched in parallel and merged together into a single set of tabs. If one endpoint fails, the others are still shown.This is a listing of all the tabs to display for the library. These are presented across the left hand side of the screen, such as "Personal", "Organisation" in the screenshot above. The JSON payload needs to be an array of objects, each having a title, an icon (which will be an SVG) and a URL.
Your endpoint needs to return data that looks like:
[
{
"id": string | number,
"title": string, // "Math Resources"
"icon": string, // An SVG icon, e.g. "<svg xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\" version=\"1.1\" width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"currentColor\">...</svg>"
"url": string, // "https://example.com/path/to/tab/endpoint/"
"foldersUrl": string, // Optional. If not provided, it is resolved relative to `url` as `folders/` (see warning below)
"allow_upload": boolean // Optional. If true, an upload button is shown so users can add files to this tab
}
]
Trailing slashes matter on url. When foldersUrl is not provided, the folders endpoint is resolved as a relative URL against url (equivalent to new URL('folders/', url)), not by string concatenation.
If url ends with a slash (e.g. https://example.com/tab/), the folders endpoint becomes https://example.com/tab/folders/ as expected.
If url does not end with a slash (e.g. https://example.com/tab), the last path segment is replaced, producing https://example.com/folders/, which is almost certainly not what you want.
Always end your tab url with a trailing slash, or set foldersUrl explicitly.
This endpoint is optional, but necessary if you want to enable folder support. Currently folders can only be one level deep and are displayed at the root of each tab.
Given the tab from Step 1, a GET request is made to foldersUrl if defined, otherwise to the value resolved relative to url (see the warning above).
The folders endpoint is requested every time a tab is opened (and again when sorting or searching changes). If you don't want to support folders, just ensure the URL returns a 404 response code — this is treated as "no folders" and handled gracefully.
The following query parameters are sent to the folders endpoint:
| Parameter | Description |
|---|---|
parent | The id (or uuid) of the currently selected folder, or empty at the root. |
ordering | The current sort order: name, -name, created_at, or -created_at. |
search | The current search string (only sent when a search is active). |
searchType | current or all (only sent when a search is active). See Step 3. |
Your endpoint needs to return data that looks like:
[
{
"id": string | number,
"name": string, // e.g. "Term 1"
"uuid": string // Optional. If present, this value (rather than `id`) is used as the `folder` query parameter when requesting files
}
]
When a folder is selected, its uuid (if provided, otherwise its id) is sent as the folder query parameter in the request to the files endpoint as described in Step 3.
The files endpoint is the main endpoint that returns the list of files in the tab/folder. Given the example in Step 1 above, a GET request is made to the tab's url with the query parameters below.
| Parameter | Description |
|---|---|
| folder | The uuid (or id) of the selected folder, or empty at the root. |
| search | The current search string, or empty. |
| searchType | current (search only the current folder) or all (search across all folders). |
| ordering | Sort order: name, -name, created_at, or -created_at. |
| page | The page number, starting at 1. |
Pagination is driven by the page parameter and the top-level count. If you return fewer items in the results array than the top level count, a 'Load More' button is displayed and the page parameter is incremented until the total number of fetched results equals count.
Your endpoint needs to return data that looks like:
{
"count": 85, // total count of results across all pages
"results": [
{
"id": string | number, // Ensure this is unique within the results set
"name": string, // e.g. "Resource Name"
"type": "image" | "zip" | "pdf", // This will send the file to the correct conversion service so ensure this is accurate
"source": string, // e.g. "https://example.com/files/xyz.jpg"
"thumbnail": string, // A base64-encoded PNG thumbnail (see note). Only rendered for files of type "image".
"includeAuthHeaders": boolean // Optional. Include the X-Holodeck-JWT and X-Holodeck-Room headers when fetching the `source` URL upon selection
}
]
}
thumbnail must be a PNG. It is rendered as data:image/png;base64,<thumbnail>, so the base64 payload must decode to a PNG image. Thumbnails are only displayed for files with type: "image"; PDFs and ZIPs always show a generic type icon.With the above endpoints done, you can pass in your tabs endpoint (from Step 1) to the Launch API by setting the top level resource_url parameter. You may provide more than one to merge multiple tab sources.
When debugging and developing, you can also change the query parameter resource on the client_url (go.room.sh) URL directly. This parameter may be supplied multiple times to load several tabs endpoints at once.