Introduction
Welcome to the CanvasCBL API! You can use the CanvasCBL API to get CBL Grades, along with information about outcomes, courses, users and more.
CanvasCBL has no official bindings at this time-- so you'll need to use your HTTP client of choice (hopefully, in your language of choice!) to make requests.
Currently, we offer API examples in JavaScript using axios and with cURL for testing.
Also, we have a fully built out demo of the entire authorization flow and pulling grades written in Node.JS and Express.JS at https://go.canvascbl.com/api-demo-node.
Contributing
See something wrong? Please help fix it!
The repository that builds these docs is open-source at https://github.com/canvascbl/api-docs.
This version of the docs was built from commit 6d11ea1.
Developer Forum
If you currently hold a CanvasCBL Developer Key, you'll have access to the CanvasCBL Developer Forum. It's a place where anyone with a CanvasCBL Developer Key can ask questions, hear about API changes early, and more.
Members can access the forum at https://go.canvascbl.com/devforum.
Base URL
Our base URL (a 404!)
curl https://api.canvascbl.com/
# 404 page not found - go.canvascbl.com/docs
const baseUrlRequest = await axios('https://api.canvascbl.com/')
// 404 page not found - go.canvascbl.com/docs
Our base URL is https://api.canvascbl.com/
. That's the starting point for all requests. Note that HTTP requests will be forwarded to HTTPS, but you've already sent the access token in plain text over the internet. Please use HTTPS!
Times
Seconds since epoch
1580589676
RFC3339
2020-02-01T21:35:03Z
All times come back in UTC, whether they are in seconds since epoch or RFC3339. All integer times will be in seconds since epoch, and all string timestamps will be in RFC3339.
To make this easier, you can use a JavaScript library like moment.js in production, or a website like epochconverter.com during development.
CORS
CORS, or Cross-Origin Resource Sharing, is an internet standard for protecting limited access to internet resources from other webpages. You can learn more about CORS here.
The CanvasCBL API does not support CORS. For you, this means that, if you want to use the CanvasCBL API and display the result on a webpage, you must proxy the request and reponse through a server you control. Check out our API Demo for a demo of this.
Rate Limiting
The CanvasCBL API has a per-IP rate limit that should be way, way more than enough for nearly every purpose.
However, if all of the following conditions apply to you:
- You hold a CanvasCBL Developer Key
- You currently experience issues with rate limiting
- You have a real need for a higher rate limit
Please let us know via the Developer Forum.
Authentication
The CanvasCBL API uses OAuth2, a standard protocol for API authentication. To get the required Developer Key (your Client ID and Client Secret), follow the link below the table of contents on the left.
The access token should go in the HTTP Authorization
header like this:
Authorization: Bearer ilovecanvascbl
Make sure you include the "Bearer " (note that space) in the header-- otherwise it may not work.
Scopes
The following OAuth2 scopes are available, although your credentials may not have access to all scopes.
Name | Description |
---|---|
user_profile | Information about users on Canvas, like their email, name and profile picture. |
observees | Names and profile pictures of observees (if applicable). |
courses | Detailed information about each course that currently has a grade. |
alignments | Outcome alignments for a specific class. |
assignments | Detailed information about all assignments for every class the user has access to. |
outcomes | Details about any individual outcome the user has access to. |
grades | Name of each class and its grade. |
previous_grades | Grades from the last time the user used CanvasCBL. Only applies to CanvasCBL+ users. |
average_course_grade | The average grade for any course the user is enrolled in. |
average_outcome_score | The average score for any outcome in any course the user is enrolled in. |
outcome_results | Specific scores on assignments. |
detailed_grades | Grades, along with each outcome score and whether the last alignment was dropped. |
gpa | The user's unweighted GPA. |
notifications | The ability to see and change all of the user's notification settings. |
enrollments | Enrollments in a user's courses. |
submissions | Submission metadata and submission summaries. This scope does not include access to a user's submission content. |
Request
The OAuth2 request is a URL that the user should be sent to in their browser.
Endpoint
GET /api/oauth2/auth
Query String
Param | Example Value | Description |
---|---|---|
response_type |
code |
Required. Must be code . |
client_id |
d262d1d3-d969-4d48-ac1e-cfceec88b5c9 |
Required. Your Client ID. |
scope |
user_profile observees grades |
Required. Space-separated list of scopes you would like access to. |
redirect_uri |
https://dcraft.com/oauth2/response |
Required. The URI where the user will be redirected after the authorization. Must match one of the Redirect URIs on your OAuth2 Credentials. |
purpose |
dCraft |
Helps the user identify what this token is for. Note that it will already say your app's name, so try to be more specific. Optional field, though. |
Description
Prepare this URL, then send the user to it. Do not use anything (ex. URL shorteners like bit.ly) that hide the identity of this URL.
Example URL (send the user to this)
https://api.canvascbl.com/api/oauth2/auth?response_type=code&client_id=d262d1d3-d969-4d48-ac1e-cfceec88b5c9&scope=user_profile%20observees%20grades&redirect_uri=https%3A%2F%2Fdcraft.com%2Foauth2%2Fresponse&purpose=dCraft
The user will now be forwarded to an opaque URL for authorization. If they accept or deny your request, they will be redirected to the redirect URI in the original request.
After User Input
Success
https://dcraft.com/oauth2/response?code=3f17a378-b84a-4f42-a492-76f205364b81
Error
https://dcraft.com/oauth2/response?error=access_denied
After the user accepts or denies your request, they will be sent to your redirect URI with the following query params. Note that there is no guarantee control will return to your application as they may close the tab, etc.
Success:
Param | Example Value | Description |
---|---|---|
code |
3f17a378-b84a-4f42-a492-76f205364b81 |
The code you'll need for your token request. |
Error:
Param | Example Value | Description |
---|---|---|
error |
access_denied |
What the error was. |
Token
With a code
curl -X POST \
"https://api.canvascbl.com/api/oauth2/token?\
grant_type=authorization_code\
&client_id=d262d1d3-d969-4d48-ac1e-cfceec88b5c9\
&client_secret=d314d3d41e051cb569c55fe6c34d3dac\
&redirect_uri=https%3A%2F%2Fdcraft.com%2Foauth2%2Fresponse\
&code=3f17a378-b84a-4f42-a492-76f205364b81"
const code = '3f17a378-b84a-4f42-a492-76f205364b81';
const tokenRequest = await axios({
method: 'post',
url: 'https://api.canvascbl.com/api/oauth2/token',
params: {
grant_type: 'authorization_code',
client_id: 'd262d1d3-d969-4d48-ac1e-cfceec88b5c9',
client_secret: '314d3d41e051cb569c55fe6c34d3dac',
redirect_uri: 'https://dcraft.com/oauth2/response',
code: code
}
});
Code response
{
"access_token": "582caaaa-d89e-47f9-92a1-660d15be050a",
"refresh_token": "4d1dbae6-0fff-4873-8930-845231fd26bc",
"user": {
"id": 1
},
"expires_at": "2020-02-01T21:35:03Z" // one hour later
}
With a refresh token
curl -X POST \
"https://api.canvascbl.com/api/oauth2/token?\
grant_type=refresh_token\
&client_id=d262d1d3-d969-4d48-ac1e-cfceec88b5c9\
&client_secret=d314d3d41e051cb569c55fe6c34d3dac\
&redirect_uri=https%3A%2F%2Fdcraft.com%2Foauth2%2Fresponse\
&refresh_token=4d1dbae6-0fff-4873-8930-845231fd26bc"
const refreshToken = '3f17a378-b84a-4f42-a492-76f205364b81';
const refreshTokenRequest = await axios({
method: 'post',
url: 'https://api.canvascbl.com/api/oauth2/token',
params: {
grant_type: 'refresh_token',
client_id: 'd262d1d3-d969-4d48-ac1e-cfceec88b5c9',
client_secret: '314d3d41e051cb569c55fe6c34d3dac',
redirect_uri: 'https://dcraft.com/oauth2/response',
refresh_token: refreshToken
}
});
Refresh token response
{
"access_token": "f690f300-6fbb-4e17-a04a-bd032658ad13",
"user": {
"id": 1
},
"expires_at": "2020-02-01T21:38:36Z"
}
You can use the token endpoint either to refresh an expired access token (access tokens last an hour) or to get a new access and refresh token from a code.
Endpoint
POST /api/oauth2/token
Query String
Param | Required For | Values or Example Value | Description |
---|---|---|---|
grant_type |
Always | authorization_code or refresh_token |
Represents what you want to do. authorization_code should be used when you have a code and refresh_token should be used when you have a refresh token and an expired access token. |
client_id |
Always | d262d1d3-d969-4d48-ac1e-cfceec88b5c9 |
Your Client ID. |
client_secret |
Always | d314d3d41e051cb569c55fe6c34d3dac |
Your Client Secret. |
redirect_uri |
Always | https://dcraft.com/oauth2/response |
The Redirect URI used when first requesting the token. |
code |
grant_type = authorization_code |
The code from your Redirect URI (?). | |
refresh_token |
grant_type = refresh_token |
The refresh token of the access token you'd like to refresh. |
Description
This endpoint is the final step in the OAuth2 process, and is also how you 'refresh' an expired access token.
Developer Keys (your Client ID and Client Secret) can have an unlimited number of OAuth2 Grants, but each grant may only have one valid access token at a time. This means that, if you want to use the CanvasCBL API concurrently (a completely supported behavior!) you need to be sure that each of your requests don't try to refresh the token at the same time. If you do that, you're establishing a race condition-- don't do this!
Access tokens expire after an hour. Refresh tokens do not expire, but users may revoke a grant (both the access and refresh token) at any time from their profile page.
Storing Grants
You may store grants in your database. However, you must (hopefully obviously) secure them as best as possible. If a valid access token is leaked, an attacker may use that token to retrieve information without your knowledge.
It is not recommended to store your client secret in your database. Use an environment variable for that.
You get a unique ID for every user in the response from this endpoint. Use that to store access and refresh tokens for a user.
Logout
Invalidate that token!
curl \
-X DELETE \
-H "Authorization: Bearer ilovecanvascbl" \
https://api.canvascbl.com/api/oauth2/token
await axios({
"method": "delete",
"url": "https://api.canvascbl.com/api/oauth2/token",
"headers": {
"Authorization": "Bearer ilovecanvascbl"
}
})
Logout lets you revoke an access token.
Endpoint
DELETE /api/oauth2/token
Description
Logout invalidates the grant used to call it. It returns a 204 NO CONTENT
.
When issuing this request, it's recommended to delete the grant associated with the used access token from your database.
Grades
The most powerful part of the CanvasCBL API, by far.
Get Grades
Simple grades alone
curl \
-X GET \
-H "Authorization: ilovecanvascbl" \
"https://api.canvascbl.com/api/v1/grades"
const gradesRequest = await axios({
method: "GET",
url: "https://api.canvascbl.com/api/v1/grades",
headers: {
"Authorization": "Bearer ilovecanvascbl"
}
});
// if you just care about the 'first' user's grades, you can do something like this:
const grades =
// get a k/v array from our object
Object.entries(gradesRequest.data.simple_grades).
// reduce it into a single object
reduce((acc, g) => {
// g[0] = class name
// g[1] = { userID: grade }
// Object.values(g[1]) = [grade]
acc[g[0]] = Object.values(g[1])[0];
return acc;
// we have this empty object here as our starting value for reduce
// learn more: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/Reduce
}, {});
/*
{ 'Calculus - S2 - Smith': 'A',
'Biology - S2 - Martinez': 'B',
'English 3 - S2 - Lee': 'A-',
'World History - S2 - Brown': 'A' }
*/
// if you want something iterable (and just the first user's grade), try something like this:
const iterableGrades =
// get a k/v array from our object
Object.entries(gradesRequest.data.simple_grades).
// use map to transform each item
map(g => {
// g[0] = class name
// g[1] = { userID: grade }
// Object.values(g[1]) = [grade]
return [g[0], Object.values(g[1])[0]]
});
/*
[ [ 'Calculus - S2 - Smith', 'A' ],
[ 'Biology - S2 - Martinez', 'B' ],
[ 'English 3 - S2 - Lee', 'A-' ],
[ 'World History - S2 - Brown', 'A' ] ]
*/
Simple grades (no include[]) response
{
"simple_grades": {
"Calculus - S2 - Smith": {
// 1 (keys) is the graded user's Canvas ID
// multiple entries will appear if the user is an Observer and has multiple Observees
// in that case, you do NOT need the Observees include or scope.
"1": "A"
},
"Biology - S2 - Martinez": {
"1": "B"
},
"English 3 - S2 - Lee": {
"1": "A-"
},
"World History - S2 - Brown": {
"1": "A"
}
}
}
Two includes, just as a template (scopes required:
user_profile
,observees
)
curl \
-X GET \
-H "Authorization: ilovecanvascbl" \
"https://api.canvascbl.com/api/v1/grades?\
include[]=user_profile\
&include[]=observees"
const gradesRequest = await axios({
method: "GET",
url: "https://api.canvascbl.com/api/v1/grades",
params: {
includes: [
'user_profile',
'observees'
]
}
headers: {
"Authorization": "Bearer ilovecanvascbl"
}
});
See the response here.
Kitchen Sink (simple grades, scopes:
user_profile
,outcome_results
,observees
,courses
)
curl \
-X GET \
-H "Authorization: ilovecanvascbl" \
"https://api.canvascbl.com/api/v1/grades?\
include[]=user_profile\
&include[]=outcome_results\
&include[]=observees\
&include[]=courses\
&include[]=gpa"
const kitchenSinkRequest = await axios({
method: "GET",
url: "https://api.canvascbl.com/api/v1/grades",
params: {
includes: [
'user_profile',
'outcome_results',
'observees',
'courses',
'gpa'
]
}
headers: {
"Authorization": "Bearer ilovecanvascbl"
}
});
See the response here.
Kitchen Sink (detailed grades, scopes:
detailed_grades
,user_profile
,outcome_results
,observees
,courses
)
curl \
-X GET \
-H "Authorization: ilovecanvascbl" \
"https://api.canvascbl.com/api/v1/grades?\
include[]=user_profile\
&include[]=outcome_results\
&include[]=observees\
&include[]=courses\
&include[]=detailed_grades\
&include[]=gpa"
const kitchenSinkRequest = await axios({
method: "GET",
url: "https://api.canvascbl.com/api/v1/grades",
params: {
includes: [
'user_profile',
'outcome_results',
'observees',
'courses',
'detailed_grades',
'gpa'
]
}
headers: {
"Authorization": "Bearer ilovecanvascbl"
}
});
See the response here.
Endpoint
GET /api/v1/grades
Scopes/Includes
Grades is a flexible endpoint that can return anything from just a user's class names and their grades to their profile, outcome results, outcome averages, full courses and more.
You tell the grades endpoint what you want by using the include[]
query parameter.
If you do not include any include[]
parameters, only simple grades will be returned. Simple grades just requres the grades
scope.
However, if you ask for detailed_grades
, you will not get simple grades. It's one or the other.
While the include[]
parameter is intended to mirror OAuth2 Scopes, they may differ in the future, so the following table is here for convience.
Includes Name | Required Scope | Note |
---|---|---|
detailed_grades |
detailed_grades |
|
distance_learning |
grades |
Please see the Distance Learning section. |
user_profile |
user_profile |
|
outcome_results |
outcome_results |
Outcome results are auto-paginated. |
observees |
observees |
|
courses |
courses |
|
gpa |
gpa |
Please see the GPA section. |
Description
Grades is, by far, the most powerful endpoint that the CanvasCBL API offers.
When using it, though, there are a few things to note:
- It is a slow endpoint. It relies on many responses from Canvas, which can take a while. If you want to set a reasonable timeout for this request, we recommend about 15 seconds. Normally, it takes 0.5-5 seconds, but we've seen it as high as 14.
- It is an expensive endpoint. There is a lot of computation on both sides which is required to make this work.
- We recommend that you re-fetch grades on every reload of your app.
- The user's Canvas ID may not appear in grades-- that generally means that the user is an Observer. For information about their Observees, you'll want to request
observees
. - You may not store anything but profiles. Storing any information from this endpoint, (as you should know!-- except user_profile data) is a violation of the CanvasCBL Developer Key Agreement and will cause a revocation of your developer key.
If you're curious what the full response is from this endpoint (with all includes and scopes), you can click here for everything (simple grades) and here for everything (detailed grades).
Canvas API Bindings
Some of the include[]
options return responses that essentially mirror Canvas's API.
Not all fields will be there, notably large ones like descriptions. You can see what is and isn't included in the Kitchen Sink response.
Here's a reference to those:
Includes Name | Canvas API Doc | Note |
---|---|---|
user_profile |
GET /api/v1/users/:user_id/profile |
|
outcome_results |
GET /api/v1/courses/:course_id/outcome_results |
|
observees |
GET /api/v1/users/:user_id/observees |
|
courses |
GET /api/v1/courses |
Courses will have a canvascbl_hidden property. See course hiding for more info. |
GPA
The GPA response (as a part of the grades request)
{
// ...
"gpa": {
// user id
"1": {
"unweighted": {
"subgrades": 3.70,
"default": 4.00
}
}
// ...
}
GPA at d.tech is calculated differently than it is at many schools.
The notable change is that, in an unweighted GPA, d.tech does not count what we're calling "subgrades"-- +
or -
versions of grades--,
like an A- or B+. d.tech counts all subgrades as their base grade, so a B-, B and B+ all earn a 3.0, for example.
However, we understand that students may want to see their GPA with so-called "subgrades", so we include this feature.
In the example (it's the towards the bottom, scroll down!) our student has all A-'s. Normally, an A- would equate to a 3.7.
This value is reflected in gpa[user_id].unweighted.subgrades
.
But, since d.tech does not count the subgrade, this A- is "turned into" an A, giving them a 4.0. This GPA is
reflected in gpa[user_id].unweighted.default
.
We have a helpdesk-style article about this here.
Currently, we do not offer a weighted GPA. However, the object structure is set up so that we could introduce it without breaking changes.
Distance Learning
For the second semester of the 2019-2020 school year, d.tech will be combining the grades from two canvas courses to determine a final pass or incomplete score for the class.
Basically, if the student did not have an incomplete before distance learning, they need to earn a non-incomplete distance learning score. If the student had an incomplete before distance learning, they must earn a B or better in distance learning to pass.
Calculating this means that the CanvasCBL API must synthesize two Canvas courses to compute a final, human-readable score.
To return these new grades, we're adding a new include
to the grades
endpoint. It's called distance_learning
, and it's part of the grades
scope.
In turn, it adds a new property to the grades response, aptly also
distance_learning
. Check out a response on the right.
Response from /api/v1/grades with
include[]=distance_learning
{
// grades, courses, etc...
"distance_learning": {
// user ID
"1": {
"Biology": {
"grade": {
"grade": "P",
// use rank to compare grades. higher is better.
"rank": 1
},
// the Canvas ID of the in-person course
"original_course_id": 1,
// the Canvas ID of the distance learning course
"distance_learning_course_id": 2
}
// ... (more courses)
}
// ... (more users)
}
// ...
}
Get Distance Learning Grades Overview
Get a summary of distance learning grades for the specified courses
curl \
-X GET \
-H "Authorization: ilovecanvascbl" \
"https://api.canvascbl.com/api/v1/grades/distance_learning/overview\
?original_course_id=123\
&distance_learning_course_id=456"
const distanceLearningGradesOverviewRequest = await axios({
method: "GET",
url: "https://api.canvascbl.com/api/v1/grades/distance_learning/overview",
headers: {
"Authorization": "Bearer ilovecanvascbl"
},
params: {
original_course_id: 123,
distance_learning_course_id: 456
}
});
Distance learning grades overview
{
"distance_learning_grades_overview": [
{
"user_id": 1,
"grade": {
"grade": "P"
},
// what time CanvasCBL computed the grade
"timestamp": "2020-02-01T21:35:03Z"
}
// ...
]
}
Get a summary of distance learning grades for a pair of distance learning courses.
Endpoint
GET /api/v1/grades/distance_learning/overview
Scopes
grades
Query String
Param | Example Value | Description |
---|---|---|
distance_learning_course_id |
123 |
Required. The ID of the distance learning course. Get this from the Get Courses endpoint with ?include[]=distance_learning_pairs . |
original_course_id |
456 |
Required. The ID of the original (in-person) course. Get this from the Get Courses endpoint with ?include[]=distance_learning_pairs . |
Description
This endpoint lets you get a summary of distance learning grades for all students in the specified courses.
In order to load this endpoint, the calling user must have a TeacherEnrollment in both courses.
This endpoint returns cached grades. That means they're updated about hourly.
When a user first signs up, it can take up to 3 hours for grades to be available from this endpoint, as grades and enrollments must sync to CanvasCBL.
The max age of a grade that will be returned by this endpoint is 48 hours.
Courses
These APIs allow you to get courses and auxiliary information about them.
Get Courses
Get the calling user's courses and distance learning pairs
curl \
-X GET \
-H "Authorization: ilovecanvascbl" \
"https://api.canvascbl.com/api/v1/courses\
?include[]=distance_learning_pairs"
const coursesRequest = await axios({
method: "GET",
url: "https://api.canvascbl.com/api/v1/courses",
headers: {
"Authorization": "Bearer ilovecanvascbl"
},
params: {
include: [
'distance_learning_pairs'
]
}
});
Courses for the calling user and distance learning pairs
{
"courses": [
{
"account_id": 41,
"apply_assignment_group_weights": false,
"blueprint": false,
"calendar": {
"ics": "https://canvas.instructure.com/feeds/calendars/course_tp7ihFuDOa2co5Kjl6ncT4jzxS1GfcP6G3jpHxzt.ics"
},
"course_code": "Biology - S2 - Martinez",
"created_at": "2020-01-15T01:20:47Z",
"default_view": "modules",
"end_at": "",
"enrollment_term_id": 11,
"enrollments": [
{
"associated_user_id": 3,
"enrollment_state": "active",
"limit_privileges_to_course_section": false,
"role": "ObserverEnrollment",
"role_id": 7,
"type": "observer",
"user_id": 1
},
{
"associated_user_id": 2,
"enrollment_state": "active",
"limit_privileges_to_course_section": false,
"role": "ObserverEnrollment",
"role_id": 7,
"type": "observer",
"user_id": 1
},
{
"associated_user_id": 4,
"enrollment_state": "active",
"limit_privileges_to_course_section": false,
"role": "ObserverEnrollment",
"role_id": 7,
"type": "observer",
"user_id": 1
}
],
"grade_passback_setting": null,
"grading_standard_id": 0,
"hide_final_grades": true,
"id": 1,
"is_public": false,
"is_public_to_auth_users": false,
"license": "private",
"locale": "",
"name": "Biology - S2 - Martinez",
"overridden_course_visibility": "",
"public_syllabus": false,
"public_syllabus_to_auth": false,
"restrict_enrollments_to_course_dates": false,
"root_account_id": 1,
"start_at": "2020-01-21T17:26:00Z",
"storage_quota_mb": 500,
"time_zone": "America/Los_Angeles",
"uuid": "thisisnormallyunique",
"workflow_state": "available",
"canvascbl_hidden": false
}
// ...
],
// only included with ?include[]=distance_learning_pairs
"distance_learning_pairs": [
{
"course_name": "Biology",
"original_course_id": 1,
"distance_learning_course_id": 2
}
// ...
]
}
Get all courses for a user.
Endpoint
GET /api/v1/courses
Scopes
courses
Query String
Param | Example Value | Description |
---|---|---|
include[] |
distance_learning_pairs |
Optional. Returns pairs of distance learning courses. |
Description
This endpoint lets you get all assignments for a course.
Mostly a mirror of this Canvas endpoint, but we append the following query params:
enrollment_state=active
include[]=observed_users
(you don't need the observees scope for this)include[]=course_image
This endpoint is auto-paginated.
Get Assignments
Get assignments for course ID
1
curl \
-X GET \
-H "Authorization: ilovecanvascbl" \
"https://api.canvascbl.com/api/v1/courses/1/assignments"
const assignmentsRequest = await axios({
method: "GET",
url: "https://api.canvascbl.com/api/v1/courses/1/assignments",
headers: {
"Authorization": "Bearer ilovecanvascbl"
}
});
Response: Assignments for course ID
1
[
{
"allowed_attempts": -1,
"anonymize_students": false,
"anonymous_grading": false,
"anonymous_instructor_annotations": false,
"anonymous_peer_reviews": false,
"anonymous_submissions": false,
"assignment_group_id": 326,
"automatic_peer_reviews": false,
"can_duplicate": true,
"course_id": 1,
"created_at": "2019-08-26T15:04:16Z",
"due_at": "2019-08-24T05:59:59Z",
"due_date_required": false,
"final_grader_id": null,
"free_form_criterion_comments": false,
"grade_group_students_individually": false,
"grader_comments_visible_to_graders": true,
"grader_count": 0,
"grader_names_visible_to_final_grader": true,
"graders_anonymous_to_graders": false,
"grading_standard_id": null,
"grading_type": "not_graded",
"group_category_id": null,
"has_submitted_submissions": false,
"html_url": "https://canvas.instructure.com/courses/1/assignments/1",
"id": 1,
"in_closed_grading_period": false,
"intra_group_peer_reviews": false,
"is_quiz_assignment": false,
"lock_at": "",
"lock_explanation": "",
"lock_info": {
"asset_string": "",
"can_view": false,
"lock_at": ""
},
"locked_for_user": false,
"max_name_length": 255,
"moderated_grading": false,
"muted": true,
"name": "Assignment Name",
"omit_from_final_grade": false,
"only_visible_to_overrides": false,
"original_assignment_id": null,
"original_assignment_name": null,
"original_course_id": null,
"original_quiz_id": null,
"peer_reviews": false,
"points_possible": 0,
"position": 1,
"post_manually": false,
"post_to_sis": false,
"published": true,
"quiz_id": 0,
"rubric": null,
"rubric_settings": {
"free_form_criterion_comments": false,
"hide_points": false,
"hide_score_total": false,
"id": 0,
"points_possible": 0,
"title": ""
},
"secure_params": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJsdGlfYXNzaWdubWVudF9pZCI6Iijil4_vvL5v77y-4pePKSJ9.81MdexcyaAsnMEpSWstOvbkpFhKpl9sO0wLbuh01DL4",
"submission_types": [
"not_graded"
],
"submissions_download_url": "https://canvas.instructure.com/courses/1/assignments/1/submissions?zip=1",
"unlock_at": "",
"updated_at": "2019-10-17T01:39:57Z",
"use_rubric_for_grading": false,
"workflow_state": "published"
},
// ...
]
Get all assignments for a course.
Endpoint
GET /api/v1/courses/:courseID/assignments
Scopes
assignments
Query String
Param | Example Value | Description |
---|---|---|
assignment_ids[] |
1 |
Optional. Lets you specify the assignment IDs you want returned. Include as many as you'd like. Note that this endpoint will error out if you ask for one or more assignments that don't exist or you don't have access to. |
Description
This endpoint lets you get all assignments for a course.
Mostly a mirror of this Canvas endpoint.
This endpoint is auto-paginated.
Get Outcome Alignments
Get outcome alignments for course ID
1
and student ID1
curl \
-X GET \
-H "Authorization: ilovecanvascbl" \
"https://api.canvascbl.com/api/v1/courses/1/outcome_alignments?\
student_id=1"
const outcomeAlignmentsRequest = await axios({
method: "GET",
url: "https://api.canvascbl.com/api/v1/courses/1/outcome_alignments",
params: {
student_id: 1
}
headers: {
"Authorization": "Bearer ilovecanvascbl"
}
});
Response: Outcome alignments for course ID
1
and student ID1
[
{
"learning_outcome_id": 1,
"title": "Outcome A",
"assignment_id": 1,
"submission_types": "on_paper",
"url": "https://canvas.instructure.com/courses/1/assignments/1"
},
// ...
]
Gets Outcome Alignments for a course.
Endpoint
GET /api/v1/courses/:courseID/outcome_alignments
Scopes
alignments
Query String
Param | Example Value | Description |
---|---|---|
student_id |
1 |
Required. Canvas ID of the user you want alignments for. |
Description
This endpoint gets outcome alignments for a course on Canvas.
Mostly a mirror of this Canvas endpoint.
Get Enrollments
Enrollments for course ID 1
curl \
-X GET \
-H "Authorization: ilovecanvascbl" \
"https://api.canvascbl.com/api/v1/courses/1/enrollments"
const courseId = 1;
const coursesRequest = await axios({
method: "GET",
url: `https://api.canvascbl.com/api/v1/courses/${courseId}/enrollments`,
headers: {
"Authorization": "Bearer ilovecanvascbl"
}
});
Enrollments for course ID 1, from a teacher's perspective
{
"enrollments": [
{
"id": 1,
"user_id": 1,
"course_id": 1,
"type": "StudentEnrollment",
"created_at": "2020-03-27T19:22:17Z",
"updated_at": "2020-04-06T03:32:25Z",
"associated_user_id": null,
"start_at": null,
"end_at": null,
"course_section_id": 1,
"root_account_id": 1,
"limit_privileges_to_course_section": false,
"enrollment_state": "active",
"role": "StudentEnrollment",
"role_id": 3,
"last_activity_at": "2020-04-20T18:35:13Z",
"last_attended_at": null,
"total_activity_time": 1,
// only present if the calling user is a teacher OR if this is the calling user's enrollment
// also not shown for CBL courses
"grades": {
"html_url": "https://canvas.instructure.com/courses/1/grades/1",
"current_grade": "A",
"current_score": 100.0,
"final_grade": "I",
"final_score": 1.95
},
"html_url": "https://canvas.instructure.com/courses/1/users/1",
"user": {
"id": 1,
"name": "Example Student",
"created_at": "2019-05-16T15:46:30-07:00",
"sortable_name": "Student, Example",
"short_name": "Example Student",
// only shown if the calling user is a teacher
"login_id": "student@example.com"
}
}
// ...
]
}
Enrollments for course ID 1, from a non-teacher's perspective
{
"enrollments": [
{
"course_id": 1,
"course_section_id": 1,
"created_at": "2020-03-27T19:23:18Z",
"enrollment_state": "active",
"grades": {
// grades are only visible for CBL courses
// visible because this is the calling user's enrollment
"current_grade": "A",
"current_score": 91.33,
"final_grade": "I",
"final_score": 47.24,
"html_url": "https://canvas.instructure.com/courses/1/grades/1"
},
"html_url": "https://dtechhs.instructure.com/courses/1/users/1",
"id": 1,
"last_activity_at": "2020-04-20T20:37:05Z",
"role": "StudentEnrollment",
"role_id": 3,
"root_account_id": 1,
"total_activity_time": 154137,
"type": "StudentEnrollment",
"updated_at": "2020-04-06T17:08:13Z",
"user": {
"created_at": "2019-05-16T15:46:30-07:00",
"id": 1,
"name": "Calling User",
"short_name": "Calling User",
"sortable_name": "User, Calling"
},
"user_id": 1
},
{
"course_id": 1,
"course_section_id": 1,
"created_at": "2020-03-27T19:23:17Z",
"enrollment_state": "active",
"grades": {
// grades are only visible for CBL courses
// no grades because this is NOT the calling user
"html_url": "https://canvas.instructure.com/courses/1/grades/2"
},
"html_url": "https://canvas.instructure.com/courses/1/users/2",
"id": 2,
"role": "StudentEnrollment",
"role_id": 3,
"root_account_id": 1,
"type": "StudentEnrollment",
"updated_at": "2020-04-06T17:08:13Z",
"user": {
"created_at": "2019-05-16T15:46:49-07:00",
"id": 460,
"name": "Another User",
"short_name": "Another User",
"sortable_name": "User, Another"
},
"user_id": 2
}
]
}
Get all enrollments for a course.
Endpoint
GET /api/v1/courses/:courseID/enrollments
Scopes
grades
enrollments
Both scopes are required for this call.
Query String
Param | Example Value | Description |
---|---|---|
type[] |
StudentEnrollment |
See Canvas API documentation. |
state[] |
active |
See Canvas API documentation. |
Description
This endpoint lets you get all enrollments for a course.
Mostly a mirror of this Canvas endpoint, but we append the following query params:
include[]=avatar_url
include[]=observed_users
(you don't need the observees scope for this)
This endpoint is auto-paginated.
Get Course Submission Summary
By-assignment submission summary for course
1
curl \
-X PUT \
-H "Authorization: ilovecanvascbl" \
"https://api.canvascbl.com/api/v1/courses/1/submission_summary/users"
const submissionSummaryRequest = await axios({
method: "PUT",
url: "https://api.canvascbl.com/api/v1/courses/1/submission_summary/users",
headers: {
"Authorization": "Bearer ilovecanvascbl"
}
});
Per-user submission summary for course
1
{
"submission_summary": {
// Canvas user ID
"1": {
"summary": {
"graded": 10,
// submitted but not graded - does not include graded
"submitted": 5,
"unsubmitted": 10,
// only included with ?include[]=late_count
"late": {
// total number of late, submitted assignments
"total": 2,
// 8%
"percent": 8
}
}
}
// ...
}
}
Endpoint
GET /api/v1/courses/:courseID/submission_summary/users
Scopes
submissions
Query String
Param | Example Value | Description |
---|---|---|
user_ids[] |
123 |
The users that you'd like the summary for. See the Permissions section below for more info. |
use_cache |
true or false |
Whether you would like to use the CanvasCBL cache for this request. This param is ignored and the cache is always used when teachers get data for an entire class. Defaults to true for teachers and false for everyone else. |
include[] |
late_count |
Adds the number and percentage of late assignments to the summary. |
Description
Course submission summaries provide users with an overview of student submissions in their course.
It provides counts of:
- Graded assignments
- Submitted, but ungraded assignments
- Unsubmitted assignments
By default, data from this endpoint is cached for teachers and live for students and observers.
This endpoint may not work for all users. We're using data from Canvas that
needs scopes we added after some users signed up. In this case, we'll include
the redirect_to_oauth
error action.
Permissions
Every user who is enrolled in this course may use this endpoint. However, we will limit the scope of data returned.
- Students may get data for themselves only.
- Observers may get data for all of their enrolled observees.
- Teachers may get data for all users in the specified course.
You may figure out the user's enrollment in the course by either getting enrollments or getting courses.
If a user does not have access to one or more requested users' submissions,
the following error will be returned: you do not have access to one or more
of the requested user's submissions
.
By-Enrollment Permissions
If the user does not have a valid enrollment in the course, you will get the
following error: unable to find a valid enrollment for you in this course
.
Note that this error may show up when using the cache if the user's
enrollments have not synced to CanvasCBL.
This endpoint supports the following enrollment types:
TeacherEnrollment
StudentEnrollment
ObserverEnrollment
If the user does not have one of those enrollment types, the following error
will be returned: your enrollment type in this course does not support submission summaries at this time
.
Hide a Course
Hide course ID 1
curl \
-X PUT \
-H "Authorization: ilovecanvascbl" \
"https://api.canvascbl.com/api/v1/courses/1/hide"
const hideCourseRequest = await axios({
method: "PUT",
url: "https://api.canvascbl.com/api/v1/courses/1/hide",
headers: {
"Authorization": "Bearer ilovecanvascbl"
}
});
Response: Course ID 1 is marked as hidden
{
"canvascbl_hidden": true
}
Endpoint
PUT /api/v1/courses/:courseID/hide
Scopes
courses
Description
This endpoint enables hiding a course. When a course is hidden,
the canvascbl_hidden
course attribute will be set to true
. The API will
not remove that course from responses.
You may make this request as many times as you like, and the result will be the same.
Show a Course
Show course ID 1
curl \
-X PUT \
-H "Authorization: ilovecanvascbl" \
"https://api.canvascbl.com/api/v1/courses/1/hide"
const showCourseRequest = await axios({
method: "DELETE",
url: "https://api.canvascbl.com/api/v1/courses/1/hide",
headers: {
"Authorization": "Bearer ilovecanvascbl"
}
});
Response: Course ID 1 is NOT marked as hidden
{
"canvascbl_hidden": false
}
Endpoint
DELETE /api/v1/courses/:courseID/hide
Scopes
courses
Description
This endpoint disables hiding a course. When a course is hidden,
the canvascbl_hidden
course attribute will be set to true
. The API will
not remove that course from responses.
You may make this request as many times as you like, and the result will be the same.
Outcomes
These endpoints are about Canvas Outcomes.
Get an Outcome
Get outcome ID
1
curl \
-X GET \
-H "Authorization: ilovecanvascbl" \
"https://api.canvascbl.com/api/v1/outcomes/1"
const outcomeRequest = await axios({
method: "GET",
url: "https://api.canvascbl.com/api/v1/outcomes/1",
headers: {
"Authorization": "Bearer ilovecanvascbl"
}
});
Response: Outcome ID
1
{
"assessed": true,
"calculation_int": 65,
"calculation_method": "decaying_average",
"can_edit": false,
"context_id": 1,
"context_type": "Course",
"display_name": "Outcome A",
"has_updateable_rubrics": false,
"id": 1,
"mastery_points": 2.5,
"points_possible": 4,
"ratings": [
{
"points": 4
},
{
"points": 3
},
{
"points": 2
},
{
"points": 1
}
],
"title": "Full Title for Outcome A",
"url": "/api/v1/outcomes/1",
"vendor_guid": null
}
Endpoint
GET /api/v1/outcomes/:outcomeID
Scopes
outcomes
Description
Lets you get information about a single Outcome on Canvas.
Mostly a mirror of this Canvas endpoint.
Users
These APIs let you get information about users.
You can always use self
in place of a user's ID to get results for the
calling user.
User Profile (CanvasCBL)
Get your own user profile
curl \
-X GET \
-H "Authorization: ilovecanvascbl" \
"https://api.canvascbl.com/api/v1/users/self/profile?\
include[]=extra_info"
const profileRequest = await axios({
method: "GET",
url: "https://api.canvascbl.com/api/v1/users/self/profile",
headers: {
"Authorization": "Bearer ilovecanvascbl"
},
params: {
include: [
'extra_info'
]
}
});
Your user profile
{
"profile": {
"id": 1,
"name": "Example Student",
"email": "student@example.com",
// only included with ?include[]=extra_info
"lti_user_id": "averylongstringofnumb3rsandl3tt3rsyoushouldgooglethis",
"canvas_user_id": 123,
// CanvasCBL internal-- don't really use this for anything
// only included with ?include[]=extra_info
"status": 0
}
}
Get a bit of info about a user from CanvasCBL.
Endpoint
GET /api/v1/users/:userID/profile
Scopes
user_profile
Query String
Param | Example Value | Description |
---|---|---|
include[] |
extra_info |
See the example response. Adds fields that are useful once in a while. |
Description
Sometimes, you just want to know a bit about a user. This endpoint is for exactly that.
Note that this is a user's profile on CanvasCBL. It may not be completely up-to-date with their Canvas profile, but it should be close enough for almost every purpose.
At the moment, users are only authorized to view their own profile.
Notifications
These endpoints let you configure notifications for a user.
List Available Notifications
List available notifications
curl \
-X GET \
-H "Authorization: ilovecanvascbl" \
"https://api.canvascbl.com/api/v1/notifications/types"
const listAvailableNotificationsRequest = await axios({
method: "GET",
url: "https://api.canvascbl.com/api/v1/notifications/types",
headers: {
"Authorization": "Bearer ilovecanvascbl"
}
});
Available notifications
[
{
"id": 1,
"name": "Grade Change",
// these are unique
"short_name": "grade_change",
"description": "A notification when your grade in any class changes."
}
// ...
]
This endpoint lets you view all available notification types a user can subscribe to.
Endpoint
GET /api/v1/notifications/types
^If you're curious, we're leaving /api/v1/notifications
open for future expansion
^(listing delivered notifications, for example).
Scopes
notifications
Description
List notification types lets you list all of the available notification types for a user.
It does not, however, include the user's notification settings.
List Notification Settings
List notification settings
curl \
-X GET \
-H "Authorization: ilovecanvascbl" \
"https://api.canvascbl.com/api/v1/notifications/settings"
const listNotificationSettingsRequest = await axios({
method: "GET",
url: "https://api.canvascbl.com/api/v1/notifications/settings",
headers: {
"Authorization": "Bearer ilovecanvascbl"
}
});
Available notifications
{
"notification_settings": [
{
"notification_type_id": 1,
"medium": "email"
}
// ...
]
}
List notification settings and types
curl \
-X GET \
-H "Authorization: ilovecanvascbl" \
"https://api.canvascbl.com/api/v1/notifications/settings\
?include[]=notification_types"
const listNotificationSettingsRequest = await axios({
method: "GET",
url: "https://api.canvascbl.com/api/v1/notifications/settings",
headers: {
"Authorization": "Bearer ilovecanvascbl"
},
params: {
"include": [
"notification_types"
]
}
});
Notification settings and types
{
"notification_settings": [
{
"notification_type_id": 1,
"medium": "email"
}
// ...
],
"notification_types": [
{
"id": 1,
"name": "Grade Change",
// these are unique
"short_name": "grade_change",
"description": "A notification when your grade in any class changes."
}
// ...
]
}
Endpoint
GET /api/v1/notifications/settings
Scopes
notifications
Query String
Param | Example Value | Description |
---|---|---|
include[] |
notification_types |
Ask for notification types if you want them. |
Description
List notification settings allows you to list the user's notification settings.
Add a Notification
Enable grade change emails (id 1)
curl \
-X PUT \
-H "Authorization: ilovecanvascbl" \
"https://api.canvascbl.com/api/v1/notifications/types/1\
?medium=email"
const addNotificationRequest = await axios({
method: "PUT",
url: "https://api.canvascbl.com/api/v1/notifications/types/1",
headers: {
"Authorization": "Bearer ilovecanvascbl"
},
params: {
'medium': 'email'
}
});
Returns a 204 no content
Endpoint
PUT /api/v1/notifications/types/:notificationTypeID
Scopes
notifications
Query String
Param | Example Value | Description |
---|---|---|
medium |
email |
Required. In the future, other mediums may be available. For now, email is the only acceptable medium. |
Description
This endpoint lets you enable or disable a notification for a user.
Because the PUT
HTTP Verb is idempotent, you can call this endpoint as many
times as you'd like, and only one notification will be created per user.
Remove a Notification
Disable grade change emails (id 1)
curl \
-X DELETE \
-H "Authorization: ilovecanvascbl" \
"https://api.canvascbl.com/api/v1/notifications/types/1\
?medium=email"
const removeNotificationRequest = await axios({
method: "DELETE",
url: "https://api.canvascbl.com/api/v1/notifications/types/1",
headers: {
"Authorization": "Bearer ilovecanvascbl"
},
params: {
'medium': 'email'
}
});
Returns a 204 no content
Endpoint
DELETE /api/v1/notifications/types/:notificationTypeID
Scopes
notifications
Query String
Param | Example Value | Description |
---|---|---|
medium |
email |
Required. In the future, other mediums may be available. For now, email is the only acceptable medium. |
Description
This endpoint lets you enable or disable a notification for a user.
Because the PUT
HTTP Verb is idempotent, you can call this endpoint as many
times as you'd like, and only one notification will be created per user.
Errors
Example Error
{
"error": "example error message",
"status_code": 123
}
This section discusses Error Handling in the CanvasCBL API.
All errors are in JSON. See the example on the right.
The status_code
field is populated with the HTTP Status Code returned.
Session Error
Session error text
{
"error": "no session string (pass it in via the session_string cookie)",
"status_code": 401
}
This means that you have not passed in an Access Token via the Authorization header. This error won't show up if you pass in an invalid token, just a missing one.
Validation Errors
Validation Error Structure
{
"error": "<invalid/missing> <param name> as <param type, like url or query> param",
"status_code": 400
}
Trying to submit
abcdef
as an outcome ID
{
"error": "invalid outcomeID as query param",
"status_code": 400
}
Validation errors pop up all the time, and they all take on the same form.
See the example on the right.
OAuth2 Errors
OAuth2 Errors are self-evident:
missing requested scope
invalid access token
invalid refresh_token
- ...
If you encounter an error you feel should be here, please help us out and document it! These docs are open-source at github.com/canvascbl/api-docs.
Grades Errors
Example Grades Error With an Action
{
"error": "after refreshing the token, it is invalid",
"action": "redirect_to_oauth"
}
Grades errors sometimes include an action.
Action | What you should do |
---|---|
redirect_to_oauth |
Tell the user to log into CanvasCBL at canvascbl.com, then try again. |
retry_once |
Just try again in a sec. |
If no action is included, it's probably due to an extraordinary circumstance.
Currently, all possible grades errors are to the right.
const (
gradesErrorNoTokens = "no stored tokens for this user"
gradesErrorRevokedToken = "the token/refresh token has been revoked or no longer works"
gradesErrorRefreshedTokenError = "after refreshing the token, it is invalid"
gradesErrorUnknownCanvasError = "there was an unknown error from canvas"
gradesErrorInvalidInclude = "invalid include"
gradesErrorUnauthorizedScope = "your oauth2 grant doesn't have one or more requested scopes"
gradesErrorInvalidAccessToken = "invalid access token"
gradesErrorMissingCanvasScope = "we need a new canvas token from you"
)
Errors From Canvas
Errors from Canvas will use the non-standard HTTP Status Code 450
.
There are various reasons we chose to do this, but mostly, it's because almost every error from Canvas is
user-error, for example when you enter an invalid Outcome ID.
Glossary
The glossary contains definitions for terms that may not be clear throughout the documentation.
Developer Key
Client ID
d262d1d3-d969-4d48-ac1e-cfceec88b5c9
Client Secret
d262d1d3-d969-4d48-ac1e-cfceec88b5c9
A Client ID/Client Secret combo. These are granted, upon request and review, by CanvasCBL alone.
They may never be shared or posted publicly.
OAuth2 Credential
Another term for a Developer Key.
OAuth2 Grant
An OAuth2 Grant is a Access/Refresh Token combo. They are linked to a Redirect URI, a number of scopes, and a Developer Key.
You can see an example grant response in the Token request documentation.
OAuth2 Redirect URI
Example Redirect URI
https://dcraft.com/oauth2/response
Where users will be sent after accepting/denying your OAuth2 Request.
Access Token
Short-lived tokens that grant access to resources. Currently, they last an hour.
They can be regenerated with a Refresh Token.
Refresh Token
Long-lived tokens that can be used, along with some other information, to get new Access Tokens.
Auto-pagination
Throughout the docs, you might see that an endpoint says it's "auto-paginated".
Canvas employs a system of pagination that limits how many objects can be returned during a single API call. You can read more about that here.
The CanvasCBL API will automatically paginate responses from Canvas, meaning that every single resource requested will be returned. This comes at a performance cost, but that's ok because you often need all resources.
Some endpoints that use auto-pagination allow you to specify the object IDs you want returned. You can use those systems to limit the number of objects requested, therefore lowering the request time and response size.
Cached Data
Throughout the docs, you might see a reference to "cached data".
This means that the CanvasCBL API is not fetching the data on-demand from Canvas. It is using the CanvasCBL cache, which is updated about hourly. Additionally, some endpoints may let you choose whether you would like to pull from the CanvasCBL cache. Using the cache can speed up large requests (>100 results) by about 5x.
We tend to use the cache in the following scenarios:
- When requesting large amounts of data, like almost anything for an entire class
- When the endpoint does not require immediately-updated data (like get profile (CanvasCBL))
- When the request would take an unreasonable amount of time to fetch from Canvas