---
title: "Launching: Unified API for Learning Management Systems"
slug: launching-unified-api-for-learning-management-systems
date: 2026-02-26
author: Uday Gajavalli
categories: [Product Updates]
excerpt: "Integrate with Canvas, Moodle, Docebo, and TalentLMS through a single Unified API for Learning Management Systems."
tldr: "Truto’s Unified API for Learning Management Systems normalizes users, courses, and enrollments across multiple platforms into a single canonical schema."
canonical: https://truto.one/blog/launching-unified-api-for-learning-management-systems/
---

# Launching: Unified API for Learning Management Systems


We just shipped our Unified Learning Management System (LMS) API. If you build edtech software, corporate training tools, or HR platforms, you already know the pain of integrating with LMS providers. Every platform has its own proprietary data model, authentication flow, and pagination logic.

Starting today, you can integrate with **TalentLMS** using a single, [canonical schema](https://truto.one/blog/why-schema-normalization-is-the-hardest-problem-in-saas-integrations/) to manage Users, Courses, Course Items, and Course Enrollments.
## The Brutal Reality of Building LMS API Integrations

**LMS API integration** is the process of connecting external applications to a Learning Management System to sync users, courses, and enrollments. In practice, it means dealing with fragmented protocols, rigid data models, and aggressive rate limits.

If you have ever tried to build a 1:1 integration with an LMS, you have likely run into these architectural headaches:

*   **Aggressive rate limits:** Docebo caps you at exactly 1,000 calls per hour per endpoint per IP. If you are syncing a large university's enrollments, you will hit that wall in minutes without a queuing system.
*   **Fragmented API strategies:** Canvas pushes developers toward their GraphQL API, yet many core resources are still only available via their legacy REST API. You end up maintaining two separate API clients for a single integration.
*   **Rigid data models:** Moodle strictly mandates that a user must be fully registered in the system before they can be enrolled in a course. If your application attempts to handle payment and enrollment in a single transaction, the API rejects it.
*   **Auth nightmares:** While some platforms support standard OAuth2, others require administrators to manually generate highly privileged developer keys and assign granular account roles—like Canvas's API Roster Exchange setup.
*   **Pagination chaos:** If you want to sync 10,000 course enrollments, you have to paginate. Canvas uses standard HTTP Link headers. Docebo limits you to 100 records per page using offset/limit parameters. Moodle often requires custom page indexing. Your engineering team ends up writing a custom pagination iterator for every single LMS.

[Building these integrations in-house](https://truto.one/blog/3-models-for-product-integrations-a-choice-between-control-and-velocity/) means writing custom imperative code to handle every provider's specific quirks, rate limits, and error codes. It is a massive maintenance burden that distracts your team from building your actual product.

## How a Unified Learning Management System API Works

A [unified API](https://truto.one/blog/what-is-a-unified-api/) acts as a translation layer. You send a standard JSON payload to Truto, and we handle the translation to the specific LMS provider. 

Our Unified LMS API normalizes four core resources:

*   **Users:** Create, update, and fetch learners, instructors, and administrators. We normalize the wildly different role definitions across platforms.
*   **Courses:** Retrieve course catalogs, metadata, descriptions, and configuration states (active, archived, draft).
*   **Course Items:** Access the nested hierarchy of individual modules, lessons, quizzes, and assignments within a course.
*   **Course Enrollments:** Manage who is taking what, track completion status, sync grades, and monitor learner progress.

## Architectural Deep Dive: Normalizing LMS Data Models

Instead of writing custom imperative code for every new LMS, Truto uses a proxy layer combined with declarative JSONata expressions. This architecture cleanly separates the unified interface you interact with from the messy reality of the third-party API.

When you request `GET /unified/lms/courses`, our engine evaluates a mapping configuration for that specific integrated account. We map your unified query parameters (like `limit=50`) into the provider's native format, execute the request through our proxy layer, and map the response back into our canonical schema.

The proxy layer handles the authentication injection, rate limiting, and pagination automatically. The mapping layer uses JSONata to transform the payload. For example, standardizing a course's creation date from Moodle's UNIX timestamp into an ISO 8601 string happens declaratively:

```jsonata
response.{
  "id": $string(id),
  "name": fullname,
  "description": summary,
  "status": visible ? "active" : "inactive",
  "created_at": $fromMillis(timecreated * 1000)
}
```

### Handling Multi-Step Operations Automatically

Remember the Moodle quirk where you cannot enroll a user who doesn't exist? Our architecture supports **before and after steps**. If a unified operation requires multiple API calls to satisfy a provider's rigid rules, we chain those proxy calls together behind the scenes.

If you send a request to enroll a user, our engine evaluates the payload, executes a "before step" to check if the user exists (and creates them if they do not), and then executes the primary enrollment request. You make one unified request; we handle the sequence of API calls required to make it happen.

### Solving the N+1 Problem with Related Resources

LMS integrations are notorious for causing N+1 query problems. You fetch a list of 50 enrollments, but the API only returns a `user_id` and a `course_id`. To display a meaningful dashboard to your users, you now have to make 50 requests to the Users endpoint and 50 requests to the Courses endpoint.

Our engine solves this through declarative side-loading. You pass an `include=user,course` query parameter, and our engine executes the related resource fetches concurrently. It joins the related data to the primary response using equality or array-contains logic before the payload ever reaches your server.

> [!TIP]
> Side-loading related resources drastically reduces the number of HTTP requests your application needs to make, but it does consume API quota on the underlying LMS provider. Always monitor your rate limits when aggressively side-loading data.

## The Escape Hatch: Bypassing the Unified Schema

I will be honest: unified APIs are an abstraction, and all abstractions leak. If a customer uses a highly customized Canvas instance with proprietary metadata fields, a strict unified schema will drop that data. 

We do not hide this reality. Every single response from Truto includes a `remote_data` object containing the raw, untouched JSON payload from the third-party API. 

```json
{
  "result": [
    {
      "id": "course_123",
      "name": "Introduction to Computer Science",
      "description": "A foundational CS course.",
      "status": "active",
      "remote_data": {
        "custom_canvas_course_id": "9982",
        "sis_course_id": "CS101-Fall",
        "workflow_state": "available"
      }
    }
  ],
  "next_cursor": "page_2"
}
```

If you need a field that falls outside our canonical model, it is always there. You are never locked out of platform-specific features. 

If you need to bypass the unified model entirely to hit an obscure, undocumented endpoint, you can use our Proxy API. The Proxy API uses the exact same underlying transport layer, allowing you to make raw HTTP requests directly to the provider using the stored credentials, completely bypassing the JSONata mapping layer.

## Handling LMS Pagination and Rate Limits

As mentioned earlier, LMS platforms use wildly different pagination strategies. Truto abstracts this away entirely using our [declarative pagination](https://truto.one/blog/declarative-pagination-system-in-truto-unified-real-time-api/) system. 

Every list endpoint in the Unified LMS API returns a `next_cursor` and `prev_cursor`. You pass this cursor back in your next request, and our engine translates it into the provider's native pagination strategy—whether that means extracting a Link header, calculating the next offset, or incrementing a page parameter.

Rate limits are handled the same way. LMS providers signal “too many requests” in different ways: some use HTTP 429, others return 200 with a custom header or use headers like `X-RateLimit-Remaining` and `X-RateLimit-Reset`. Truto detects rate limiting per integration (by default we treat HTTP 429 as rate limited; we can also use a configurable JSONata expression for providers that use non-429 status or custom headers). When we determine a response is rate limited, we **standardize** what your application sees:

- **Status:** We always return **HTTP 429** to you, even if the underlying LMS used a different status.
- **Retry-After:** We normalize “when to retry” into a single **`Retry-After`** header (seconds or derived from the provider’s HTTP-date or from provider-specific headers like `X-RateLimit-Reset` via JSONata).
- **Quota headers:** When configured, we map provider-specific headers (e.g. `X-RateLimit-Limit`, `X-RateLimit-Remaining`) into a fixed set: **`ratelimit-limit`**, **`ratelimit-remaining`**, and **`ratelimit-reset`**. You can rely on the same header names across every LMS.

These same **`ratelimit-*`** headers are also added on **successful** responses, so your client can always read quota state and avoid hitting the limit in the first place. The Unified API also sets **`truto_error_insight.rate_limit_error`** on 429 responses so you can handle rate limits in code without parsing body text. Both the Unified LMS API and the Proxy API use the same pipeline, so you get a consistent, predictable experience no matter how each LMS signals rate limits.

## Next Steps for LMS Integration

We are starting with TalentLMS, and our engineering team is actively building out support for Canvas, Moodle, Blackboard, and Docebo. 

Read the [Unified LMS API Reference](https://truto.one/docs/api-reference/unified-lms-api) to review the exact schemas for users, courses, and enrollments, and start building your integration today.

> Want to get early access to our upcoming LMS integrations or request a specific provider? Schedule a technical deep dive with our engineering team.
>
> [Talk to us](https://cal.com/truto/partner-with-truto)
