Connecting an LMS is a two-sided handshake. First you register TutorFlow as an external tool inside your LMS and collect the values the LMS assigns. Then you register that LMS on your TutorFlow organization so TutorFlow trusts launches from it.
TutorFlow tool endpoints
Give these URLs to your LMS when you create the external tool.
| LMS field | Value |
|---|---|
| OpenID Connect Initiation URL (login) | https://api.tutorflow.io/v1/platform/lti/login at first; https://api.tutorflow.io/v1/platform/lti/login/{registrationId} once the registration exists (see Step 4) |
| Redirect URI / Launch URL / Target Link URI | https://api.tutorflow.io/v1/platform/lti/launch |
| Public keyset URL (JWKS) | https://api.tutorflow.io/v1/platform/lti/.well-known/jwks.json |
The redirect and JWKS URLs are the same for every organization. The login URL has two forms. The LMS usually asks for a login URL before it gives you the client ID, and TutorFlow can only create the registration once it has that client ID, so use the generic /v1/platform/lti/login in Step 1. After Step 3, replace it with the registration's own login URL.
TutorFlow requests these LTI Advantage scopes: Deep Linking, Assignment and Grade Services (line items + scores), and Names and Role Provisioning. Enable them when the LMS asks which services the tool may use.
Step 1: Register TutorFlow in your LMS
Canvas
- As a Canvas admin, open Admin → Developer Keys → + Developer Key → + LTI Key.
- Choose Method: Manual Entry and fill in:
- Target Link URI:
https://api.tutorflow.io/v1/platform/lti/launch - OpenID Connect Initiation Url:
https://api.tutorflow.io/v1/platform/lti/login(you replace it in Step 4) - JWK Method: Public JWK URL →
https://api.tutorflow.io/v1/platform/lti/.well-known/jwks.json
- Target Link URI:
- Under LTI Advantage Services, turn on line items, scores, results, and membership.
- Add a placement:
Assignment Selectionand/orLink Selection(these enable the content picker). - Save, then set the key's state to ON. Copy the Client ID (a long number).
Moodle
- As a Moodle admin, go to Site administration → Plugins → Activity modules → External tool → Manage tools → configure a tool manually.
- Fill in:
- Tool URL:
https://api.tutorflow.io/v1/platform/lti/launch - LTI version: LTI 1.3
- Public key type: Keyset URL →
https://api.tutorflow.io/v1/platform/lti/.well-known/jwks.json - Initiate login URL:
https://api.tutorflow.io/v1/platform/lti/login(you replace it in Step 4) - Redirection URI(s):
https://api.tutorflow.io/v1/platform/lti/launch
- Tool URL:
- Under Services, enable IMS LTI Assignment and Grade Services and IMS LTI Names and Role Provisioning. Under Privacy, share the launcher's name and email "Always".
- Enable Supports Deep Linking (Content-Item Message).
- Save. Open the tool's configuration details and copy the Client ID, Platform ID (issuer), Authentication request URL, Access token URL, and Public keyset URL.
Step 2: Collect the LMS values
To register the LMS on TutorFlow you need five values from the LMS:
| Value | Canvas | Moodle |
|---|---|---|
issuer | https://canvas.instructure.com (your Canvas URL) | Platform ID |
clientId | Developer Key Client ID | Client ID |
authorizationEndpoint | https://<canvas-host>/api/lti/authorize_redirect | Authentication request URL |
tokenEndpoint | https://<canvas-host>/login/oauth2/token | Access token URL |
jwksEndpoint | https://<canvas-host>/api/lti/security/jwks | Public keyset URL |
Step 3: Register the LMS on your TutorFlow organization
Organization admins can register the LMS on the LMS Integration (LTI) page of the organization settings, or through the admin API with a signed-in TutorFlow admin session (cookie name jwt), as below.
Set the base URL:
export TUTORFLOW_API_BASE_URL="https://api.tutorflow.io"Find your organization ID:
curl "$TUTORFLOW_API_BASE_URL/v1/content/organizations" \
-b tutorflow-admin.cookies[
{ "id": "00000000-0000-4000-8000-000000000001", "name": "Customer Academy", "role": "ADMIN" }
]Register the LMS (organization admins only):
curl -X POST \
"$TUTORFLOW_API_BASE_URL/v1/admin/organizations/00000000-0000-4000-8000-000000000001/lti/registrations" \
-b tutorflow-admin.cookies \
-H "Content-Type: application/json" \
-d '{
"name": "Acme University Canvas",
"issuer": "https://canvas.instructure.com",
"clientId": "10000000000042",
"authorizationEndpoint": "https://acme.instructure.com/api/lti/authorize_redirect",
"tokenEndpoint": "https://acme.instructure.com/login/oauth2/token",
"jwksEndpoint": "https://acme.instructure.com/api/lti/security/jwks"
}'Response:
{
"id": "6f2b7f1e-9c1a-4b2e-8f0d-2b8f6f1a2c3d",
"organizationId": "00000000-0000-4000-8000-000000000001",
"classroomId": null,
"name": "Acme University Canvas",
"issuer": "https://canvas.instructure.com",
"clientId": "10000000000042",
"status": "ACTIVE",
"loginInitiationPath": "/v1/platform/lti/login/6f2b7f1e-9c1a-4b2e-8f0d-2b8f6f1a2c3d"
}loginInitiationPath is this registration's own login URL path. Prefix it with https://api.tutorflow.io for the next step.
Optional: scope a registration to one classroom
Pass classroomId to limit what an LMS can deep link and launch to a single classroom. Omit it to let the registration reach every classroom in the organization.
-d '{ "name": "...", "issuer": "...", "clientId": "...", "authorizationEndpoint": "...", "tokenEndpoint": "...", "jwksEndpoint": "...", "classroomId": "<classroom-uuid>" }'Manage registrations
# List
curl "$TUTORFLOW_API_BASE_URL/v1/admin/organizations/<orgId>/lti/registrations" -b tutorflow-admin.cookies
# Update (any subset of fields)
curl -X PATCH "$TUTORFLOW_API_BASE_URL/v1/admin/organizations/<orgId>/lti/registrations/<registrationId>" \
-b tutorflow-admin.cookies -H "Content-Type: application/json" \
-d '{ "name": "Renamed" }'
# Deactivate
curl -X DELETE "$TUTORFLOW_API_BASE_URL/v1/admin/organizations/<orgId>/lti/registrations/<registrationId>" \
-b tutorflow-admin.cookiesStep 4: Switch to the registration's own login URL
Go back to the tool in your LMS and replace the login URL from Step 1 with the registration's own URL:
https://api.tutorflow.io/v1/platform/lti/login/{registrationId}The LMS Integration (LTI) settings page shows this URL under each registration, with a copy button. The API returns it as loginInitiationPath. In Canvas it is the developer key's OpenID Connect Initiation Url; in Moodle, the tool's Initiate login URL.
A launch through this URL resolves to that registration only. With the generic URL, TutorFlow looks up the registration by issuer and client ID, and refuses the launch if more than one registration matches, so a registration with the same values in another organization could block your launches. The per-registration URL cannot be blocked that way. The generic URL keeps working while exactly one registration matches.
Step 5: Confirm the launch
In your LMS course, add the tool as an external activity, open it as a test student, and confirm you are handed into a TutorFlow classroom. Then continue to Deep Linking to insert specific content.
Troubleshooting registration
- "Multiple LTI registrations match issuer and this client_id": the LMS used the generic login URL, and the same issuer and client ID are registered more than once (for example on both a classroom app and the Agent Platform, or in another organization). Set the LMS login URL to the registration's own URL from Step 4.
- Launch shows "We couldn't verify this LTI session": the launch expired (sessions last ~10 minutes) or the LMS clock/keys changed. Re-launch from the LMS. If it persists, confirm the
jwksEndpointvalue is correct.