Canvas API: Create Users, Courses, and Enroll Students (Code Examples)
Formswrite Team
•
February 15, 2026

Canvas API: Create Users, Courses, and Enroll Students
This guide covers the most common Canvas API operations with complete code examples: creating users, building courses, enrolling students, and managing grades.
Prerequisites
- A Canvas LMS instance (institutional or free teacher account)
- An Access Token (Account → Settings → Approved Integrations → New Access Token)
- Admin permissions for user creation (or use the free teacher account for course management)
Create Users
POST /api/v1/accounts/:account_id/users
Requires admin permissions.
bashcurl -X POST "https://yourschool.instructure.com/api/v1/accounts/1/users" \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"user": {
"name": "Jane Smith",
"short_name": "Jane",
"sortable_name": "Smith, Jane",
"terms_of_use": true,
"skip_registration": true
},
"pseudonym": {
"unique_id": "[email protected]",
"password": "SecurePass123!",
"sis_user_id": "STU-2026-001",
"send_confirmation": false
}
}'
Response
json{
"id": 142,
"name": "Jane Smith",
"short_name": "Jane",
"sortable_name": "Smith, Jane",
"email": "[email protected]",
"login_id": "[email protected]",
"created_at": "2026-02-15T10:30:00Z"
}
Python: Create Multiple Users
pythonimport requests
CANVAS_URL = "https://yourschool.instructure.com"
TOKEN = "your_access_token"
ACCOUNT_ID = 1
headers = {
"Authorization": f"Bearer {TOKEN}",
"Content-Type": "application/json"
}
students = [
{"name": "Alice Johnson", "email": "[email protected]", "sis_id": "STU-001"},
{"name": "Bob Williams", "email": "[email protected]", "sis_id": "STU-002"},
{"name": "Carol Davis", "email": "[email protected]", "sis_id": "STU-003"},
]
created_users = []
for student in students:
response = requests.post(
f"{CANVAS_URL}/api/v1/accounts/{ACCOUNT_ID}/users",
headers=headers,
json={
"user": {
"name": student["name"],
"terms_of_use": True,
"skip_registration": True
},
"pseudonym": {
"unique_id": student["email"],
"password": "Welcome2026!",
"sis_user_id": student["sis_id"],
"send_confirmation": False
}
}
)
user = response.json()
created_users.append(user)
print(f"Created: {user['name']} (ID: {user['id']})")
Get All Users
GET /api/v1/accounts/:account_id/users
bashcurl "https://yourschool.instructure.com/api/v1/accounts/1/users?per_page=100" \
-H "Authorization: Bearer YOUR_TOKEN"
Python: Search Users
python# Search by email
response = requests.get(
f"{CANVAS_URL}/api/v1/accounts/{ACCOUNT_ID}/users",
headers=headers,
params={
"search_term": "[email protected]",
"per_page": 10
}
)
users = response.json()
# List all users with pagination
def get_all_users():
url = f"{CANVAS_URL}/api/v1/accounts/{ACCOUNT_ID}/users?per_page=100"
all_users = []
while url:
response = requests.get(url, headers=headers)
all_users.extend(response.json())
links = response.headers.get("Link", "")
url = None
for link in links.split(","):
if 'rel="next"' in link:
url = link.split(";")[0].strip("<> ")
return all_users
Create Courses
POST /api/v1/accounts/:account_id/courses
bashcurl -X POST "https://yourschool.instructure.com/api/v1/accounts/1/courses" \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"course": {
"name": "Biology 101 - Spring 2026",
"course_code": "BIO101-SP26",
"start_at": "2026-01-15T00:00:00Z",
"end_at": "2026-05-15T00:00:00Z",
"license": "private",
"is_public": false,
"default_view": "modules"
}
}'
Python: Create Multiple Courses
pythoncourses = [
{"name": "Biology 101", "code": "BIO101"},
{"name": "Chemistry 201", "code": "CHEM201"},
{"name": "Physics 301", "code": "PHYS301"},
]
for c in courses:
response = requests.post(
f"{CANVAS_URL}/api/v1/accounts/{ACCOUNT_ID}/courses",
headers=headers,
json={
"course": {
"name": c["name"],
"course_code": c["code"],
"default_view": "modules"
},
"offer": True # Publish immediately
}
)
course = response.json()
print(f"Created course: {course['name']} (ID: {course['id']})")
Get All Courses
pythonresponse = requests.get(
f"{CANVAS_URL}/api/v1/courses",
headers=headers,
params={"per_page": 100}
)
for course in response.json():
print(f"{course['id']}: {course['name']} ({course.get('course_code', 'N/A')})")
Enroll Students
POST /api/v1/courses/:course_id/enrollments
Enrollment Types
| Type | Role |
|---|---|
StudentEnrollment | Student |
TeacherEnrollment | Teacher |
TaEnrollment | Teaching Assistant |
ObserverEnrollment | Observer |
DesignerEnrollment | Designer |
cURL: Enroll a Student
bashcurl -X POST "https://yourschool.instructure.com/api/v1/courses/5/enrollments" \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"enrollment": {
"user_id": 142,
"type": "StudentEnrollment",
"enrollment_state": "active",
"notify": false
}
}'
Python: Bulk Enroll Students
pythoncourse_id = 5
student_ids = [142, 143, 144, 145, 146]
for uid in student_ids:
response = requests.post(
f"{CANVAS_URL}/api/v1/courses/{course_id}/enrollments",
headers=headers,
json={
"enrollment": {
"user_id": uid,
"type": "StudentEnrollment",
"enrollment_state": "active",
"notify": False
}
}
)
enrollment = response.json()
print(f"Enrolled user {uid}: {enrollment.get('id', 'error')}")
Enroll by SIS ID
bashcurl -X POST "https://yourschool.instructure.com/api/v1/courses/5/enrollments" \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"enrollment": {
"user_id": "sis_user_id:STU-001",
"type": "StudentEnrollment",
"enrollment_state": "active"
}
}'
Complete Workflow: Course Setup
pythonimport requests
CANVAS_URL = "https://yourschool.instructure.com"
TOKEN = "your_token"
ACCOUNT_ID = 1
headers = {
"Authorization": f"Bearer {TOKEN}",
"Content-Type": "application/json"
}
# Step 1: Create the course
course = requests.post(
f"{CANVAS_URL}/api/v1/accounts/{ACCOUNT_ID}/courses",
headers=headers,
json={
"course": {
"name": "Biology 101 - Spring 2026",
"course_code": "BIO101",
"default_view": "modules"
},
"offer": True
}
).json()
course_id = course["id"]
print(f"Course created: {course_id}")
# Step 2: Create students
students = [
{"name": "Alice", "email": "[email protected]"},
{"name": "Bob", "email": "[email protected]"},
]
user_ids = []
for s in students:
user = requests.post(
f"{CANVAS_URL}/api/v1/accounts/{ACCOUNT_ID}/users",
headers=headers,
json={
"user": {"name": s["name"], "skip_registration": True},
"pseudonym": {"unique_id": s["email"], "password": "Welcome2026!"}
}
).json()
user_ids.append(user["id"])
print(f"User created: {user['name']} ({user['id']})")
# Step 3: Enroll students
for uid in user_ids:
requests.post(
f"{CANVAS_URL}/api/v1/courses/{course_id}/enrollments",
headers=headers,
json={
"enrollment": {
"user_id": uid,
"type": "StudentEnrollment",
"enrollment_state": "active"
}
}
)
print(f"Enrolled {len(user_ids)} students in course {course_id}")
# Step 4: Create a module
module = requests.post(
f"{CANVAS_URL}/api/v1/courses/{course_id}/modules",
headers=headers,
json={"module": {"name": "Week 1: Introduction", "position": 1}}
).json()
print(f"Module created: {module['id']}")
Adding Quizzes to Your Courses
Once your course structure is set up, you'll want to add assessments. Creating quizzes through the Canvas API requires building each question individually with complex JSON — for a 50-question quiz, that's 50+ API calls.
A faster approach: use Formswrite to convert a Google Doc into a Canvas QTI package, then import it.
bash# 1. Convert Google Doc to Canvas QTI via Formswrite
curl -X POST https://api.formswrite.com/api/v1/convert \
-H "Authorization: Bearer FORMSWRITE_TOKEN" \
-H "Content-Type: application/json" \
-d '{"documentId": "DOC_ID", "format": "canvas"}'
# 2. Download the QTI .zip file from the response URL
# 3. Import into Canvas via Settings → Import Course Content → QTI .zip file
This approach: write questions naturally in a Google Doc, let AI handle the conversion, and import into Canvas in seconds.
FAQ
How do I get a Canvas API access token?
Account → Settings → Approved Integrations → New Access Token. Copy it immediately — it won't be shown again.
Can I create users without admin permissions?
No. User creation requires account-level admin access. Individual teachers can manage enrollments in their own courses.
What enrollment types are available?
StudentEnrollment, TeacherEnrollment, TaEnrollment, ObserverEnrollment, and DesignerEnrollment.
Can I enroll users by email instead of user ID?
Not directly. You need the user's Canvas ID or SIS ID. Search for the user first with the users API, then enroll by ID.
Summary
The Canvas API makes it straightforward to automate user creation, course setup, and enrollments. For quiz content, pair it with Formswrite to convert Google Docs into Canvas QTI packages — significantly faster than building quizzes through the API.