Prerequisites: API access and webhooks
Before the integration can do anything, a few things need to be in place: a way to retrieve information from Eduframe and a way to subscribe to data changes. This page explains what to configure first.
1. Create a service user and API key
API keys in Eduframe belong to a person. Create a dedicated administrator called, for example, LMS integration, log in as that user and create the key there. Removing a colleague from Eduframe will then never break your LMS sync. Follow Create an API key for the exact steps.
Give the key only the scopes you need:
| Capability | Scopes |
|---|---|
| Sync courses and editions | courses:read |
| Sync participants | relations:read; relations:modify to set principal IDs |
| Sync teachers | teachers:read, courses:read |
| Sync enrollments | enrollments:read |
| Set the LMS course link on an edition | courses:modify |
| Send grades to Eduframe | enrollments:modify |
| Register webhooks through the API | settings:modify |
| Inspect webhook notifications and failed deliveries | settings:read |
Requests are authenticated with the key as a bearer token:
GET /api/v1/planned_courses HTTP/1.1
Host: api.eduframe.nl
Authorization: Bearer <your api key>
The Admin API is documented at developer.eduframe.com. Read the Overview section there for pagination (follow the Link header, up to 100 records per page), sorting, filtering and the current rate limits.
2. Register a webhook
Webhooks tell your middleware that something changed so you do not have to poll. Register one endpoint in Settings → Webhooks or through POST /webhooks, and subscribe it to the events listed in each of the sync guides. The full list of events, the payload format and the admin UI are described in How to configure a webhook.
Every notification is signed. Verify the signature before you act on it, as explained in How to authenticate a webhook, and read How to validate a webhook for retry behaviour and how to inspect failed deliveries.
Eduframe waits at most 10 seconds for your endpoint to respond. Acknowledge the notification immediately, put it on a queue and do the actual work asynchronously. If you do not respond in time, Eduframe tries again 5 minutes later, up to three attempts in total.
3. Ask for the feature flags you need
Some attributes are behind a feature flag on your Eduframe environment. For an LMS integration you may need:
| Feature flag | Used for |
|---|---|
| Course edition external link | Storing the LMS course URL on a planned course, shown in the participant portal. |
| Departments | Only if you chose to mirror Eduframe departments into the LMS hierarchy, see Decisions. |
| Manage principal ids | Identifying users by their principal ID, see Sync users. |
Ask support@eduframe.com to enable them. Endpoints that depend on a flag carry a green badge in the API reference.
4. Store Eduframe IDs in your LMS
Your middleware has to remember which LMS course belongs to which Eduframe planned course, and which LMS user belongs to which Eduframe user. Most LMSs have a field meant exactly for this: an external ID or SIS ID that the LMS itself never changes and that its API can look records up by. Use it. It makes every sync step an upsert (look up by the key, create if missing, otherwise update), it survives redeploys of your middleware, and it lets administrators trace any LMS record back to Eduframe.
For courses, use the planned course id. If you share your LMS instance with other systems and want to avoid key conflicts, add a short prefix, for example eduframe-planned-course-4211. For users, use the principal ID rather than the Eduframe id, see Identify users by their principal ID. Never use names, emails or dates as the key, since those can change.
| LMS | Course field | User field | Look up by external ID |
|---|---|---|---|
| Moodle | idnumber on the course | idnumber on the user | core_course_get_courses_by_field with field=idnumber; core_user_get_users_by_field with field=idnumber |
| Blackboard Learn | externalId on the course | externalId on the user | Any course or user path accepts the prefix form, e.g. GET /learn/api/public/v3/courses/externalId:eduframe-planned-course-4211 |
| Canvas | sis_course_id | sis_user_id | GET /api/v1/courses/sis_course_id:<id>, GET /api/v1/users/sis_user_id:<id> |
| Brightspace | Code on the course offering | OrgDefinedId on the user | Org unit and user lookups filter on these fields |
Moodle example, creating a course that carries the Eduframe id:
wsfunction=core_course_create_courses
courses[0][fullname]=Project management basics - 2026-10-05
courses[0][shortname]=PMB-2026-10-05
courses[0][categoryid]=12
courses[0][idnumber]=eduframe-planned-course-4211
Blackboard example, enrolling a user by the planned course id and the user's principal ID, without ever knowing the Blackboard primary keys:
PUT /learn/api/public/v1/courses/externalId:eduframe-planned-course-4211/users/externalId:e3b0c442-98fc-4d5e-9a1b-7c2f0d1a6b8e
Content-Type: application/json
{ "courseRoleId": "Student" }
If your LMS has no such field, keep a mapping table in your middleware's own database and treat it as the single source for lookups.
Ask Drieam for a test environment and point the integration at your LMS's sandbox. Webhooks fire for test data exactly like production data.