LearnDash REST API

SkillAI & models

Build or audit LearnDash REST API integrations for courses, lessons, topics, quizzes, groups, users, course steps, enrollments, group memberships, progress, and the modern LearnDash REST manifest/OpenAPI docs. Use when code mentions ldlms/v2, learndash/v1, LearnDash_REST_API, learndash_rest_api_enabled, learndash-rest-api-controllers, sfwd-courses REST routes, /steps, /users, /groups, /course-progress, Learndash-Experimental-Rest-Api, or headless LearnDash clients.

Available today. Use it from your connected AI after setup.

Connect ahel once, and every AI you use reads what you have installed.

Then ask your AI: use the LearnDash REST API skill

What this skill tells your AI

The instructions your AI receives, as published by lonsdale201/wp-agent-skills in learndash/learndash-rest-api/SKILL.md and read by ahel’s review.

Use this when building or reviewing a REST/headless integration for LearnDash. Prefer source-verified routes and schemas over guessed endpoint shapes.

LearnDash 5.1.9 exposes two relevant REST surfaces:

  • Classic LearnDash content/relationship endpoints under ldlms/v2.
  • Newer manifest/OpenAPI/documentation endpoints under learndash/v1.

The v2 endpoints are still the practical surface for course, group, user, progress, and course-steps CRUD. The learndash/v1 manifest/docs surface is the discovery contract and includes newer endpoint metadata.

When to use this skill

Trigger when ANY of these appears:

  • /wp-json/ldlms/v2/, /wp-json/learndash/v1/, LearnDash_REST_API, learndash_rest_api_enabled, or learndash-rest-api-controllers.
  • REST work around sfwd-courses, sfwd-lessons, sfwd-topic, sfwd-quiz, groups, users, course progress, quiz progress, or assignments.
  • Headless app needs course outlines, enrollments, group memberships, or progress data.
  • API client gets 401/403, missing endpoint, wrong rest base, or malformed /steps payload errors.

Enablement and namespaces

REST availability requires both:

  • Constant LEARNDASH_REST_API_ENABLED true. The default is true.
  • LearnDash REST settings section value enabled = yes.

LearnDash_REST_API::enabled() also exposes the learndash_rest_api_enabled filter.

Classic LearnDash REST namespace defaults to ldlms; v2 routes use ldlms/v2. The namespace constant is LEARNDASH_REST_API_NAMESPACE.

Do not hard-code every route base. LearnDash settings allow REST base overrides for courses, lessons, topics, quizzes, groups, users, and relation subroutes.

Default important v2 bases:

  • Courses: /wp-json/ldlms/v2/sfwd-courses
  • Course steps: /wp-json/ldlms/v2/sfwd-courses/{id}/steps
  • Course users: /wp-json/ldlms/v2/sfwd-courses/{id}/users
  • Course groups: /wp-json/ldlms/v2/sfwd-courses/{id}/groups
  • Groups: /wp-json/ldlms/v2/groups
  • Group courses: /wp-json/ldlms/v2/groups/{id}/courses
  • Group users: /wp-json/ldlms/v2/groups/{id}/users
  • Users courses: /wp-json/ldlms/v2/users/{id}/courses
  • Users groups: /wp-json/ldlms/v2/users/{id}/groups
  • User course progress: /wp-json/ldlms/v2/users/{id}/course-progress

Discovery workflow

For learndash/v1, do not guess parameters. The local source declares the manifest as the mandatory discovery workflow.

Use:

  • GET /wp-json/learndash/v1/manifest
  • Follow each endpoint href to fetch the exact JSON schema.
  • Or inspect GET /wp-json/learndash/v1/docs/openapi.

Most learndash/v1 endpoints are experimental and require:

Learndash-Experimental-Rest-Api: allow

The manifest and OpenAPI documentation endpoints are public and not experimental in 5.1.9.

Course steps endpoint

Creating lesson/topic/quiz posts is not enough to build a course outline. Update the course steps relationship.

Endpoint:

GET/POST /wp-json/ldlms/v2/sfwd-courses/{course_id}/steps

Read permission:

  • Anonymous users are denied unless the filter learndash_rest_course_steps_allow_anonymous_read returns true.
  • Admin users can read.
  • Other logged-in users are denied by the controller.

Update permission:

  • Requires edit_courses.

Expected update body shape is an object keyed by LearnDash post types. Lesson, topic, and quiz IDs are object keys, not list items:

{
  "sfwd-lessons": {
    "123": {
      "sfwd-topic": {
        "456": {
          "sfwd-quiz": {
            "789": {}
          }
        }
      },
      "sfwd-quiz": {}
    }
  },
  "sfwd-quiz": {
    "999": {}
  }
}

Common bug: sending [123, 456] arrays. The controller expects nested objects where IDs are keys.

Course custom pagination in 5.1.7+

Course REST fields expose lessons_per_page, lesson_per_page_custom, and topic_per_page_custom. When custom pagination is enabled, use positive integers for both custom values. LearnDash 5.1.7+ normalizes empty or zero values to the corresponding global setting, then to LEARNDASH_LMS_DEFAULT_WIDGET_PER_PAGE if the global value is also invalid.

Do not use zero to mean "show all" for these course-specific fields. Disable custom pagination when the course should inherit the global values.

