google-classroom
# Google Classroom
Access the Google Classroom API with managed OAuth authentication. Manage courses, coursework, students, teachers, announcements, and submissions.
## Quick Start
```bash
# List all courses
python3 <<'EOF'
import urllib.request, os, json
req = urllib.request.Request('https://gateway.maton.ai/google-classroom/v1/courses')
req.add_header('Authorization', f'Bearer {os.environ["MATON_API_KEY"]}')
print(json.dumps(json.load(urllib.request.urlopen(req)), indent=2))
EOF
```
## Base URL
```
https://gateway.maton.ai/google-classroom/{api-path}
```
The Google Classroom API uses the path pattern:
```
https://gateway.maton.ai/google-classroom/v1/{resource}
```
## Authentication
All requests require the Maton API key in the Authorization header:
```
Authorization: Bearer $MATON_API_KEY
```
**Environment Variable:** Set your API key as `MATON_API_KEY`:
```bash
export MATON_API_KEY="YOUR_API_KEY"
```
### Getting Your API Key
1. Sign in or create an account at [maton.ai](https://maton.ai)
2. Go to [maton.ai/settings](https://maton.ai/settings)
3. Copy your API key
## Connection Management
Manage your Google Classroom OAuth connections at `https://ctrl.maton.ai`.
### List Connections
```bash
python3 <<'EOF'
import urllib.request, os, json
req = urllib.request.Request('https://ctrl.maton.ai/connections?app=google-classroom&status=ACTIVE')
req.add_header('Authorization', f'Bearer {os.environ["MATON_API_KEY"]}')
print(json.dumps(json.load(urllib.request.urlopen(req)), indent=2))
EOF
```
### Create Connection
```bash
python3 <<'EOF'
import urllib.request, os, json
data = json.dumps({'app': 'google-classroom'}).encode()
req = urllib.request.Request('https://ctrl.maton.ai/connections', data=data, method='POST')
req.add_header('Authorization', f'Bearer {os.environ["MATON_API_KEY"]}')
req.add_header('Content-Type', 'application/json')
print(json.dumps(json.load(urllib.request.urlopen(req)), indent=2))
EOF
```
### Get Connection
```bash
python3 <<'EOF'
import urllib.request, os, json
req = urllib.request.Request('https://ctrl.maton.ai/connections/{connection_id}')
req.add_header('Authorization', f'Bearer {os.environ["MATON_API_KEY"]}')
print(json.dumps(json.load(urllib.request.urlopen(req)), indent=2))
EOF
```
**Response:**
```json
{
"connection": {
"connection_id": "8efa1361-0e86-40b1-a63b-53a5051f8ac6",
"status": "ACTIVE",
"creation_time": "2026-02-14T00:00:00.000000Z",
"last_updated_time": "2026-02-14T00:00:00.000000Z",
"url": "https://connect.maton.ai/?session_token=...",
"app": "google-classroom",
"metadata": {}
}
}
```
Open the returned `url` in a browser to complete OAuth authorization.
### Delete Connection
```bash
python3 <<'EOF'
import urllib.request, os, json
req = urllib.request.Request('https://ctrl.maton.ai/connections/{connection_id}', method='DELETE')
req.add_header('Authorization', f'Bearer {os.environ["MATON_API_KEY"]}')
print(json.dumps(json.load(urllib.request.urlopen(req)), indent=2))
EOF
```
### Specifying Connection
If you have multiple Google Classroom connections, specify which one to use with the `Maton-Connection` header:
```bash
python3 <<'EOF'
import urllib.request, os, json
req = urllib.request.Request('https://gateway.maton.ai/google-classroom/v1/courses')
req.add_header('Authorization', f'Bearer {os.environ["MATON_API_KEY"]}')
req.add_header('Maton-Connection', '8efa1361-0e86-40b1-a63b-53a5051f8ac6')
print(json.dumps(json.load(urllib.request.urlopen(req)), indent=2))
EOF
```
If omitted, the gateway uses the default (oldest) active connection.
## API Reference
### Courses
#### List Courses
```bash
GET /v1/courses
GET /v1/courses?courseStates=ACTIVE
GET /v1/courses?teacherId=me
GET /v1/courses?studentId=me
GET /v1/courses?pageSize=10
```
**Query Parameters:**
- `courseStates` - Filter by state: `ACTIVE`, `ARCHIVED`, `PROVISIONED`, `DECLINED`, `SUSPENDED`
- `teacherId` - Filter by teacher ID (use `me` for current user)
- `studentId` - Filter by student ID (use `me` for current user)
- `pageSize` - Number of results per page (max 100)
- `pageToken` - Token for next page
**Response:**
```json
{
"courses": [
{
"id": "825635865485",
"name": "Introduction to Programming",
"section": "Section A",
"descriptionHeading": "CS 101",
"description": "Learn the basics of programming",
"ownerId": "102753038276005039640",
"creationTime": "2026-02-14T01:53:58.991Z",
"updateTime": "2026-02-14T01:53:58.991Z",
"enrollmentCode": "3qsua37m",
"courseState": "ACTIVE",
"alternateLink": "https://classroom.google.com/c/ODI1NjM1ODY1NDg1",
"guardiansEnabled": false
}
],
"nextPageToken": "..."
}
```
#### Get Course
```bash
GET /v1/courses/{courseId}
```
#### Create Course
```bash
POST /v1/courses
Content-Type: application/json
{
"name": "Course Name",
"section": "Section A",
"descriptionHeading": "Course Title",
"description": "Course description",
"ownerId": "me"
}
```
**Response:**
```json
{
"id": "825637533405",
"name": "Course Name",
"section": "Section A",
"ownerId": "102753038276005039640",
"courseState": "PROVISIONED",
"enrollmentCode": "abc123"
}
```
#### Update Course
```bash
PATCH /v1/courses/{courseId}?updateMask=name,description
Content-Type: application/json
{
"name": "Updated Course Name",
"description": "Updated description"
}
```
**Note:** Use `updateMask` query parameter to specify which fields to update.
#### Delete Course
```bash
DELETE /v1/courses/{courseId}
```
**Note:** Courses must be archived before deletion. To archive, update the course with `courseState: "ARCHIVED"`.
### Course Work (Assignments)
#### List Course Work
```bash
GET /v1/courses/{courseId}/courseWork
GET /v1/courses/{courseId}/courseWork?courseWorkStates=PUBLISHED
GET /v1/courses/{courseId}/courseWork?orderBy=dueDate
```
**Query Parameters:**
- `courseWorkStates` - Filter by state: `PUBLISHED`, `DRAFT`, `DELETED`
- `orderBy` - Sort by: `dueDate`, `updateTime`
- `pageSize` - Number of results per page
- `pageToken` - Token for next page
#### Get Course Work
```bash
GET /v1/courses/{courseId}/courseWork/{courseWorkId}
```
#### Create Course Work
```bash
POST /v1/courses/{courseId}/courseWork
Content-Type: application/json
{
"title": "Assignment Title",
"description": "Assignment description",
"workType": "ASSIGNMENT",
"state": "PUBLISHED",
"maxPoints": 100,
"dueDate": {
"year": 2026,
"month": 3,
"day": 15
},
"dueTime": {
"hours": 23,
"minutes": 59
}
}
```
**Work Types:**
- `ASSIGNMENT` - Regular assignment
- `SHORT_ANSWER_QUESTION` - Short answer question
- `MULTIPLE_CHOICE_QUESTION` - Multiple choice question
**States:**
- `DRAFT` - Not visible to students
- `PUBLISHED` - Visible to students
#### Update Course Work
```bash
PATCH /v1/courses/{courseId}/courseWork/{courseWorkId}?updateMask=title,description
Content-Type: application/json
{
"title": "Updated Title",
"description": "Updated description"
}
```
#### Delete Course Work
```bash
DELETE /v1/courses/{courseId}/courseWork/{courseWorkId}
```
### Student Submissions
#### List Student Submissions
```bash
GET /v1/courses/{courseId}/courseWork/{courseWorkId}/studentSubmissions
GET /v1/courses/{courseId}/courseWork/{courseWorkId}/studentSubmissions?states=TURNED_IN
```
**Query Parameters:**
- `states` - Filter by state: `NEW`, `CREATED`, `TURNED_IN`, `RETURNED`, `RECLAIMED_BY_STUDENT`
- `userId` - Filter by student ID
- `pageSize` - Number of results per page
- `pageToken` - Token for next page
**Note:** Course work must be in `PUBLISHED` state to list submissions.
**Response:**
```json
{
"studentSubmissions": [
{
"courseId": "825635865485",
"courseWorkId": "825637404958",
"id": "Cg4I8ufNwwYQ7tSZgYIB",
"userId": "102753038276005039640",
"creationTime": "2026-02-14T02:30:00.000Z",
"state": "NEW",
"alternateLink": "https://classroom.google.com/..."
}
]
}
```
#### Get Student Submission
```bash
GET /v1/courses/{courseId}/courseWork/{courseWorkId}/studentSubmissions/{submissionId}
```
#### Grade Submission
```bash
PATCH /v1/courses/{courseId}/courseWork/{courseWorkId}/studentSubmissions/{submissionId}?updateMask=assignedGrade,draftGrade
Content-Type: application/json
{
"assignedGrade": 95,
"draftGrade": 95
}
```
#### Return Submission
```bash
POST /v1/courses/{courseId}/courseWork/{courseWorkId}/studentSubmissions/{submissionId}:return
Content-Type: application/json
{}
```
### Teachers
#### List Teachers
```bash
GET /v1/courses/{courseId}/teachers
```
**Response:**
```json
{
"teachers": [
{
"courseId": "825635865485",
"userId": "102753038276005039640",
"profile": {
"id": "102753038276005039640",
"name": {
"givenName": "John",
"familyName": "Doe",
"fullName": "John Doe"
},
"emailAddress": "john.doe@example.com"
}
}
]
}
```
#### Get Teacher
```bash
GET /v1/courses/{courseId}/teachers/{userId}
```
#### Add Teacher
```bash
POST /v1/courses/{courseId}/teachers
Content-Type: application/json
{
"userId": "teacher@example.com"
}
```
#### Remove Teacher
```bash
DELETE /v1/courses/{courseId}/teachers/{userId}
```
### Students
#### List Students
```bash
GET /v1/courses/{courseId}/students
```
#### Get Student
```bash
GET /v1/courses/{courseId}/students/{userId}
```
#### Add Student
```bash
POST /v1/courses/{courseId}/students
Content-Type: application/json
{
"userId": "student@example.com"
}
```
#### Remove Student
```bash
DELETE /v1/courses/{courseId}/students/{userId}
```
### Announcements
#### List Announcements
```bash
GET /v1/courses/{courseId}/announcements
GET /v1/courses/{courseId}/announcements?announcementStates=PUBLISHED
```
#### Get Announcement
```bash
GET /v1/courses/{courseId}/announcements/{announcementId}
```
#### Create Announcement
```bash
POST /v1/courses/{courseId}/announcements
Content-Type: application/json
{
"text": "Announcement text content",
"state": "PUBLISHED"
}
```
**States:**
- `DRAFT` - Not visible to students
- `PUBLISHED` - Visible to students
#### Update Announcement
```bash
PATCH /v1/courses/{courseId}/announcements/{announcementId}?updateMask=text
Content-Type: application/json
{
"text": "Updated announcement text"
}
```
#### Delete Announcement
```bash
DELETE /v1/courses/{courseId}/announcements/{announcementId}
```
### Topics
#### List Topics
```bash
GET /v1/courses/{courseId}/topics
```
#### Get Topic
```bash
GET /v1/courses/{courseId}/topics/{topicId}
```
#### Create Topic
```bash
POST /v1/courses/{courseId}/topics
Content-Type: application/json
{
"name": "Topic Name"
}
```
#### Update Topic
```bash
PATCH /v1/courses/{courseId}/topics/{topicId}?updateMask=name
Content-Type: application/json
{
"name": "Updated Topic Name"
}
```
#### Delete Topic
```bash
DELETE /v1/courses/{courseId}/topics/{topicId}
```
### Course Work Materials
#### List Course Work Materials
```bash
GET /v1/courses/{courseId}/courseWorkMaterials
```
#### Get Course Work Material
```bash
GET /v1/courses/{courseId}/courseWorkMaterials/{courseWorkMaterialId}
```
### Invitations
#### List Invitations
```bash
GET /v1/invitations?courseId={courseId}
GET /v1/invitations?userId=me
```
**Note:** Either `courseId` or `userId` is required.
#### Create Invitation
```bash
POST /v1/invitations
Content-Type: application/json
{
"courseId": "825635865485",
"userId": "user@example.com",
"role": "STUDENT"
}
```
**Roles:**
- `STUDENT`
- `TEACHER`
- `OWNER`
#### Accept Invitation
```bash
POST /v1/invitations/{invitationId}:accept
```
#### Delete Invitation
```bash
DELETE /v1/invitations/{invitationId}
```
### User Profiles
#### Get Current User
```bash
GET /v1/userProfiles/me
```
**Response:**
```json
{
"id": "102753038276005039640",
"name": {
"givenName": "John",
"familyName": "Doe",
"fullName": "John Doe"
},
"emailAddress": "john.doe@example.com",
"permissions": [
{
"permission": "CREATE_COURSE"
}
],
"verifiedTeacher": false
}
```
#### Get User Profile
```bash
GET /v1/userProfiles/{userId}
```
### Course Aliases
#### List Course Aliases
```bash
GET /v1/courses/{courseId}/aliases
```
## Pagination
The Google Classroom API uses token-based pagination. Responses include a `nextPageToken` when more results are available.
```bash
GET /v1/courses?pageSize=10
```
**Response:**
```json
{
"courses": [...],
"nextPageToken": "Ci8KLRIrEikKDmIMCLK8v8wGEIDQrsYBCgsI..."
}
```
To get the next page:
```bash
GET /v1/courses?pageSize=10&pageToken=Ci8KLRIrEikKDmIMCLK8v8wGEIDQrsYBCgsI...
```
## Code Examples
### JavaScript
```javascript
// List all courses
const response = await fetch(
'https://gateway.maton.ai/google-classroom/v1/courses',
{
headers: {
'Authorization': `Bearer ${process.env.MATON_API_KEY}`
}
}
);
const data = await response.json();
console.log(data.courses);
```
### Python
```python
import os
import requests
# List all courses
response = requests.get(
'https://gateway.maton.ai/google-classroom/v1/courses',
headers={'Authorization': f'Bearer {os.environ["MATON_API_KEY"]}'}
)
data = response.json()
print(data['courses'])
```
### Create Assignment Example
```python
import os
import requests
course_id = "825635865485"
# Create an assignment
assignment = {
"title": "Week 1 Homework",
"description": "Complete exercises 1-10",
"workType": "ASSIGNMENT",
"state": "PUBLISHED",
"maxPoints": 100,
"dueDate": {"year": 2026, "month": 3, "day": 15},
"dueTime": {"hours": 23, "minutes": 59}
}
response = requests.post(
f'https://gateway.maton.ai/google-classroom/v1/courses/{course_id}/courseWork',
headers={
'Authorization': f'Bearer {os.environ["MATON_API_KEY"]}',
'Content-Type': 'application/json'
},
json=assignment
)
print(response.json())
```
## Notes
- **updateMask Required**: PATCH requests require the `updateMask` query parameter specifying which fields to update
- **Course Deletion**: Courses must be archived (`courseState: "ARCHIVED"`) before they can be deleted
- **Student Submissions**: Course work must be in `PUBLISHED` state to access student submissions
- **User IDs**: Use `me` to refer to the current authenticated user
- **Timestamps**: Dates use `{year, month, day}` format; times use `{hours, minutes}` format
- **IMPORTANT**: When piping curl output to `jq` or other commands, environment variables like `$MATON_API_KEY` may not expand correctly in some shell environments
## Error Handling
| Status | Meaning |
|--------|---------|
| 400 | Bad request, invalid argument, or precondition failed |
| 401 | Invalid API key or expired token |
| 403 | Permission denied |
| 404 | Resource not found |
| 409 | Conflict (e.g., user already enrolled) |
| 429 | Rate limited |
| 4xx/5xx | Passthrough error from Google Classroom API |
### Common Errors
**Precondition check failed (400)**
- When deleting a course: Course must be archived first
- When listing submissions: Course work must be published
**Permission denied (403)**
- User doesn't have required role (teacher/owner) for the operation
- Attempting to access guardian information without proper scopes
## Resources
- [Google Classroom API Documentation](https://developers.google.com/workspace/classroom/reference/rest)
- [Course Resource Reference](https://developers.google.com/workspace/classroom/reference/rest/v1/courses)
- [CourseWork Resource Reference](https://developers.google.com/workspace/classroom/reference/rest/v1/courses.courseWork)
- [StudentSubmissions Reference](https://developers.google.com/workspace/classroom/reference/rest/v1/courses.courseWork.studentSubmissions)
- [Maton Community](https://discord.com/invite/dBfFAcefs2)
- [Maton Support](mailto:support@maton.ai)
标签
skill
ai