Grow LMS API Documentation
Grow by Plenum — Pull-Based Data Access
Querying Grow directly for the records your systems need, on your schedule.
This document is for engineers building the pull side of a Grow integration: scheduled extracts into a data warehouse, on-demand lookups, and the reconciliation process that backs up real-time webhooks. It is the companion to Real-Time Data: Webhooks — together they cover the full push/pull picture. It assumes you’ve read Authentication & Access Setup, since every request here uses the token described there.
Throughout, <SCHOOL_ID> is your dedicated Grow environment and <ACCESS_TOKEN> is your bearer token. No live data appears in this document. Plenum provides the exact endpoint paths for your environment at onboarding; this document describes what’s available and how it behaves.
1. The short version
Where webhooks push events to you the moment they happen, the API lets you pull the current state of any record whenever you want it. Use pull for three things:
- Scheduled extracts — load completions, certificates, and enrollments into your warehouse on whatever cadence your reporting needs.
- On-demand lookups — answer a specific question (“what’s this learner’s status across all required courses?”) in real time.
- Reconciliation — replay anything your webhook receiver may have missed during downtime, so push and pull together give you a complete, gap-free record (Section 5).
Every request is an authenticated HTTPS call to your environment and returns JSON. The same two credentials from the Authentication doc apply to every call: the Pl-Client header identifying your client, and Authorization: Bearer <ACCESS_TOKEN>.
2. How requests work
A pull request is a GET against your environment, carrying your credentials:
curl "https://<SCHOOL_ID>/admin/api/v2/<resource>?page=1" \
-H "Pl-Client: <CLIENT_ID>" \
-H "Authorization: Bearer <ACCESS_TOKEN>"
Responses are JSON and carry the same success boolean envelope you saw for authentication, so your client can branch on success directly rather than inferring outcome from HTTP status alone. Collection responses (lists of records) are paginated — see Section 4.
3. The record catalog
These are the records a compliance-integration consumes. (Grow exposes more — commerce, community, marketing — but those aren’t relevant to a workforce-training program and are omitted here.)
| Record | What you pull it for | Key fields you’ll consume |
|---|---|---|
| Learner progress | The heart of compliance reporting: who has completed what | status (not_started / completed / not_completed), progress_rate, average_score_rate, time_on_course, completed_units / total_units, completed_at — available per course and broken down per section and per unit |
| Enrollments | Who currently has access to which course/program | created (access granted) and expires (access ends) — both Unix timestamps; expires may be null for non-expiring access |
| Certificates | Issued credentials, for credential records and renewal clocks | certificate id, title, type, issued timestamp, score, status |
| Assessment grades | The score behind a completion — part of the compliance audit record | course grades and per-assessment responses, including submitted answers and scoring |
| Learner records | Identity and the attributes you report by | identity + contact, tags, custom fields, role level, attribution |
| Course catalog | Reference data to join everything else against | course id, title, access state, created / modified timestamps |
| Event log | The chronological record of everything that happened — your reconciliation source | per-event activity, timestamp, and the associated user/course (Section 5) |
One distinction worth holding onto. Completion and access are different records with different timestamps. Completion lives on the progress record (
completed_at, empty until the learner actually finishes). Access lives on the enrollment record (createdwhen granted,expireswhen it ends). A learner can be enrolled (has access) without having completed, and can have completed a course whose enrollment later expires. Key compliance logic offcompleted_at; key access logic off the enrollment window.
4. Pagination
Collection endpoints return one page at a time, with a meta block describing where you are:
{
"meta": {
"page": 1,
"totalItems": 1280,
"totalPages": 26,
"itemsPerPage": 50
},
"data": [ /* records */ ],
"success": true
}
To pull a full collection, request page=1 and continue incrementing until page reaches totalPages. Page size varies by endpoint (the event log, for example, returns 50 per page). Write your extractor to read totalPages from the response rather than assuming a fixed count.
5. The reconciliation pattern (event log)
This is the most important pull capability for a robust integration, so it gets its own section.
Webhooks are real-time but not a system of record — if your receiver is down for ten minutes, those deliveries are gone from its perspective. The event log closes that gap. It’s a queryable, chronological log of activity in your environment, and you replay it to catch up on anything you missed.
The event log is filterable, and multiple filters combine with AND:
| Filter | Purpose |
|---|---|
activity |
Restrict to a specific activity type. The compliance-relevant values include complete_course, award_certificate, manual_enrollment, and visit_course. Omit to get all activity. |
created_after |
Only events after this moment (Unix timestamp) — your incremental watermark. |
created_before |
Only events before this moment (Unix timestamp) — bound the window. |
sort |
asc or desc by creation time. |
Worked example — backfill after downtime. Say your webhook receiver was offline from 1751290000 to 1751299200. To recover every completion and certificate in that window:
curl "https://<SCHOOL_ID>/admin/api/v2/eventlogs?activity=complete_course&created_after=1751290000&created_before=1751299200&sort=asc&page=1" \
-H "Pl-Client: <CLIENT_ID>" \
-H "Authorization: Bearer <ACCESS_TOKEN>"
Page through the result (Section 4), apply the same idempotent handling your webhook path uses, and you’ve reconciled the gap with certainty. Repeat for award_certificate (or omit activity to sweep everything at once).
Steady-state incremental pulls. Even without an outage, the same mechanism powers an efficient nightly sync: store the timestamp of the last event you processed, and on each run pull created_after=<last_watermark>. You move only new activity, not the whole history.
6. Putting push and pull together
A dependable production integration uses both paths for what each does best:
- Webhooks for timeliness — react to a completion or certificate within seconds.
- Scheduled pulls for bulk state — load full snapshots of progress, enrollments, and certificates on your reporting cadence.
- Event-log replay for guarantees — periodic reconciliation (and post-outage recovery) so nothing is ever permanently missed.
Because both paths describe the same records with the same fields, data arriving by webhook and data arriving by pull reconcile cleanly against each other.
7. Where to go next
- Real-Time Data: Webhooks — the push counterpart to this document.
- Authentication & Access Setup — the token and headers every call here uses.
- Data Schema Reference — field-level detail for the progress, enrollment, certificate, and user records described above.
Prepared by Plenum Solutions for your evaluation. “Grow by Plenum” is operated and supported by Plenum on your behalf. For integration design support, contact your Plenum engagement lead.


