Introduction
Our API lets you integrate Sana into your existing platforms. We're still actively developing the API and will be adding more functionality as we go.
Authentication
Request Access Token
Use client credentials to request access tokens. All requests need to be authenticated using an access token.
The retrieved access token can authenticate requests using the authorization header
like Authorization: Bearer <accessToken>
.
curl "https://<domain>.sana.ai/api/token" \
-X POST \
-H "Content-Type: application/x-www-form-urlencoded" \
-d "grant_type=client_credentials&client_id=<client-id>&client_secret=<client-secret>&scope=read,write" \
The above command returns JSON structured like this:
{
"data": {
"accessToken": "<access-token>",
"tokenType": "bearer",
"expiresIn": 3600
}
}
HTTP Request
POST https://<domain>.sana.ai/api/token
Body Parameters
Parameter | Description |
---|---|
grant_type | Must be set to client_credentials |
client_id | The ID of the client |
client_secret | The secret of the client |
scope | Comma-separated list of scopes. GET requests require read scope. POST , PATCH , and DELETE requests require write scope. |
Users
List All Users
curl "https://<domain>.sana.ai/api/v0/users?limit=1" \
-H "Authorization: Bearer <accessToken>"
The above command returns JSON structured like this:
{
"data": [
{
"id": "eb87a2dc-3e78-4d0b-b868-9d3f49c64f68",
"email": "sana@sanalabs.com",
"firstName": "Sana",
"lastName": "Banana",
"disabled": false,
"customAttributes": {}
}
],
"links": {
"next": "https://<domain>.sana.ai/api/v0/users?next=9399b472-199b-4d18-97d9-819c7e1bf22f&limit=1"
},
"error": null
}
This endpoint retrieves all users
HTTP Request
GET https://<domain>.sana.ai/api/v0/users
Query Parameters
Parameter | Type | Required | Default | Description |
---|---|---|---|---|
next | String | No | - | Set to fetch the next batch of users. |
limit | Integer | No | 100 | The number of users to return. Max: 1000 |
Get a User
curl "https://<domain>.sana.ai/api/v0/users/eb87a2dc-3e78-4d0b-b868-9d3f49c64f68" \
-H "Authorization: Bearer <accessToken>"
The above command returns JSON structured like this:
{
"data": {
"id": "eb87a2dc-3e78-4d0b-b868-9d3f49c64f68",
"email": "sana@sanalabs.com",
"firstName": "Sana",
"lastName": "Banana",
"disabled": false,
"customAttributes": {}
},
"error": null
}
This endpoint retrieves a specific user
HTTP Request
GET https://<domain>.sana.ai/api/v0/users/<userId>
URL Parameters
Parameter | Type | Description |
---|---|---|
userId | String | The ID of the user to retrieve |
Create a User
curl "https://<domain>.sana.ai/api/v0/users" \
-X POST \
-H "Content-Type: application/json" \
-H "Authorization: Bearer <accessToken>" \
-d `{ \
"user": { \
"email": "sana@sanalabs.com", \
"firstName": "Sana", \
"lastName": "Banana" \
} \
}`
The above command returns JSON structured like this:
{
"data": {
"id": "eb87a2dc-3e78-4d0b-b868-9d3f49c64f68",
"email": "sana@sanalabs.com",
"firstName": "Sana",
"lastName": "Banana",
"inviteLink": "https://<domain>.sana.ai/accept-invite?inviteCode=<code>",
"customAttributes": {}
},
"error": null
}
The
inviteLink
should be sent to the user to complete the sign up
This endpoint creates a user
HTTP Request
POST https://<domain>.sana.ai/api/v0/users
Body Parameters
Parameter | Type | Required | Default | Description |
---|---|---|---|---|
String | Yes | - | The user's email address | |
firstName | String | No | - | The first name of the user |
lastName | String | No | - | The last name of the user |
role | String | No | - | One of learner , group-admin or admin |
customAttributes | Map<String, String> | No | - | For storing arbitrary key/value pairs. The keyset needs to be pre-configured. |
Send invite
curl "https://<domain>.sana.ai/api/v0/users/<userId>/send-invite" \
-X POST \
-H "Content-Type: application/json" \
-H "Authorization: Bearer <accessToken>"
This endpoint will generate a new invite link and send it to the user. Calling this endpoint will invalidate the previous invite links.
If called after a user has accepted the invite the request will be rejected.
The endpoint can also reject requests if called too often to prevent sending multiple emails to the same user.
HTTP Request
POST https://<domain>.sana.ai/api/v0/users/<userId>/send-invite
Generate new invite link
curl "https://<domain>.sana.ai/api/v0/users/<userId>/invite-link" \
-X POST \
-H "Content-Type: application/json" \
-H "Authorization: Bearer <accessToken>"
Calling this endpoint will invalidate the previous invite links.
If called after a user has accepted the invite the request will be rejected.
HTTP Request
POST https://<domain>.sana.ai/api/v0/users/<userId>/invite-link
Update a User
curl "https://<domain>.sana.ai/api/v0/users/eb87a2dc-3e78-4d0b-b868-9d3f49c64f68" \
-X PATCH \
-H "Content-Type: application/json" \
-H "Authorization: Bearer <accessToken>"
-d `{ \
"user": { \
"lastName": "Apple" \
} \
}`
The above command returns JSON structured like this:
{
"data": {
"id": "eb87a2dc-3e78-4d0b-b868-9d3f49c64f68",
"email": "sana@sanalabs.com",
"firstName": "Sana",
"lastName": "Apple",
"disabled": false,
"customAttributes": {}
},
"error": null
}
This endpoint updates a specific user.
A user account can be deactivated by setting disabled = true
. This operation can be reversed to reactivate an account
by setting disabled = false
.
HTTP Request
PATCH https://<domain>.sana.ai/api/v0/users/<userId>
URL Parameters
Parameter | Type | Description |
---|---|---|
userId | String | The ID of the user to update |
Body Parameters
Parameter | Type | Required | Default | Description |
---|---|---|---|---|
String | No | - | The user's email address | |
firstName | String | No | - | The first name of the user |
lastName | String | No | - | The last name of the user |
disabled | Boolean | No | - | If set to true the account is deactivated. If set to false the account is reactivated. |
role | String | No | - | One of learner , group-admin or admin |
customAttributes | Map |
No | - | For storing arbitrary key/value pairs. The keyset needs to be pre-configured. |
Delete a User
curl "https://<domain>.sana.ai/api/v0/users/eb87a2dc-3e78-4d0b-b868-9d3f49c64f68" \
-X DELETE \
-H "Authorization: Bearer <accessToken>"
This endpoint deletes a specific user.
HTTP Request
DELETE https://<domain>.sana.ai/api/v0/users/<userId>
URL Parameters
Parameter | Type | Description |
---|---|---|
userId | String | The ID of the user to delete |
List All Groups for a User
curl "https://<domain>.sana.ai/api/v0/users/eb87a2dc-3e78-4d0b-b868-9d3f49c64f68/groups?limit=1" \
-H "Authorization: Bearer <accessToken>"
The above command returns JSON structured like this:
{
"data": [
{
"id": "b3a96b74-1b2e-49da-b5d8-bfa7c7b800be",
"role": "learner"
}
],
"links": {
"next": "https://<domain>.sana.ai/api/v0/users/eb87a2dc-3e78-4d0b-b868-9d3f49c64f68/groups?next=5f4818ba-16d1-43c0-8421-4a1782a999a1&limit=1"
},
"error": null
}
This endpoint retrieves all groups in a specific user
HTTP Request
GET https://<domain>.sana.ai/api/v0/users/<userId>/groups
URL Parameters
Parameter | Description |
---|---|
userId | The ID of the user |
Query Parameters
Parameter | Type | Required | Default | Description |
---|---|---|---|---|
next | String | No | - | Set to fetch the next batch of groups. |
limit | Integer | No | 100 | The number of groups to return. Max: 1000 |
Set user's manager
curl "https://<domain>.sana.ai/api/v0/users/eb87a2dc-3e78-4d0b-b868-9d3f49c64f68/manager/0e9e5c2e-5db4-42e7-a4ed-0d8aebe23094" \
-X PUT \
-H "Authorization: Bearer <accessToken>"
This endpoint sets the user's manager.
Cycles in user manager relationships are not allowed. The request that closes a cycle will be rejected.
HTTP Request
PUT https://<domain>.sana.ai/api/v0/users/<userId>/manager/<managerId>
Delete user's manager
curl "https://<domain>.sana.ai/api/v0/users/eb87a2dc-3e78-4d0b-b868-9d3f49c64f68/manager" \
-X DELETE \
-H "Authorization: Bearer <accessToken>"
This endpoint deletes the user's manager.
HTTP Request
DELETE https://<domain>.sana.ai/api/v0/users/<userId>/manager
Groups
List All Groups
curl "https://<domain>.sana.ai/api/v0/groups?limit=1" \
-H "Authorization: Bearer <accessToken>"
The above command returns JSON structured like this:
{
"data": [
{
"id": "b3a96b74-1b2e-49da-b5d8-bfa7c7b800be",
"name": "The Fruits"
}
],
"links": {
"next": "https://<domain>.sana.ai/api/v0/groups?next=5f4818ba-16d1-43c0-8421-4a1782a999a1&limit=1"
},
"error": null
}
This endpoint retrieves all groups
HTTP Request
GET https://<domain>.sana.ai/api/v0/groups
Query Parameters
Parameter | Type | Required | Default | Description |
---|---|---|---|---|
next | String | No | - | Set to fetch the next batch of groups. |
limit | Integer | No | 100 | The number of groups to return. Max: 1000 |
Get a Group
curl "https://<domain>.sana.ai/api/v0/groups/b3a96b74-1b2e-49da-b5d8-bfa7c7b800be" \
-H "Authorization: Bearer <accessToken>"
The above command returns JSON structured like this:
{
"data": {
"id": "b3a96b74-1b2e-49da-b5d8-bfa7c7b800be",
"name": "The Fruits"
},
"error": null
}
This endpoint retrieves a specific group
HTTP Request
GET https://<domain>.sana.ai/api/v0/groups/<groupId>
URL Parameters
Parameter | Description |
---|---|
groupId | The ID of the group to retrieve |
Create a Group
curl "https://<domain>.sana.ai/api/v0/groups" \
-X POST \
-H "Content-Type: application/json" \
-H "Authorization: Bearer <accessToken>" \
-d `{ \
"group": {
"name": "Fruits" \
"type": "program" \
}
}`
The above command returns JSON structured like this:
{
"data": {
"id": "b3a96b74-1b2e-49da-b5d8-bfa7c7b800be",
"name": "Fruits",
"type": "program"
},
"error": null
}
This endpoint creates a group.
Note: The type attribute is disabled by default, once enabled existing groups will be of type program
.
HTTP Request
POST https://<domain>.sana.ai/api/v0/groups
Body Parameters
Parameter | Type | Required | Default | Description |
---|---|---|---|---|
name | String | Yes | - | The name of the group |
type | Enum | No | program | Type of group: program, user |
Update a Group
curl "https://<domain>.sana.ai/api/v0/users/b3a96b74-1b2e-49da-b5d8-bfa7c7b800be" \
-X PATCH \
-H "Content-Type: application/json" \
-H "Authorization: Bearer <accessToken>"
-d `{ \
"group": { \
"name": "Fruit Loops" \
}
}`
The above command returns JSON structured like this:
{
"data": {
"id": "b3a96b74-1b2e-49da-b5d8-bfa7c7b800be",
"name": "The Fruit Loops",
"type": "program"
},
"error": null
}
This endpoint updates a specific group
HTTP Request
PATCH https://<domain>.sana.ai/api/v0/groups/<groupId>
URL Parameters
Parameter | Type | Description |
---|---|---|
groupId | String | The ID of the group to update |
Body Parameters
Parameter | Type | Required | Default | Description |
---|---|---|---|---|
name | String | No | - | The name of the group |
Delete a Group
curl "https://<domain>.sana.ai/api/v0/groups/b3a96b74-1b2e-49da-b5d8-bfa7c7b800be" \
-X DELETE \
-H "Authorization: Bearer <accessToken>"
This endpoint deletes a specific group
HTTP Request
DELETE https://<domain>.sana.ai/api/v0/groups/<groupId>
URL Parameters
Parameter | Description |
---|---|
groupId | The ID of the group to delete |
List All Users in a Group
curl "https://<domain>.sana.ai/api/v0/groups/b3a96b74-1b2e-49da-b5d8-bfa7c7b800be/users?limit=1" \
-H "Authorization: Bearer <accessToken>"
The above command returns JSON structured like this:
{
"data": [
{
"id": "eb87a2dc-3e78-4d0b-b868-9d3f49c64f68",
"role": "learner"
}
],
"links": {
"next": "https://<domain>.sana.ai/api/v0/groups/b3a96b74-1b2e-49da-b5d8-bfa7c7b800be/users?next=9399b472-199b-4d18-97d9-819c7e1bf22f&limit=1"
},
"error": null
}
This endpoint retrieves all users in a specific group
HTTP Request
GET https://<domain>.sana.ai/api/v0/groups/<groupId>/users
URL Parameters
Parameter | Description |
---|---|
groupId | The ID of the group |
Query Parameters
Parameter | Type | Required | Default | Description |
---|---|---|---|---|
next | String | No | - | Set to fetch the next batch of users. |
limit | Integer | No | 100 | The number of users to return. Max: 1000 |
Add Users to a Group
curl "https://<domain>.sana.ai/api/v0/groups/b3a96b74-1b2e-49da-b5d8-bfa7c7b800be/users" \
-X POST \
-H "Content-Type: application/json" \
-H "Authorization: Bearer <accessToken>" \
-d `{ \
"users": [ \
{ \
"id": "eb87a2dc-3e78-4d0b-b868-9d3f49c64f68", \
"role": "learner" \
} \
] \
}`
This endpoint adds users to a specific group
HTTP Request
POST https://<domain>.sana.ai/api/v0/groups/<groupId>/users
URL Parameters
Parameter | Description |
---|---|
groupId | The ID of the group |
Body Parameters
Parameter | Type | Required | Default | Description |
---|---|---|---|---|
id | String | Yes | - | The ID of the user to add |
role | String | Yes | - | The user's role in the group. One of learner , group-admin . |
Update a User in a Group
curl "https://<domain>.sana.ai/api/v0/groups/b3a96b74-1b2e-49da-b5d8-bfa7c7b800be/users/eb87a2dc-3e78-4d0b-b868-9d3f49c64f68" \
-X PATCH \
-H "Content-Type: application/json" \
-H "Authorization: Bearer <accessToken>" \
-d `{ \
"user": { \
"role": "group-admin" \
} \
}`
This endpoint updates a user in a group
HTTP Request
PATCH https://<domain>.sana.ai/api/v0/groups/<groupId>/users/<userId>
URL Parameters
Parameter | Description |
---|---|
groupId | The ID of the group |
userId | The ID of the user |
Body Parameters
Parameter | Type | Required | Default | Description |
---|---|---|---|---|
role | String | No | - | The user's role in the group. One of learner , group-admin . |
Delete a User from a Group
curl "https://<domain>.sana.ai/api/v0/groups/b3a96b74-1b2e-49da-b5d8-bfa7c7b800be/users/eb87a2dc-3e78-4d0b-b868-9d3f49c64f68" \
-X DELETE \
-H "Authorization: Bearer <accessToken>"
This endpoint deletes a user from a specific group
HTTP Request
DELETE https://<domain>.sana.ai/api/v0/groups/<groupId>/users/<userId>
URL Parameters
Parameter | Description |
---|---|
groupId | The ID of the group |
userId | The ID of the user |
Assignments
An assignment is a relationship between a content entity and an identity entity.
Currently the only supported content entity is course
and the supported identity entities are user
and group
. More
entities should be expected in the future.
New entities can be introduced with short notice and this needs to be considered when parsing this data.
List user assignments
curl "https://<domain>.sana.ai/api/v0/users/bdaf7ff4-c665-4f1c-8e7b-1ca7fcca5277/assignments" \
-H "Authorization: Bearer <accessToken>"
The above command returns JSON structured like this:
{
"data": [
{
"content": {
"type": "course",
"id": "bdBUCzdWq3CK"
},
"identity": {
"type": "user",
"id": "bdaf7ff4-c665-4f1c-8e7b-1ca7fcca5277"
},
"status": {
"completed": false
},
"passedTime": null
},
{
"content": {
"type": "course",
"id": "c4etyA_7VGq4"
},
"identity": {
"type": "group",
"id": "1f1ee52d-492b-4003-afa6-0b80a2259ceb"
},
"status": {
"completed": true
},
"passedTime": "2021-12-15T18:40:53.553743439Z"
}
]
}
This endpoint lists the assignments for a user.
A user can have many assignments for the same content.
This is because a user can be assigned content through a group which they are a member of.
For this reason content
should not be considered to be a unique value in the list.
A user assignment through a group can be identified by identity
where type=group
and id
is the group's ID.
HTTP Request
GET https://<domain>.sana.ai/api/v0/users/<userId>/assignments
Query Parameters
Parameter | Type | Required | Default | Description |
---|---|---|---|---|
contentType | String | No | - | Filter assignments using content types. Allowed values: course , path |
identityType | String | No | - | Filter assignments using identity types. Allowed values: user , group |
URL Parameters
Parameter | Description |
---|---|
userId | The ID of the user |
Assign content to a user
curl "https://<domain>.sana.ai/api/v0/users/bdaf7ff4-c665-4f1c-8e7b-1ca7fcca5277/assignments" \
-X POST \
-H "Content-Type: application/json" \
-H "Authorization: Bearer <accessToken>" \
-d '{ "assignments": [{ "type": "course", "id": "c4etyA_7VGq4" }] }'
This endpoint assigns content to the user
HTTP Request
POST https://<domain>.sana.ai/api/v0/users/<userId>/assignments
Body Parameters
Parameter | Type | Required | Default | Description |
---|---|---|---|---|
assignments.type | String | Yes | - | The content type. Possible values: course , path |
assignments.id | String | Yes | - | The content ID |
URL Parameters
Parameter | Description |
---|---|
userId | The ID of the user |
Delete an assignment from a user
curl "https://<domain>.sana.ai/api/v0/users/bdaf7ff4-c665-4f1c-8e7b-1ca7fcca5277/assignments" \
-H "Authorization: Bearer <accessToken>" \
-X DELETE \
-d '{ "assignments": [{ "type": "course", "id": "c4etyA_7VGq4" }] }'
This endpoint deletes an assignment from the user.
HTTP Request
DELETE https://<domain>.sana.ai/api/v0/users/<userId>/assignments
Body Parameters
Parameter | Type | Required | Default | Description |
---|---|---|---|---|
assignments.type | String | Yes | - | The content type. Possible values: course , path |
assignments.id | String | Yes | - | The content ID |
URL Parameters
Parameter | Description |
---|---|
userId | The ID of the user |
List group assignments
curl "https://<domain>.sana.ai/api/v0/groups/1f1ee52d-492b-4003-afa6-0b80a2259ceb/assignments" \
-H "Authorization: Bearer <accessToken>"
The above command returns JSON structured like this:
{
"data": [
{
"content": {
"type": "course",
"id": "bdBUCzdWq3CK"
},
"identity": {
"type": "group",
"id": "1f1ee52d-492b-4003-afa6-0b80a2259ceb"
}
},
{
"content": {
"type": "course",
"id": "c4etyA_7VGq4"
},
"identity": {
"type": "group",
"id": "1f1ee52d-492b-4003-afa6-0b80a2259ceb"
}
}
]
}
List of content assigned to a specific group.
HTTP Request
GET https://<domain>.sana.ai/api/v0/groups/<groupId>/assignments
URL Parameters
Parameter | Description |
---|---|
groupId | The ID of the group |
Query Parameters
Parameter | Type | Required | Default | Description |
---|---|---|---|---|
contentType | String | No | - | Filter assignments using content types. Allowed values: course , path |
Assign content to a group
curl "https://<domain>.sana.ai/api/v0/groups/1f1ee52d-492b-4003-afa6-0b80a2259ceb/assignments" \
-X POST \
-H "Content-Type: application/json" \
-H "Authorization: Bearer <accessToken>" \
-d '{ "assignments": [{ "type": "course", "id": "bdBUCzdWq3CK" }] }'
This endpoint assigns content to the group
HTTP Request
POST https://<domain>.sana.ai/api/v0/groups/<groupId>/assignments
Body Parameters
Parameter | Type | Required | Default | Description |
---|---|---|---|---|
assignments.type | String | Yes | - | The content type. Possible values: course , path |
assignments.id | String | Yes | - | The content ID |
URL Parameters
Parameter | Description |
---|---|
groupId | The ID of the group |
Delete an assignment from a group
curl "https://<domain>.sana.ai/api/v0/groups/1f1ee52d-492b-4003-afa6-0b80a2259ceb/assignments" \
-H "Authorization: Bearer <accessToken>" \
-X DELETE \
-d '{ "assignments": [{ "type": "course", "id": "bdBUCzdWq3CK" }] }'
This endpoint deletes an assignment from the group.
HTTP Request
DELETE https://<domain>.sana.ai/api/v0/groups/<groupId>/assignments
URL Parameters
Parameter | Description |
---|---|
groupId | The ID of the group |
Body Parameters
Parameter | Type | Required | Default | Description |
---|---|---|---|---|
assignments.type | String | Yes | - | The content type. Possible values: course , path |
assignments.id | String | Yes | - | The content ID |
Content
Status: Disabled by default
This endpoint is disabled by default. Please reach out to your Sana contact to setup this endpoint for your organization in Sana.
List Courses
curl "https://<domain>.sana.ai/api/v0/courses" \
-H "Authorization: Bearer <accessToken>"
The above command returns JSON structured like this:
{
"data": [
{
"id": "5_dl6jHhI78o",
"title": "Agile Project Management",
"description": "Agile is an approach to project management...",
"imageUrl": "https://...",
"durationMinutes": 15
}
]
}
This endpoint lists the published courses.
HTTP Request
GET https://<domain>.sana.ai/api/v0/courses
Query Parameters
Parameter | Type | Required | Default | Description |
---|---|---|---|---|
next | String | No | - | Set to fetch the next batch of courses. |
limit | Integer | No | 100 | The number of courses to return. Max: 1000 |
Get a Course
curl "https://<domain>.sana.ai/api/v0/courses/5_dl6jHhI78o" \
-H "Authorization: Bearer <accessToken>"
The above command returns JSON structured like this:
{
"data": {
"id": "5_dl6jHhI78o",
"title": "Agile Project Management",
"description": "Agile is an approach to project management...",
"imageUrl": "https://...",
"durationMinutes": 15
}
}
This endpoint returns a specific course.
HTTP Request
GET https://<domain>.sana.ai/api/v0/courses/<courseId>
URL Parameters
Parameter | Description |
---|---|
courseId | The ID of the course |
Reporting
List available reports
curl "https://<domain>.sana.ai/api/v0/reports" \
-H "Authorization: Bearer <accessToken>"
The above command returns JSON structured like this:
{
"data": [
{
"id": "learner-progress",
"title": "Learner Progress",
"description": "Analyze progress for a set of learners on their assignments"
}
],
"links": null,
"error": null
}
This endpoint retrieves all the available reports
HTTP Request
GET https://<domain>.sana.ai/api/v0/reports
Create a job to generate a report of a specific report type.
curl "https://<domain>.sana.ai/api/v0/reports/learner-progress/jobs" \
-X POST \
-H "Content-Type: application/json" \
-H "Authorization: Bearer <accessToken>" \
-d '{ "contentTypes": ["course", "path"], "groups": [], "contentIds": [], "assignmentType": "assigned", "outputFormat": "xlsx" }'
The above command returns JSON structured like this:
{
"data": {
"jobId": "5bee6ce9-59dd-49c5-a66c-9547d345c02f"
}
}
This endpoint creates a job to generate a report.
HTTP Request
POST https://<domain>.sana.ai/api/v0/reports/<reportId>/jobs
URL Parameters
Parameter | Description |
---|---|
reportId | The ID of the report |
Body Parameters for learner-progress
report
Parameter | Type | Required | Default | Description |
---|---|---|---|---|
contentTypes | List<String> | Yes | - | The content types to include. Possible values: course , path |
groups | List<String> | No | - | The group IDs to include |
contentIds | List<String> | No | The content IDs to include | |
assignmentType | String | Yes | The assignments to include. Possible values: all , assigned |
|
outputFormat | String | Yes | The output format. Possible values: csv , xlsx |
Get status of a jobs for a specific report type.
curl "https://<domain>.sana.ai/api/v0/reports/learner-progress/jobs" \
-H "Authorization: Bearer <accessToken>"
The above command returns JSON structured like this:
{
"data": [
{
"jobId": "5bee6ce9-59dd-49c5-a66c-9547d345c02f",
"status": "successful",
"createdAt": "2022-07-28T06:40:03.658904Z",
"startedAt": "2022-07-28T06:40:13.589207Z",
"finishedAt": "2022-07-28T06:40:56.37516Z"
}
],
"links": null,
"error": null
}
This endpoint retrieves the status of the jobs for a specific report type.
HTTP Request
GET https://<domain>.sana.ai/api/v0/reports/<reportId>/jobs
URL Parameters
Parameter | Description |
---|---|
reportId | The ID of the report |
Get status of a specific job to generate a report
curl "https://<domain>.sana.ai/api/v0/reports/learner-progress/jobs/5bee6ce9-59dd-49c5-a66c-9547d345c02f" \
-H "Authorization: Bearer <accessToken>"
The above command returns JSON structured like this:
{
"data": {
"jobId": "5bee6ce9-59dd-49c5-a66c-9547d345c02f",
"status": "successful",
"createdAt": "2022-07-28T06:40:03.658904Z",
"startedAt": "2022-07-28T06:40:13.589207Z",
"finishedAt": "2022-07-28T06:40:56.37516Z",
"link": {
"url": "<url>",
"expiresAt": "2022-07-28T06:56:29.660261Z"
}
},
"links": null,
"error": null
}
This endpoint retrieves metadata for a specific job. If the job has status successful
, a link is included
in the response where the report can be downloaded.
HTTP Request
GET https://<domain>.sana.ai/api/v0/reports/<reportId>/jobs/<jobId>
URL Parameters
Parameter | Description |
---|---|
reportId | The ID of the report |
jobId | The ID of the job |
xAPI
Status: Disabled by default
This endpoint is disabled by default. Please reach out to your Sana contact to setup this endpoint for your organization in Sana.
Sana is a Learning Record Provider in the context of the xAPI specification. This means that an integration with Sana can subscribe to Statements (events) about what users' activity in Sana.
Authentication
The xAPI specification states that a client to server integration use the OAuth Client Credentials flow.
In the context of authentication Sana is the client and the integration is the server. This means that the integration must be able to issue tokens to Sana that can be used to send statements.
Request Access token
curl "https://example.com/token" \
-X POST \
-H "Content-Type: application/x-www-form-urlencoded" \
-d "grant_type=client_credentials&client_id=<client-id>&client_secret=<client-secret>&scope=statements/write"
Sana will make a request like above and expect at least the following values to be returned.
{
"access_token": "<accessToken>",
"token_type": "bearer",
"expires_in": <timeout>
}
The returned access token will be stored and used for sending statements. Sana will request a new token when the old one has expired or when a request returns 401 or 403 status.
Body Parameters
Parameter | Description |
---|---|
grant_type | Always set to client_credentials |
client_id | The ID of the client, provided by the integration |
client_secret | The secret of the client, provided by the integration |
scope | Defaults to statements/write , a custom scope can be provided in the if required. |
Response Parameters
Parameter | Description |
---|---|
access_token | An access token that can be used by Sana to make send statements |
token_type | Must be set to bearer |
expires_in | The number of seconds until the access token expires |
Configuration
xAPI integrations can be configured in https://<domain>.sana.ai/manage/api
After an integration has been created new events will be sent to the integration.
Retry logic
If a statement request fails it will be retried for some period with an exponential backoff. A statement will be retried for 6 days before discarded but the retry period can change in the future without notice.
Requests that return a 2xx status will be treated as successful, any other response will be considered a failure and will result in a retry.
Delivery semantics
Each statement (identified by its id
) will be sent at least once. At least once means that the consumer should expect
to process the same statement multiple times (in rare cases). Each statement type defines its own semantics for what is
a unique event.
Statements
The following sections list the supported statements. This list will be grow over time so it's important that the receiving endpoint can handle unknown statements types.
Course completion
Sent when a user completes a course. The user does not have to be assigned to the course for an event to be sent.
A user can have multiple completions for the same course if the course progress has been reset in between.
{
"id": "c66431c9-60ff-4997-8da6-6522a70e309a",
"actor": {
"objectType": "Agent",
"account": {
"homePage": "https://sanalabs.com",
"name": "c4db5d53-3738-4c5d-b400-edad621dbeff"
}
},
"verb": {
"display": {
"en-US": "completed"
},
"id": "http://adlnet.gov/expapi/verbs/completed"
},
"object": {
"definition": {
"type": "http://adlnet.gov/expapi/activities/course"
},
"id": "rVJIoKPfKLQK",
"objectType": "Activity"
},
"timestamp": "2021-12-15T18:40:53.553743439Z"
}
Path completion
Sent when a user completes a path. The user does not have to be assigned to the path for an event to be sent.
The completion of a path is a derived state from the completion of the courses belonging to a path. This means that the path can be completed multiple times. Either due to an underlying course being completed multiple times or new courses being added to a path.
{
"id": "c66431c9-60ff-4997-8da6-6522a70e309a",
"actor": {
"objectType": "Agent",
"account": {
"homePage": "https://sanalabs.com",
"name": "c4db5d53-3738-4c5d-b400-edad621dbeff"
}
},
"verb": {
"display": {
"en-US": "completed"
},
"id": "http://adlnet.gov/expapi/verbs/completed"
},
"object": {
"definition": {
"type": "https://sanalabs.com/xapi/activities/path"
},
"id": "th2V7hmRix_7",
"objectType": "Activity"
},
"timestamp": "2021-12-15T18:40:53.553743439Z"
}