# Praesidium APIs # Event Publishing Specification This document provides the build specification to clients who wish to receive learning event notifications programmatically. #### Changelog
2023-03-15 | Added several refX fields to event\_specific\_detail |
2023-01-20 | Clarified meaning of UUID in eventContext Corrected typo in learning\_path\_completed sample payload |
2022-12-20 | Added LEARNING\_PATH\_COMPLETED event type |
2022-12-13 | Corrected payload property names from camel case to snake case |
2022-01-12 | Added first\_name and last\_name fields to COURSE\_COMPLETED payload in event\_specific\_detail to aid with the resolution of matching errors |
Note that the url parameter is optional. When present, the current client event publishing endpoint will be changed to the url value in the payload and will be the endpoint used until it is changed again.
**Sample Response (HTTP 200)** ```JSON { "message": "success" } ``` # User Management REST API This document details the RESTful API methods available to manage users for Praesidium clients. #### Changelog2024-08-18 | - Added note about ignoring duplicate requests |
2023-10-30 | - Addition of content removal capabilities to the API - New Endpoint for removal of content from User - Addition of content re-enrollment capabilities to the API - New Endpoint for re-enrollment content in User - Updated the "Create a new user" notes to explain changes to the functionality of the HTTP 400 errors that may occur. - For "Create a new user", added a note about Academy requiring unique emails |
2023-01-18 | - Added examples with and without content specification - Updated general object structure to specify some fields as optional/ignored - Noted lack of content return from GET - Noted which UUIDs will be provided by Praesidium and the general format in which they will be provided |
2022-10-18 | - Added content enrollment to API - User Creation & Update impacted - New endpoint for enrollment of User in content - added content into structure of User object - Clarification of JWT expiration timeframe |
2021-05-18 | - Added instructions on how to use refresh token - changed field name "program-type" in user object to "program\_type" for consistency |
2021-02-26 | - Added structure of User Object - Endpoint URLs updated - Sample requests updated to match structure and to use properly formatted UUIDs - Clarified return value of creation endpoint - Fixed typo in authentication success response - Role details and descriptions added |
**Unless otherwise specified, all services require the JWT token to be passed in the Authorization: Bearer header**
**In addition to all other potential error messages listed below, any endpoint may return HTTP 429 Too Many Requests. If this code is returned, a Retry-After header will be attached to the message to indicate how long to wait before retrying the request.**
**Any duplicate requests to change data (e.g. Create, Update, Deactivate, Enroll) within 30 seconds will be ignored.**
#### AuthenticationJWT expiration is 900 seconds (15 minutes)
**URL** | /portal/authenticate/login\_api |
**Method** | POST |
**Data Format** | ```JSON
{
"grant_type": "client_credentials",
"client_id": " |
**Success Response** | **HTTP Status Code: 200**
```JSON
{
"access_token": " |
**Failure Response** | Authentication Error **HTTP Status Code:** 401 Authorization Required ```JSON { "error": "invalid_client", "error_description": "[string]", "expires_uri": "[reserved for future use]" } ``` Input Validation Error **HTTP Status Code:** 400 Bad Request ```JSON { "error": "invalid_request", "error_description": "[string]", "expires_uri": "[reserved for future use]" } ``` Invalid Scope Error **HTTP Status Code:** 400 Bad Request ```JSON { "error": "invalid_client", "error_description": "[string]", "expires_uri": "[reserved for future use]" } ``` |
**Example** | ```JavaScript // JQuery $.ajax({ url: "/portal/authenticate/login_api", dataType: "json", data: { "grant_type": "client_credentials", "client_id": "xyz_client", "client_secret": "itsasecret", "scope": [ "prae.client.api.user" ] }, type: "POST", success: function( r ) { console.log( r ); } }); ``` |
When using a POST to create a user, the UUID field at the top level is optional.
The "content" object under the "context" object is optional when passing a user object to POST for creation or PUT for general update
In addition, the "content" object will never be specified in a return value from an API call for performance reasons
The UUIDs under "client", "locations" and "content" will be provided by Praesidium (csv file will contain UUID, name for client and locations, and will additionally contain content\_type and SKU for courses/learning paths)
##### Retrieve a User Record**URL** | /portal/lms\_api/v2/user/{UUID} |
**Method** | GET |
**Path Parameters** | Required **UUID** - UUID for the desired user |
**Success Response** | **HTTP Status Code: 200** User object (structure as described above) |
**Failure Response** | Input Validation Error **HTTP Status Code:** 400 Bad Request ```JSON { "status": [integer], "code": "[string]", "message": "[string]", "technicalMessage": "[string]", "infoURI": "[reserved for future use]" } ``` Not Found Error **HTTP Status Code:** 404 Not Found ```JSON { "status": [integer], "code": "[string]", "message": "[string]", "technicalMessage": "[string]", "infoURI": "[reserved for future use]" } ``` Internal Server Error **HTTP Status Code:** 500 Internal Server Error ```JSON { "status": [integer], "code": "[string]", "message": "[string]", "technicalMessage": "[string]", "infoURI": "[reserved for future use]" } ``` **status** - integer HTTP status **code** - internal error code (if available, otherwise HTTP Status) **message** - Human readable error messages, separated by new lines **technicalMessage** - Human readable error message, separated by new lines, containing technical detail |
**Example** | ```JavaScript // JQuery $.ajax({ url: "/portal/lms_api/v2/user/aaaaaaaa-bbbb-cccc-dddd-5ce2287baaa", type: "GET", success: function( r ) { console.log( r ); } }); ``` |
Upon creation, the user will be automatically enrolled in any content included in the payload
Email addresses must be unique across all Academy.
If an attempt is made to create a user with an email that already exists in Academy, the technicalMessage property of the HTTP 400 error will now contain the id of the user with the existing email IF that user falls under the requesting client's hierarchy.
**URL** | /portal/lms\_api/v2/user |
**Method** | POST |
**Data Parameters** | Required User object (structured as above). **Any value in the UUID field will be ignored**. |
**Success Response** | **HTTP Status Code: 201** User object (structure as described above). **The UUID field will contain the UUID of the newly created user** |
**Failure Response** | Input Validation Error **HTTP Status Code:** 400 Bad Request ```JSON { "status": [integer], "code": "[string]", "message": "[string]", "technicalMessage": "[string]", "infoURI": "[reserved for future use]" } ``` Internal Server Error **HTTP Status Code:** 500 Internal Server Error ```JSON { "status": [integer], "code": "[string]", "message": "[string]", "technicalMessage": "[string]", "infoURI": "[reserved for future use]" } ``` **status** - integer HTTP status **code** - internal error code (if available, otherwise HTTP Status) **message** - Human readable error messages, separated by new lines **technicalMessage** - Human readable error message, separated by new lines, containing technical detail |
**Example** | ```JavaScript
// JQuery (without content)
$.ajax({
url: "/portal/lms_api/v2/user",
type: "POST",
dataType: "json",
data: {
"principal": {
"first_name": "John",
"last_name": "Smith",
"email": "jsmith@example.com",
"client_external_id": "123456958"
},
"system": {
"status": "active",
"role": "Administrator - View Only"
},
"person": {},
"context": {
"client": "aaaaaaaa-bbbb-cccc-dddd-5ce2287baaa",
"locations": [
"aaaaaaaa-bbbb-cccc-dddd-5ce1207baaa"
]
},
"attributes": {
"position": "director (camp)",
"program_type": "aquatics"
}
},
success: function( r ) {
console.log( r );
}
});
// JQuery (with content) $.ajax({ url: "/portal/lms_api/v2/user", type: "POST", dataType: "json", data: { "principal": { "first_name": "John", "last_name": "Smith", "email": "jsmith@example.com", "client_external_id": "123456958" }, "system": { "status": "active", "role": "Administrator - View Only" }, "person": {}, "context": { "client": "aaaaaaaa-bbbb-cccc-dddd-5ce2287baaa", "locations": [ "aaaaaaaa-bbbb-cccc-dddd-5ce1207baaa" ] }, "attributes": { "position": "director (camp)", "program_type": "aquatics" } }, success: function( r ) { console.log( r ); } }); ``` |
**URL** | /portal/lms\_api/v2/user/{UUID} |
**Method** | PUT |
**Path Parameters** | Required **UUID** UUID for the user to be updated |
**Data Parameters** | Required User object (structured as above). |
**Success Response** | **HTTP Status Code: 200** User object (structure as described above). |
**Failure Response** | Authorization Error **HTTP Status Code:** 403 ```JSON { "status": [integer], "code": "[string]", "message": "[string]", "technicalMessage": "[string]", "infoURI": "[reserved for future use]" } ``` Input Validation Error **HTTP Status Code:** 400 Bad Request ```JSON { "status": [integer], "code": "[string]", "message": "[string]", "technicalMessage": "[string]", "infoURI": "[reserved for future use]" } ``` Not Found Error **HTTP Status Code:** 404 Not Found ```JSON { "status": [integer], "code": "[string]", "message": "[string]", "technicalMessage": "[string]", "infoURI": "[reserved for future use]" } ``` Internal Server Error **HTTP Status Code:** 500 Internal Server Error ```JSON { "status": [integer], "code": "[string]", "message": "[string]", "technicalMessage": "[string]", "infoURI": "[reserved for future use]" } ``` **status** - integer HTTP status **code** - internal error code (if available, otherwise HTTP Status) **message** - Human readable error messages, separated by new lines **technicalMessage** - Human readable error message, separated by new lines, containing technical detail |
**Example** | ```JavaScript
// JQuery (without content)
$.ajax({
url: "/portal/lms_api/v2/user/aaaaaaaa-bbbb-cccc-dddd-5ce9942baaa",
type: "PUT",
dataType: "json",
data: {
"principal": {
"first_name": "John",
"last_name": "Smith",
"email": "jsmith@example.com",
"client_external_id": "123456958"
},
"system": {
"status": "active",
"role": "Administrator - View Only"
},
"person": {},
"context": {
"client": "aaaaaaaa-bbbb-cccc-dddd-5ce2287baaa",
"locations": [
"aaaaaaaa-bbbb-cccc-dddd-5ce1207baaa"
]
},
"attributes": {
"position": "director (camp)",
"program_type": "aquatics"
}
},
success: function( r ) {
console.log( r );
}
});
// JQuery (with content) $.ajax({ url: "/portal/lms_api/v2/user/aaaaaaaa-bbbb-cccc-dddd-5ce9942baaa", type: "PUT", dataType: "json", data: { "principal": { "first_name": "John", "last_name": "Smith", "email": "jsmith@example.com", "client_external_id": "123456958" }, "system": { "status": "active", "role": "Administrator - View Only" }, "person": {}, "context": { "client": "aaaaaaaa-bbbb-cccc-dddd-5ce2287baaa", "locations": [ "aaaaaaaa-bbbb-cccc-dddd-5ce1207baaa" ] }, "attributes": { "position": "director (camp)", "program_type": "aquatics" } }, success: function( r ) { console.log( r ); } }); ``` |
**URL** | /portal/lms\_api/v2/user/{UUID}/deactivate |
**Method** | PUT |
**Path Parameters** | Required **UUID** - UUID for the desired user |
**Success Response** | **HTTP Status Code: 200** User object (structure as described above) |
**Failure Response** | Authorization Error **HTTP Status Code:** 403 ```JSON { "status": [integer], "code": "[string]", "message": "[string]", "technicalMessage": "[string]", "infoURI": "[reserved for future use]" } ``` Input Validation Error **HTTP Status Code:** 400 Bad Request ```JSON { "status": [integer], "code": "[string]", "message": "[string]", "technicalMessage": "[string]", "infoURI": "[reserved for future use]" } ``` Not Found Error **HTTP Status Code:** 404 Not Found ```JSON { "status": [integer], "code": "[string]", "message": "[string]", "technicalMessage": "[string]", "infoURI": "[reserved for future use]" } ``` Internal Server Error **HTTP Status Code:** 500 Internal Server Error ```JSON { "status": [integer], "code": "[string]", "message": "[string]", "technicalMessage": "[string]", "infoURI": "[reserved for future use]" } ``` **status** - integer HTTP status **code** - internal error code (if available, otherwise HTTP Status) **message** - Human readable error messages, separated by new lines **technicalMessage** - Human readable error message, separated by new lines, containing technical detail |
**Example** | ```JavaScript // JQuery $.ajax({ url: "/portal/lms_api/v2/user/aaaaaaaa-bbbb-cccc-dddd-5ce2287baaa/deactivate", type: "PUT", success: function( r ) { console.log( r ); } }); ``` |
**URL** | /portal/lms\_api/v2/user/{UUID}/enrollContent |
**Method** | PUT |
**Path Parameters** | Required **UUID** UUID for the user to be updated |
**Data Parameters** | Required Content Listing (structured as below). ```JSON { "content": [ { "uuid": "[string]", "type": "[string]" }, ..., ] } ``` **uuid** - course UUID (Praesidium provided) **type** - only the values "course" and "learning path" are available |
**Success Response** | **HTTP Status Code: 200** User object (structure as described above). |
**Failure Response** | Authorization Error **HTTP Status Code:** 403 ```JSON { "status": [integer], "code": "[string]", "message": "[string]", "technicalMessage": "[string]", "infoURI": "[reserved for future use]" } ``` Input Validation Error **HTTP Status Code:** 400 Bad Request ```JSON { "status": [integer], "code": "[string]", "message": "[string]", "technicalMessage": "[string]", "infoURI": "[reserved for future use]" } ``` Not Found Error **HTTP Status Code:** 404 Not Found ```JSON { "status": [integer], "code": "[string]", "message": "[string]", "technicalMessage": "[string]", "infoURI": "[reserved for future use]" } ``` Internal Server Error **HTTP Status Code:** 500 Internal Server Error ```JSON { "status": [integer], "code": "[string]", "message": "[string]", "technicalMessage": "[string]", "infoURI": "[reserved for future use]" } ``` **status** - integer HTTP status **code** - internal error code (if available, otherwise HTTP Status) **message** - Human readable error messages, separated by new lines **technicalMessage** - Human readable error message, separated by new lines, containing technical detail |
**Example** | ```JavaScript // JQuery $.ajax({ url: "/portal/lms_api/v2/user/aaaaaaaa-bbbb-cccc-dddd-5ce9942baaa/enrollContent", type: "PUT", dataType: "json", data: { "content": [ { "uuid": "aaaaaaaa-bbbb-cccc-dddd-5ce1248baaa", "type": "course" } ] }, success: function( r ) { console.log( r ); } }); ``` |
**URL** | /portal/lms\_api/v2/user/{UUID}/removeContent |
**Method** | PUT |
**Path Parameters** | Required **UUID** UUID for the user to be updated |
**Data Parameters** | Required Content Listing (structured as below). ```JSON { "content": [ { "uuid": "[string]", "type": "[string]" }, ..., ] } ``` **uuid** - course UUID (Praesidium provided) **type** - only the values "course" and "learning path" are available |
**Success Response** | **HTTP Status Code: 200** User object (structure as described above). |
**Failure Response** | Authorization Error **HTTP Status Code:** 403 ```JSON { "status": [integer], "code": "[string]", "message": "[string]", "technicalMessage": "[string]", "infoURI": "[reserved for future use]" } ``` Input Validation Error **HTTP Status Code:** 400 Bad Request ```JSON { "status": [integer], "code": "[string]", "message": "[string]", "technicalMessage": "[string]", "infoURI": "[reserved for future use]" } ``` Not Found Error **HTTP Status Code:** 404 Not Found ```JSON { "status": [integer], "code": "[string]", "message": "[string]", "technicalMessage": "[string]", "infoURI": "[reserved for future use]" } ``` Internal Server Error **HTTP Status Code:** 500 Internal Server Error ```JSON { "status": [integer], "code": "[string]", "message": "[string]", "technicalMessage": "[string]", "infoURI": "[reserved for future use]" } ``` **status** - integer HTTP status **code** - internal error code (if available, otherwise HTTP Status) **message** - Human readable error messages, separated by new lines **technicalMessage** - Human readable error message, separated by new lines, containing technical detail |
**Example** | ```JavaScript // JQuery $.ajax({ url: "/portal/lms_api/v2/user/aaaaaaaa-bbbb-cccc-dddd-5ce9942baaa/removeContent", type: "PUT", dataType: "json", data: { "content": [ { "uuid": "aaaaaaaa-bbbb-cccc-dddd-5ce1248baaa", "type": "course" } ] }, success: function( r ) { console.log( r ); } }); ``` |
**URL** | /portal/lms\_api/v2/user/{UUID}/reEnrollContent |
**Method** | PUT |
**Path Parameters** | Required **UUID** UUID for the user to be updated |
**Data Parameters** | Required Content Listing (structured as below). ```JSON { "content": [ { "uuid": "[string]", "type": "[string]" }, ..., ] } ``` **uuid** - course UUID (Praesidium provided) **type** - only the values "course" and "learning path" are available |
**Success Response** | **HTTP Status Code: 200** User object (structure as described above). |
**Failure Response** | Authorization Error **HTTP Status Code:** 403 ```JSON { "status": [integer], "code": "[string]", "message": "[string]", "technicalMessage": "[string]", "infoURI": "[reserved for future use]" } ``` Input Validation Error **HTTP Status Code:** 400 Bad Request ```JSON { "status": [integer], "code": "[string]", "message": "[string]", "technicalMessage": "[string]", "infoURI": "[reserved for future use]" } ``` Not Found Error **HTTP Status Code:** 404 Not Found ```JSON { "status": [integer], "code": "[string]", "message": "[string]", "technicalMessage": "[string]", "infoURI": "[reserved for future use]" } ``` Internal Server Error **HTTP Status Code:** 500 Internal Server Error ```JSON { "status": [integer], "code": "[string]", "message": "[string]", "technicalMessage": "[string]", "infoURI": "[reserved for future use]" } ``` **status** - integer HTTP status **code** - internal error code (if available, otherwise HTTP Status) **message** - Human readable error messages, separated by new lines **technicalMessage** - Human readable error message, separated by new lines, containing technical detail |
**Example** | ```JavaScript // JQuery $.ajax({ url: "/portal/lms_api/v2/user/aaaaaaaa-bbbb-cccc-dddd-5ce9942baaa/reEnrollContent", type: "PUT", dataType: "json", data: { "content": [ { "uuid": "aaaaaaaa-bbbb-cccc-dddd-5ce1248baaa", "type": "course" } ] }, success: function( r ) { console.log( r ); } }); ``` |