Enrollment and relation endpoints

Course users:

  • GET /ldlms/v2/sfwd-courses/{id}/users
  • POST /ldlms/v2/sfwd-courses/{id}/users with user_ids
  • DELETE /ldlms/v2/sfwd-courses/{id}/users with user_ids

The controller calls ld_update_course_access() for enrollment and rejects open courses with learndash_rest_rejected_course_open. It can skip admin users when admin auto-enroll is enabled.

User courses:

  • GET/POST/DELETE /ldlms/v2/users/{id}/courses
  • Individual course relation routes can update enrollment dates with enrolled_at.

Group courses:

  • GET/POST/DELETE /ldlms/v2/groups/{id}/courses with course_ids.
  • Mutations call ld_update_course_group_access().

Group users:

  • GET/POST/DELETE /ldlms/v2/groups/{id}/users with user_ids.
  • Mutations call ld_update_group_access().

User groups:

  • GET/POST/DELETE /ldlms/v2/users/{id}/groups with group_ids.

Permission model:

  • Most relation reads/writes require LearnDash admin permissions.
  • Group leaders can read users for groups they administer.
  • Group leaders are not generally allowed to mutate group users through these controllers.

Extending REST safely

LearnDash's v2 REST loader registers controllers on rest_api_init and exposes the controller list through learndash-rest-api-controllers. Prefer adding a separate namespaced WP REST controller for custom app APIs unless the task specifically needs to extend LearnDash's own route catalog.

For custom fields on LearnDash posts:

  • Register real post meta with show_in_rest when possible.
  • For LearnDash metabox settings, inspect register_rest_fields() in the v2 posts controller and the specific post-type controller before inventing field names.
  • Keep permission callbacks explicit. Do not expose course progress or enrollment writes publicly.

Progress routes are read-only

The v2 user progress routes expose course headers, ordered steps, quiz progress, and challenge-exam state through GET requests. In 5.1.9, /users/{id}/course-progress, its /{course} route, /{course}/steps, and /{course}/exam do not register a general progress-write method.

Do not invent a PATCH contract from the response schema. For a custom mutation endpoint, authorize the actor against the target user and call LearnDash's completion/progress APIs; use learndash-course-progress for that lifecycle.

Headless integration checklist

  1. Check REST is enabled in constants and LearnDash settings.
  2. Discover actual bases from settings or manifest/docs instead of assuming defaults on customized sites.
  3. Authenticate with Application Password, cookie+nonce, OAuth/JWT layer, or a site-specific auth plugin.
  4. Fetch course posts and then fetch /steps for the outline.
  5. Use relation endpoints for enrollment/group changes, not raw usermeta.
  6. Use progress endpoints for progress, not direct activity-table writes.
  7. Respect pagination, batch limits, and per-item success/failure responses.
  8. Cache read responses carefully and invalidate on post, access, group, and progress mutations.

Common mistakes to reject

  • Guessing learndash/v1 request bodies without first reading manifest href details.
  • Hard-coding route bases when LearnDash settings can change them.
  • Creating lessons/topics but never updating course steps.
  • Sending arrays to /steps instead of nested ID-keyed objects.
  • Trying to enroll users into an open course through the course-users endpoint.
  • Assuming group leaders can mutate all group REST relations.
  • Exposing a custom public route that returns locked course content without checking sfwd_lms_has_access().

Cross-references

  • Use learndash-course-access for final access checks and direct course enrollment semantics.
  • Use learndash-group-access for group membership and group-course relation behavior.
  • Use learndash-woocommerce-access for Woo-driven access changes.
  • Use learndash-course-progress for server-side completion, reset, activity, and progress-write behavior.
  • Use wp-rest-api for general WordPress REST security and schema patterns.

References

Validated against LearnDash LMS 5.1.9 local source:

  • includes/rest-api/class-ld-rest-api.php
  • includes/settings/settings-sections/class-ld-settings-section-general-rest-api.php
  • includes/rest-api/v2/class-ld-rest-courses-steps-controller.php
  • includes/rest-api/v2/class-ld-rest-courses-users-controller.php
  • includes/rest-api/v2/class-ld-rest-users-courses-controller.php
  • includes/rest-api/v2/class-ld-rest-groups-courses-controller.php
  • includes/rest-api/v2/class-ld-rest-groups-users-controller.php
  • includes/rest-api/v2/class-ld-rest-users-groups-controller.php
  • includes/rest-api/v2/class-ld-rest-users-course-progress-controller.php
  • includes/settings/settings-metaboxes/class-ld-settings-metabox-course-display-content.php
  • src/Core/Modules/REST/V1/
  • src/Core/Modules/REST/Documentation_Migration/
  • Official documentation: https://developers.learndash.com/
  • Verified source paths:
    • wp-content/plugins/sfwd-lms/includes/rest-api/v2/class-ld-rest-posts-controller.php
    • wp-content/plugins/sfwd-lms/includes/rest-api/v2/class-ld-rest-courses-controller.php

Signals

GitHub stars
22
Forks
2
Last commit
Sep 2026
Advanced
Catalog kind
skill
Gateway key
learndash-rest-api
Source
github.com/lonsdale201/wp-agent-skills