curl --request POST \
--url https://pria.praxislxp.com/api/auth/getInstitutionsForContextid \
--header 'Content-Type: application/json' \
--data '
{
"ltiContextId": "https://domain.edu/course/123",
"launch": {},
"ticket": "<string>"
}
'import requests
url = "https://pria.praxislxp.com/api/auth/getInstitutionsForContextid"
payload = {
"ltiContextId": "https://domain.edu/course/123",
"launch": {},
"ticket": "<string>"
}
headers = {"Content-Type": "application/json"}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {'Content-Type': 'application/json'},
body: JSON.stringify({ltiContextId: 'https://domain.edu/course/123', launch: {}, ticket: '<string>'})
};
fetch('https://pria.praxislxp.com/api/auth/getInstitutionsForContextid', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://pria.praxislxp.com/api/auth/getInstitutionsForContextid",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'ltiContextId' => 'https://domain.edu/course/123',
'launch' => [
],
'ticket' => '<string>'
]),
CURLOPT_HTTPHEADER => [
"Content-Type: application/json"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://pria.praxislxp.com/api/auth/getInstitutionsForContextid"
payload := strings.NewReader("{\n \"ltiContextId\": \"https://domain.edu/course/123\",\n \"launch\": {},\n \"ticket\": \"<string>\"\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://pria.praxislxp.com/api/auth/getInstitutionsForContextid")
.header("Content-Type", "application/json")
.body("{\n \"ltiContextId\": \"https://domain.edu/course/123\",\n \"launch\": {},\n \"ticket\": \"<string>\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://pria.praxislxp.com/api/auth/getInstitutionsForContextid")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Content-Type"] = 'application/json'
request.body = "{\n \"ltiContextId\": \"https://domain.edu/course/123\",\n \"launch\": {},\n \"ticket\": \"<string>\"\n}"
response = http.request(request)
puts response.read_body[
{
"command": "login",
"publicId": "<string>",
"name": "<string>",
"ainame": "<string>",
"picture": "<string>",
"credits": 123,
"accountName": "<string>",
"reason": "institution_inactive",
"count": 123,
"canManage": true,
"canUnlink": true,
"hidden": true,
"ticket": "<string>"
}
]Get institutions for LTI context
Retrieves institutions associated with a specific LTI context ID — one of four answers (design 2026-09-28 D5): login (a usable twin holds the course), unavailable (the course’s only holder(s) are disabled or account-blocked twins — named to a manager only), hidden (no holder, but a hide row exists), or the caller’s own chooser list (existing/contact). The unavailable/hidden marker is returned ALONE — it is NEVER returned alongside the chooser list, because a held or hidden course is not offered for remapping. Passing the optional launch or ticket lets a manager (a verified in-process LTI 1.3 launch, or the ticket of one, by default) get canManage/canUnlink/ticket on the unavailable/hidden answer instead of the bare block everyone else sees.
curl --request POST \
--url https://pria.praxislxp.com/api/auth/getInstitutionsForContextid \
--header 'Content-Type: application/json' \
--data '
{
"ltiContextId": "https://domain.edu/course/123",
"launch": {},
"ticket": "<string>"
}
'import requests
url = "https://pria.praxislxp.com/api/auth/getInstitutionsForContextid"
payload = {
"ltiContextId": "https://domain.edu/course/123",
"launch": {},
"ticket": "<string>"
}
headers = {"Content-Type": "application/json"}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {'Content-Type': 'application/json'},
body: JSON.stringify({ltiContextId: 'https://domain.edu/course/123', launch: {}, ticket: '<string>'})
};
fetch('https://pria.praxislxp.com/api/auth/getInstitutionsForContextid', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://pria.praxislxp.com/api/auth/getInstitutionsForContextid",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'ltiContextId' => 'https://domain.edu/course/123',
'launch' => [
],
'ticket' => '<string>'
]),
CURLOPT_HTTPHEADER => [
"Content-Type: application/json"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://pria.praxislxp.com/api/auth/getInstitutionsForContextid"
payload := strings.NewReader("{\n \"ltiContextId\": \"https://domain.edu/course/123\",\n \"launch\": {},\n \"ticket\": \"<string>\"\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://pria.praxislxp.com/api/auth/getInstitutionsForContextid")
.header("Content-Type", "application/json")
.body("{\n \"ltiContextId\": \"https://domain.edu/course/123\",\n \"launch\": {},\n \"ticket\": \"<string>\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://pria.praxislxp.com/api/auth/getInstitutionsForContextid")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Content-Type"] = 'application/json'
request.body = "{\n \"ltiContextId\": \"https://domain.edu/course/123\",\n \"launch\": {},\n \"ticket\": \"<string>\"\n}"
response = http.request(request)
puts response.read_body[
{
"command": "login",
"publicId": "<string>",
"name": "<string>",
"ainame": "<string>",
"picture": "<string>",
"credits": 123,
"accountName": "<string>",
"reason": "institution_inactive",
"count": 123,
"canManage": true,
"canUnlink": true,
"hidden": true,
"ticket": "<string>"
}
]Body
LTI context identifier
"https://domain.edu/course/123"
Optional (design 2026-09-28 D3/D5). A freshly signed SDK launch (params/launch_token/nonce/timestamp, as verified by /api/auth/sdk-verify) proving who is asking, for the unavailable/hidden answers below. Only a VERIFIED launch or the ticket of one counts — never the body's email.
A course ticket (from a prior answer here or from sdk-hide) in place of launch. The ticket wins when both are sent.
Response
Institutions retrieved successfully
login — a usable twin already holds this course, sign the caller in. hidden — the course was hidden via /api/auth/sdk-hide. unavailable — a marker (never offered as a choice): the course's only holder(s) are disabled twins. existing — a twin the caller already belongs to. contact — a twin whose contactEmail matches the caller.
login, hidden, unavailable, existing, contact Digital Twin public id (login, existing, contact).
Institution name (existing, contact).
Digital Twin display name (existing, contact; also the unavailable marker's disabled twin name).
Institution picture URL (existing, contact).
Remaining credits (existing, contact).
Parent account name, when the institution has one (existing, contact).
Marker only (unavailable) — why the disabled holder can't be used.
institution_inactive, account_inactive Marker only (unavailable) — how many disabled twins hold this course.
unavailable/hidden only — the caller proved (by launch or ticket) it may manage this course. For unavailable (a held course) that is the SCREEN_TRUST level (design 2026-09-28 D3); for hidden (no holder) it is ANY validly signed teacher launch (usertype > 1) or its ticket — the Hide gate's own level.
unavailable only, and only when canManage is true — the caller may disconnect the disabled twin via /api/auth/sdk-unlink-course under UNLINK_TRUST (never wider than SCREEN_TRUST).
unavailable, canManage only — the held course is ALSO hidden.
unavailable/hidden, canManage only — a 4-hour course ticket for /api/auth/sdk-unlink-course and /api/auth/sdk-hide, so the manager need not re-launch from Canvas. The SAME ticket is handed back when the caller already authenticated by ticket (never renewed).
Was this page helpful?