LearnDash REST API
SkillAI & modelsBuild 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.
No other account needed.
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, orlearndash-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
/stepspayload errors.
Enablement and namespaces
REST availability requires both:
- Constant
LEARNDASH_REST_API_ENABLEDtrue. 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
hrefto 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_readreturns 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}/usersPOST /ldlms/v2/sfwd-courses/{id}/userswithuser_idsDELETE /ldlms/v2/sfwd-courses/{id}/userswithuser_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}/courseswithcourse_ids.- Mutations call
ld_update_course_group_access().
Group users:
GET/POST/DELETE /ldlms/v2/groups/{id}/userswithuser_ids.- Mutations call
ld_update_group_access().
User groups:
GET/POST/DELETE /ldlms/v2/users/{id}/groupswithgroup_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_restwhen 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
- Check REST is enabled in constants and LearnDash settings.
- Discover actual bases from settings or manifest/docs instead of assuming defaults on customized sites.
- Authenticate with Application Password, cookie+nonce, OAuth/JWT layer, or a site-specific auth plugin.
- Fetch course posts and then fetch
/stepsfor the outline. - Use relation endpoints for enrollment/group changes, not raw usermeta.
- Use progress endpoints for progress, not direct activity-table writes.
- Respect pagination, batch limits, and per-item success/failure responses.
- Cache read responses carefully and invalidate on post, access, group, and progress mutations.
Common mistakes to reject
- Guessing
learndash/v1request bodies without first reading manifesthrefdetails. - Hard-coding route bases when LearnDash settings can change them.
- Creating lessons/topics but never updating course steps.
- Sending arrays to
/stepsinstead 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-accessfor final access checks and direct course enrollment semantics. - Use
learndash-group-accessfor group membership and group-course relation behavior. - Use
learndash-woocommerce-accessfor Woo-driven access changes. - Use
learndash-course-progressfor server-side completion, reset, activity, and progress-write behavior. - Use
wp-rest-apifor general WordPress REST security and schema patterns.
References
Validated against LearnDash LMS 5.1.9 local source:
includes/rest-api/class-ld-rest-api.phpincludes/settings/settings-sections/class-ld-settings-section-general-rest-api.phpincludes/rest-api/v2/class-ld-rest-courses-steps-controller.phpincludes/rest-api/v2/class-ld-rest-courses-users-controller.phpincludes/rest-api/v2/class-ld-rest-users-courses-controller.phpincludes/rest-api/v2/class-ld-rest-groups-courses-controller.phpincludes/rest-api/v2/class-ld-rest-groups-users-controller.phpincludes/rest-api/v2/class-ld-rest-users-groups-controller.phpincludes/rest-api/v2/class-ld-rest-users-course-progress-controller.phpincludes/settings/settings-metaboxes/class-ld-settings-metabox-course-display-content.phpsrc/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.phpwp-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