Found this content helpful? Log in or sign up to leave a like!

Adding Students to a Course via API

Jump to solution
cpesther
Community Member

Goal: Given a student's name and email address, I'd like to get them added to a course using the Canvas API and Python. For my purposes, either creating a Canvas account for them or sending them an invitation email to self register would be acceptable. I am using a Canvas Free for Teacher account and am the instructor for this course with a valid and working API token. 

Problem: I have yet to find the a proper API endpoint and data structure that yield any positive results for either of the two options above. The API documentation is rather vague, and I am unable to find my account ID parameter (perhaps because I'm on a free account?) that would be needed for the request structure in the documentation. 

Attempts: I have seen several older threads all with different solutions. For all attempts, here's what my header structure looks like. 

api_token = token goes here
c_headers = {
    'Authorization': f'Bearer {api_token}'
}

Here's what I've tried so far. 

The option below yields a 400 response...

url = "https://canvas.instructure.com/api/v1/accounts/self/users"
data = {
    'user[name]':'Johnny Doe',
    'user[short_name]':'John Doe',
    'user[sortable_name]':'Doe, Johnny',
    'pseudonym[unique_id]':'johndoe@johndoe.com'
}

response = requests.post(url, headers=c_headers, data=data)

...and this one below also returns 400. 

url = "https://canvas.instructure.com/api/v1/accounts/self/users"
data = {
    'name':'Johnny Doe',
    'short_name':'John Doe',
    'sortable_name':'Doe, Johnny',
    'unique_id':'johndoe@johndoe.com'
}

response = requests.post(url, headers=c_headers, data=data)

This option below with a different data structure yields a 500 response.

url = "https://canvas.instructure.com/api/v1/accounts/self/users"
data = {
    'user': {
        'name': 'Johnny Doe',
        'short_name': 'John Doe',
        'sortable_name':'Doe, Johnny'
    },
    'pseudonym': {
        'unique_id': 'johndoe@johndoe.com'
    }
}

response = requests.post(url, headers=c_headers, data=data)

 

Ultimately, I just need a solution that I can feed a name and email so that a student will get automatically added or invited to my course once they complete an external registration form, so I am open to other suggestions or workflows that achieve this same result. 

Thanks!

Labels (1)
0 Likes
2 Solutions

Hi @cpesther,

One more thing to perhaps try to add after reviewing the API more...

'user[terms_of_use]'=True

It may end up being that you won't be able to use the API for user creation with the free-for-teacher instance, but I haven't tried it myself (I also know that behind the scenes there are some different configs on different free-for-teacher subaccounts, which complicates trying to test and replicate results).

I moved the post to the developers area of the community, where some API experts tend to hang out, but I could also move it over to the free-for-teacher area later if needed.

-Chris

View solution in original post

cpesther
Community Member
Author

Okay, the combination of y'all answers was the solution! Here's all the details for future folks:

Solution: To create a Canvas account for a student using the Canvas API on the Free for Teachers plan, go through the following steps. 

Create a Canvas Account for the Student

This process creates an account in the Canvas system for the student, but doesn't yet add them to your course (that comes later). Use the following structure for your request.

# If on Free for Teacher plan, use '10' for the account ID parameter
account_id = 10
account_url = f"https://canvas.instructure.com/api/v1/accounts/{account_id}/users"
account_data = {
    'user': {
        'name': 'Johnny Doe',
        'short_name': 'John Doe',
        'sortable_name':'Doe, Johnny',
        'terms_of_use':True  # Required
    },
    'pseudonym': {
        'unique_id': 'johndoe@johndoe.com',
        'force_self_registration':True  # Required to send email
    }
}
response = requests.post(account_url, headers=c_headers, json=account_data)

Once this response is successful, a Canvas account will have been created for this user and they should receive an email asking them to confirm and complete registration. In the text response to this request will be the ID number; this is important if you want to enroll the user in a course in the next step. 

If the email address you provided is already associated with a Canvas account, you will receive a 400 error and the response will include a message indicating that the email already belongs to a user. You'll need to implement some other solution in your code for when/if this occurs. 

Enrolling the Student in a Course

Now that the student has an account, the next logical step is to go ahead and enroll them as a student in your course. The two lines of code below are an example of how to extract the user ID number from the response to account creation above. Your code will vary. 

new_user_data = json.loads(response.text)  # Convert string return into a dict
new_user_id = new_user_data.get('id')  # Get the ID number of the new user

Now that we have the ID number for the new user, we can put together an API request to enroll them in the course, which should be structured as seen below. You can most likely format the data for this request in the json-esqe format used for the previous one, but this is just the structure that happened to work for me. Make sure to replace the {course_id} argument with the ID number for the course in which you want to enroll the user. 

# Package up all of the enrollment request data
course_id = 0000000000
enroll_url = f'https://canvas.instructure.com/api/v1/courses/{course_id}/enrollments'
enroll_data = {
    'enrollment[user_id]':new_user_id,  # Required
    'enrollment[type]':'StudentEnrollment',  # Required
    'enrollemnt[notify]':True,
    'enrollment[enrollment_state]':'active' 
}

# Make the request to the API
enroll_response = requests.post(enroll_url, headers=c_headers, data=enroll_data)

Setting the enrollment state to active means that they won't be listed as a pending student in your roster, if that is your preference. Listing a student as active is also useful (at least in my case) since their email address will then be associated with their student profile, which is not the case for pending students, for whatever reason. This is helpful if you need to compare an external list of names and emails to the ones already enrolled in the course to prevent repeat/excess enrollment requests. It should also help save the student a step of needing to accept an invitation. 

Thanks so much for everyone's help!

View solution in original post