The Instructure Community will enter a read-only state on November 22, 2025 as we prepare to migrate to our new Community platform in early December. Read our blog post for more info about this change.
Found this content helpful? Log in or sign up to leave a like!
Have a question about the Canvas APIs? Have a cool API integration you'd be willing to share? If so, please post here.
Solved! Go to Solution.
Hi @EdithMurillo,
I think you just need a couple tweaks to your url...
First, I'm pretty sure you need to use the account call for this. Second, the parameter name is enrollment_term_id, not just term_id. Third, you need to swap your = and : around.
So in the end, your call should look like:
https://xxx.test.instructure.com/api/v1/accounts/1/courses?enrollment_term_id=sis_term_id:xxx
I hope this works for you!
-Chris
We are up and running a few months now with an API system that allows us to create courses, users and enrollments and then pull down submissions and grades. We're using PHP to read/write to a MySQL database that interacts on our side with our SIS:
SIS <> MySQL <> PHP <> Canvas API
Some of these phps are calling in bulk and some are targeted. We;re starting to get some undetermined fails or errors that we think may be related to API call limits. But there's nothing in results to indicate that, so not sure where all this is documented. We can certainly calibrate but how would I go about determining what the actual rule limits are so I can stay within reason on our side and manage how we hit the Canvas API?
Hi,
I need to enrol users in courses via the API.
The problem is I cannot know the course_id at the time the call is made. This is a problem seeing as the endpoint for enrolling a user is:
Is there any way for me to look up the course_id by some other key such as course_code?
Thanks in advance,
Simon
Yes, you can look up with other parameters. See Canvas LMS REST API Documentation
Throughout the API, objects are referenced by internal IDs. You can also reference objects by SIS ID, by prepending the SIS ID with the name of the SIS field, like sis_course_id:. For instance, to retrieve the list of assignments for a course with SIS ID of A1234:
/api/v1/courses/sis_course_id:A1234/assignments The following objects support SIS IDs in the API:
sis_course_idsis_login_idsis_term_idsis_user_idsis_account_idsis_section_idsis_group_idI can't believe I'd missed that in the documentation, thank you!
Simon
You are welcome. I did not catch it either. It was pointed out at Instructure Con this year at one of the API sessions I attended.
I'm getting the course id through my LTI launch. You can add custom fields to your LTI.
Hi,
I'm trying to determine whether a user exists in Canvas via the API by their email.
I'm calling
The single parameter that can be used is described like this:
Returns a list of Users
My API user is an admin.
The problem is that I'm getting unexpected results.
For example, I have 2 users with the same name registered, but with different email addresses:
[
{
"id": 2,
"name": "simon.taylor@icmponline.com",
"sortable_name": "simon.taylor@icmponline.com",
"short_name": "simon.taylor@icmponline.com",
"login_id": "simon.taylor@icmponline.com"
},
{
"id": 141,
"name": "Simon Taylor",
"sortable_name": "Taylor, Simon",
"short_name": "Simon Taylor",
"login_id": "simon.j.taylor@gmail.com"
}
]
I'd like to determine whether the user with the Gmail address exists:
GET /api/v1/accounts/1/users?access_token=CENSORED5&search_term=simon.j.taylor%40gmail.com HTTP/1.1
But this request returns both of the above users.
Am I doing something wrong?
Thanks,
Simon
Sure, but I don't know the user ID when I make the call.
I'd essentially like to be able to search for a user by their email to see if they are registered.
Thanks,
Simon
Have you tried using the Canvas reports
Settings->Reports: I find this an easier way of determine if a user exists. It also gives the ID number needed for future queires
I didn't know about that, thank you.
The problem is that this is all happening from a middleware integration so the search has to be via an API call. As far as I can tell the reports are requested and checked manually.
The API seems to behave strangely when using the search_term parameter.
I'd expect search_term=simon.j.taylor%40gmail.com to match that email but it seems to be partially matching on username.
"Queries by administrative users will search on SIS ID, name, or email address; non- administrative queries will only be compared against name."
My guess is that the search is trying to match SIS ID first, then name, then email. I'll try setting the SIS ID to be the email and see if that works.
Thanks,
Simon
Nope, it's still returning both... :smileyconfused:
If you are using an SIS_ID, and since they are unique, it makes more sense for the middleware to target a user, not search for one: /api/v1/users/sis_user_id:simon.j.taylor@gmail.com ....
... if that is an option for you.
Hi,
I'm trying to extract all calendar events from a course (from the beginning of the year to the end of the year). I've tried the 'GET api/v1/calendar_events' call but all I get back is an empty bracket [ ]. Does anyone know how to extract all calendar dates for a single course?
Thanks!
Dave
@dgilsdorf ,
You need to pass in the correct parameters... For instance for courseid= 110816 I could use:
sounds like you want:
all_events="true"
context_codes[]="course_COURSEIDNUM"
(also you need to decide if you want events or assignments using the type parameter. the default is events)
please note if you are using the command line how to pass in an array of context_codes.... use context_codes[] as the variable name.
Here is the docs: Calendar Events - Canvas LMS REST API Documentation
Hope that helps.
Josh
I need to create a report showing the file spaced used in a course. Last January in the Canvas release notes the item "storage_quota_used_mb" was said to be added to the API (Canvas Production Release Notes (2015-01-31) ). In the documentation for course data I see it listed (Courses - Canvas LMS REST API Documentation ), but that item is not being returned in the data.
I can see "storage_quota_mb", just not "storage_quota_used_mb". I'm calling /api/v1/courses in my curl.
Anyone know why it isn't showing up or where "storage_quota_used_mb" for a course might be found?
thanks,
Matt
Hi @mlewis23 ,
If you look in the documentation (Courses - Canvas LMS REST API Documentation) you will find "storage_quota_used_mb" under the optional include parameter. Your curl request url would look something like /courses/####/?include[]=storage_quota_used_mb.
That did it. Thank you.
Hi all,
Bit of a Canvas API noob here. I've got a call to Canvas to check for presence of a user with https://<canvas>/api/v1/accounts/[acc id]/users?access_token=[token no]&search_term=[user email] (Users - Canvas LMS REST API Documentation ), and I'm getting some mixed results. Just in my own testing of url strings I'm finding successful responses with some emails that exist in Canvas but not others where I get []. Searching by ID or name seems to always find the user but email is the only reliable unique identifier we can use. I'm also finding some users on their user profile page have a Default Email value which is different to the login_id value, and using the Default Email value as the search term returns the user while using the login_id value does not. And finally I'm finding some users that are returned when using a search term but not included in the full https://<canvas>/api/v1/accounts/[acc id]/users response.
Is there an admin permission I'm missing, or some secondary email field I'm not seeing which is what the search term actually checks for instead of login_id? Is there anything else regarding a user record which impacts whether their details can be retrieved by API? Appreciate any advice.
Philip,
That is an interesting one. I did a few tests on my instance but was unable to duplicate the issues you mentioned. I searched for myself with both emails I have on file and was able to find my record both ways. Granted, one of my email addresses is actually associated with my admin account, my student account and a couple of other test users.
The documentation you cited states:
Queries by administrative users will search on SIS ID, name, or email address; non- administrative queries will only be compared against name.
To my knowledge there is not a way to search based on the users login_id. It doesn't sound like this will help, but if your users come from an SIS you can combine sis_login_id: with the user's sis login id and use that in place of a user ID (example /api/v1/users/sis_login_id:<loginID>). See Object IDs, SIS IDs, and special IDs for more information on that.
As a little side note about API's, as long as you are logged into Canvas, you can enter the url in the address bar without the need for passing the access_token. In fact, passing the access_token as a url parameter is not really a good idea. For example, you could paste something like this:
https://institution.instructure.com/api/v1/accounts/self/users?search_term=john.doe@domain.com
I know that doesn't necessarily answer your question but hopefully it can at least provide a little help.
Okay, I did some more digging and was able to duplicate the [ ] response and may have figured out what is causing it. Each of the users that returned that response had never logged in. That is the only consistent factor I could discover. Hope that helps.
Thanks for your replies Kenneth, they're a big help. I was wondering about the login thing, as it's particularly happening with test users I'm creating (which I'm not subsequently logging in to Canvas with). In my code if a matching user isn't found in Canvas then I create one with the right credentials. Question now is, why aren't there a dozen test@test.com Test User records in my Canvas test instance now since it's not finding the matching Test User record after creation on subsequent tests and should be creating additional ones?
The login thing is actually your credentials. If you wanted to complete an API call that way as a test user, then you would need to login as that test user. For what you are doing, however, I doubt you are creating an OAuth token for each test user and running the calls with that token. Most test users would probably not have permission to search all of your account users either.
As far as why to don't have a dozen test@test.com users, I couldn't say because I am not aware of how you are creating the users and I have not had reason to create a workflow similar to what you are describing. Are you getting the verification back that the user was successfully created? If so, that returned JSON should contain a Canvas user id. If you do not have a whole bunch of users, I would probably guess that you would be getting an error about the user already existing, but that is just guess.
@philip1 , any chance you ever figured this out? I'm running in to something similar where I need to access users through the API based on their email address, which will always be the login ID, since they are also being created through the API. I've noticed that various users are not searchable through the API at all though, but if I go to their user profile API endpoint then they are there, so it seems like the exact issue you had.
I've checked for any difference I can think of between accounts that could cause it. I've checked whether they've logged in or not, whether they are enrolled in a course, whether that course is published or not, no matter how identical the accounts are they still won't come back.
Hi all,
I'm an API noob--but I'm hoping to get some help with something I'm experiencing. Its kind of specific for K-12--but I'm hoping someone can help.
I'm trying to make an API call to get a grade for a student in a grading period. We're using the Multiple Grading Periods feature option--and this is the API call I'm making: https://yourinstitution.instructure.com:443/api/v1/courses/{{coursenumber}}/enrollments?user_id={{us...
When I make this call--I'm getting a null value for the grade. My grading period ID matches what is returned when I make a call on the grading period. What am I missing?
Hi all--
I was able to figure this out--and thought I'd post what I've found just in case anyone else ever needs to know.
It seems to be related to a permissions issue with multiple grading periods/enrollments.
I'm assuming some of this is related to the fact that the grading period API is in beta--but thought I'd share my findings for anyone else who may need it.
I have questions about the oAuth refresh tokens mentioned in today's production release. I don't fully understand the implications of this change. What sorts of scenarios would lead to the use of a refresh token? I've read the documentation [OAuth2 - Canvas LMS REST API Documentation ], but I'm still missing something.
There is something else that is new(?) in the oAuth documentation that wasn't mentioned in the notes:
"When the user is asked to grant your application access in step 2 of the web application flow, they will also be given an option to remember their authorization. If they grant access and remember the authorization, Canvas will skip step 2 of the request flow for future requests."
I've never observed that behavior, and I never noticed it in the docs until today, so I'm assuming it is new. What do I have to do as a developer to take advantage of the skipped step? Does the issue of the refresh token depend in any way on the user's decision to 'remember' the authorization? Bottom line, is it safe to assume that my existing workflows will not be disrupted by any of these changes?
That is a good find @BKINNEY , thank you for sharing it. I had somehow missed it as I scanned through the production release notes. I agree that the documentation is lacking in information regarding this process, but here is my understanding.
Way it has worked:
New method:
I think the theory is that an OAuth token can stand alone and could be used if your application is compromised. A refresh token is connected to your developer credentials and can only be used in connection with those credentials to retrieve a new OAuth token. This reduces the danger of someone getting access to an OAuth token requested by an app.
As far as your second observation about "step 2", I am guessing that we have not seen that because we are among the existing developer keys that do not have to use a refresh token yet. My guess (which is all this is) would be that if they choose not to remember the authorization, you would not receive a refresh token, only the short lived OAuth token. That way they would be asked every time to authorize the app.
Will your existing workflows be disrupted?
I would say yes, eventually. I would imagine that is what the following line from the release notes means "Future communication will be provided advising when we will be enforcing the use of refresh tokens for all developer keys." Based on this new information, I will be spending some time in the next couple of days looking at the response from the OAuth token request to figure out if a refresh token exists and thinking through what that might mean for us as developers. I will endeavor to come back and report on anything I discover.
I would also love it if anyone who knows more about this process would chime in with further clarification.
Thanks, that helps a lot. I understand that you are guessing, but it all makes sense. Please let us know if you learn anything further. I'll look for refresh tokens as well, and we can compare notes here.
Hello All,
I seem to be have in issue with refreshing my canvas token. My process is set to request the authorization code from then redirects to my program to process that code and request a token to be used and stored. Using this initial token I am able to make requests for enrollments, courses, users etc... if that token was deleted or expired then I refresh it and try again.
Below is my request for my initial token with LMS_KEY and LMS_SECRET being values for my actual information.
<?php
$url = "https://felbry.instructure.com/login/oauth2/token";
$oauth = array( 'client_id' => LMS_KEY,
'client_secret' => LMS_SECRET,
'grant_type' => 'authorization_code',
'redirect_uri' => 'https://stars.trainingmasters.com:82/php/FLMS010.php',
'code' => $code);
$header = array('Authorization: Basic ' . base64_encode(LMS_KEY . LMS_SECRET));
$PostFields = buildAuthorizationHeader($oauth);
$options = array( CURLOPT_HTTPHEADER => $header,
CURLOPT_HEADER => false,
CURLINFO_HEADER_OUT => true,
CURLOPT_POST => true,
CURLOPT_POSTFIELDS => $PostFields,
CURLOPT_URL => $url,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_SSL_VERIFYPEER => false);
$feed = curl_init();
curl_setopt_array($feed, $options);
$json = curl_exec($feed);
$headerSent = curl_getinfo($feed, CURLINFO_HEADER_OUT );
curl_close($feed);
$Oauth_Data = json_decode($json,true);
$Token = $Oauth_Data['access_token'];
$RefToken = $Oauth_Data['refresh_token'];
?>
I then use this token to make the request for all completed courses:
$url = "https://felbry.instructure.com/api/v1/courses?state=completed";
$header = array('Authorization: Bearer ' . trim($Token));
$options = array( CURLOPT_HTTPHEADER => $header,
CURLOPT_HEADER => false,
CURLINFO_HEADER_OUT => true,
CURLOPT_URL => $url,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_SSL_VERIFYPEER => false);
$feed = curl_init();
curl_setopt_array($feed, $options);
$json = curl_exec($feed);
$headerSent = curl_getinfo($feed, CURLINFO_HEADER_OUT );
curl_close($feed);
$Oauth_Data2 = json_decode($json,true);
echo '<pre>'.print_r($Oauth_Data2,true).'</pre>';
When I print the result I get a list of all courses as expected.
Then I configure my program to fake a new token so I can trigger my logic to refresh the token. To refresh the token I use the following request $RefToken is the token collected from the initial request:
<?php
$url = "https://felbry.instructure.com/login/oauth2/token";
$oauth = array( 'client_id' => LMS_KEY,
'client_secret' => LMS_SECRET,
'grant_type' => 'refresh_token',
'refresh_token' => trim($RefToken));
$header = array('Authorization: Basic ' . base64_encode(LMS_KEY . LMS_SECRET));
$PostFields = buildAuthorizationHeader($oauth);
$options = array( CURLOPT_HTTPHEADER => $header,
CURLOPT_HEADER => false,
CURLINFO_HEADER_OUT => true,
CURLOPT_POST => true,
CURLOPT_POSTFIELDS => $PostFields,
CURLOPT_URL => $url,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_SSL_VERIFYPEER => false);
$feed = curl_init();
curl_setopt_array($feed, $options);
$json = curl_exec($feed);
$headerSent = curl_getinfo($feed, CURLINFO_HEADER_OUT );
curl_close($feed);
$Oauth_Data = json_decode($json,true);
$Token = $Oauth_Data['access_token'];
?>
This Process seems to work since I get a new token but when I attempt to use that new token to make the same courses request as above i receive the following message:
Array
(
[errors] => Array
(
[0] => Array
(
[message] => Invalid access token.
)
)
[error_report_id] => 2259
)
I have printed all my values out before and after all requests and everything is sending what its supposed to. I have used this process for other Oauth authentication with no issues. Any help with this issue would be great.
Thank you.
When you say that "$RefToken is the token collected from the initial request" do you mean you are using the OAuth token from the initial request or the refresh token from the initial request. From the code you posted, it looks like you are only grabbing the access_token. The request from Canvas includes an "access_token" and a "refresh_token". The "access_token" is used to make API calls, the "refresh_token" is used to obtain a new OAuth token. This may be old news to you if you have used the process for other OAuth authentication, but for those of us developing specifically for Canvas, this is a new addition. As you may have noticed in the comments just above yours, we are still trying to figure out the implications of the refresh token.
I missed that piece when copying my code but I am using the refresh token found in the refresh_token value from the JSON request. My apologies for the mix-up.
This is actually great. I'm happy to see code from someone familiar with the refresh process.
Can you explain a bit about the header you are sending along with your refresh token:
$header = array('Authorization: Basic ' . base64_encode(LMS_KEY . LMS_SECRET));
That's not in the Canvas API docs, and I've not done that before when posting to the /login/oauth2/token page. The docs just say to POST to the page, so that's all I've ever done. Most likely that has nothing to do with the reason why your new token is failing. Maybe the new one won't work unless the old one has expired? I hope a Canvas developer will chime in on this thread. I'd like to have a new process in place well before my old one stops working.
Previous OAuth systems I have worked with required the Client Id and Secret to be encode and sent as a header as part of getting the access token, this applies to both the initial token and getting a new token. If don't think Canvas requires this encoding but I continued it to add an extra layer or security to the request.
Thanks for the clarification. Sorry I am not more help, that was the only thing that I noticed skimming through your code. However, you do use a different approach than I do. I am hoping to rework one of my tools next week to use the refresh token. I will chime back into this thread if I experience the same issue or if I can figure it out.
I'm just beginning to work on the logic of what I'd like to do, so details are a bit sketchy. I need to add the same new page to the same module in about 75 different courses. The module is named/titled the same in each course, but of course has a different module id in each course. I have the course IDs in a CSV file and plan to loop through those course IDs and create a new page and then add that page to the module. However, I'm not sure how to identify the module ID as I go through each course. Is there a way to specify the module by name/title, or lookup the module ID based on the name/title?
This is a common scenario for us as we frequently have new or updated content that we need to add to many/all of our courses in Canvas. The body of the content is the same for every course and it's always going into the same module which exists in every course. Previously we've had to do this manually, one course at a time, which seems very inefficient.
If anyone has successfully done something similar, I'd love to see the code you used. I'm planning to use Python, but I'm open to other suggestions if someone already has this working.
Thanks!
-Brett
The module listing API supports search, so that should help some. Probably
want to import only when the module search only turns up one result, and
then mop up the others manually.
Becky Kinney
Academic Technology Services
Project Blog <http://sites.udel.edu/bkinney/>
On Wed, Dec 2, 2015 at 11:05 AM, brett.pfingston@harrison.edu <
I would agree with @BKINNEY 's approach. The API you want is List Modules, you can use the search_term parameter to identify the module and retrieve it's id.
Thanks Becky and Kenneth!
-Brett
Hi All,
I'm working on a project to scan quizzes for certain combinations of settings that are proving problematic, or that are using either Lockdown Browser or Proctorio.
I'd prefer to not have to load all courses to then load all /courses/quizzes to scan every quiz for it's create/edit date. What I need is a way to use the API to retrieve all quizzes that were created or edited in the last 24 hours. Is there a filter on /quizzes that would do this?
Thanks ,Glen
Community helpTo interact with Panda Bot, our automated chatbot, you need to sign up or log in:
Sign inTo interact with Panda Bot, our automated chatbot, you need to sign up or log in:
Sign in