Google Classroom
name: google-classroom
by byungkyu · published 2026-03-22
$ claw add gh:byungkyu/byungkyu-google-classroom---
name: google-classroom
description: |
Google Classroom API integration with managed OAuth. Manage courses, assignments, students, teachers, and announcements.
Use this skill when users want to create courses, manage coursework, track student submissions, or post announcements.
For other third party apps, use the api-gateway skill (https://clawhub.ai/byungkyu/api-gateway).
Requires network access and valid Maton API key.
metadata:
author: maton
version: "1.0"
clawdbot:
emoji: 🧠
homepage: "https://maton.ai"
requires:
env:
- MATON_API_KEY
---
# Google Classroom
Access the Google Classroom API with managed OAuth authentication. Manage courses, coursework, students, teachers, announcements, and submissions.
Quick Start
# 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))
EOFBase 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`:
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
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))
EOFCreate Connection
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))
EOFGet Connection
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:**
{
"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
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))
EOFSpecifying Connection
If you have multiple Google Classroom connections, specify which one to use with the `Maton-Connection` header:
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))
EOFIf omitted, the gateway uses the default (oldest) active connection.
API Reference
Courses
#### List Courses
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:**
**Response:**
{
"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
GET /v1/courses/{courseId}#### Create Course
POST /v1/courses
Content-Type: application/json
{
"name": "Course Name",
"section": "Section A",
"descriptionHeading": "Course Title",
"description": "Course description",
"ownerId": "me"
}**Response:**
{
"id": "825637533405",
"name": "Course Name",
"section": "Section A",
"ownerId": "102753038276005039640",
"courseState": "PROVISIONED",
"enrollmentCode": "abc123"
}#### Update Course
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
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
GET /v1/courses/{courseId}/courseWork
GET /v1/courses/{courseId}/courseWork?courseWorkStates=PUBLISHED
GET /v1/courses/{courseId}/courseWork?orderBy=dueDate**Query Parameters:**
#### Get Course Work
GET /v1/courses/{courseId}/courseWork/{courseWorkId}#### Create Course Work
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:**
**States:**
#### Update Course Work
PATCH /v1/courses/{courseId}/courseWork/{courseWorkId}?updateMask=title,description
Content-Type: application/json
{
"title": "Updated Title",
"description": "Updated description"
}#### Delete Course Work
DELETE /v1/courses/{courseId}/courseWork/{courseWorkId}Student Submissions
#### List Student Submissions
GET /v1/courses/{courseId}/courseWork/{courseWorkId}/studentSubmissions
GET /v1/courses/{courseId}/courseWork/{courseWorkId}/studentSubmissions?states=TURNED_IN**Query Parameters:**
**Note:** Course work must be in `PUBLISHED` state to list submissions.
**Response:**
{
"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
GET /v1/courses/{courseId}/courseWork/{courseWorkId}/studentSubmissions/{submissionId}#### Grade Submission
PATCH /v1/courses/{courseId}/courseWork/{courseWorkId}/studentSubmissions/{submissionId}?updateMask=assignedGrade,draftGrade
Content-Type: application/json
{
"assignedGrade": 95,
"draftGrade": 95
}#### Return Submission
POST /v1/courses/{courseId}/courseWork/{courseWorkId}/studentSubmissions/{submissionId}:return
Content-Type: application/json
{}Teachers
#### List Teachers
GET /v1/courses/{courseId}/teachers**Response:**
{
"teachers": [
{
"courseId": "825635865485",
"userId": "102753038276005039640",
"profile": {
"id": "102753038276005039640",
"name": {
"givenName": "John",
"familyName": "Doe",
"fullName": "John Doe"
},
"emailAddress": "john.doe@example.com"
}
}
]
}#### Get Teacher
GET /v1/courses/{courseId}/teachers/{userId}#### Add Teacher
POST /v1/courses/{courseId}/teachers
Content-Type: application/json
{
"userId": "teacher@example.com"
}#### Remove Teacher
DELETE /v1/courses/{courseId}/teachers/{userId}Students
#### List Students
GET /v1/courses/{courseId}/students#### Get Student
GET /v1/courses/{courseId}/students/{userId}#### Add Student
POST /v1/courses/{courseId}/students
Content-Type: application/json
{
"userId": "student@example.com"
}#### Remove Student
DELETE /v1/courses/{courseId}/students/{userId}Announcements
#### List Announcements
GET /v1/courses/{courseId}/announcements
GET /v1/courses/{courseId}/announcements?announcementStates=PUBLISHED#### Get Announcement
GET /v1/courses/{courseId}/announcements/{announcementId}#### Create Announcement
POST /v1/courses/{courseId}/announcements
Content-Type: application/json
{
"text": "Announcement text content",
"state": "PUBLISHED"
}**States:**
#### Update Announcement
PATCH /v1/courses/{courseId}/announcements/{announcementId}?updateMask=text
Content-Type: application/json
{
"text": "Updated announcement text"
}#### Delete Announcement
DELETE /v1/courses/{courseId}/announcements/{announcementId}Topics
#### List Topics
GET /v1/courses/{courseId}/topics#### Get Topic
GET /v1/courses/{courseId}/topics/{topicId}#### Create Topic
POST /v1/courses/{courseId}/topics
Content-Type: application/json
{
"name": "Topic Name"
}#### Update Topic
PATCH /v1/courses/{courseId}/topics/{topicId}?updateMask=name
Content-Type: application/json
{
"name": "Updated Topic Name"
}#### Delete Topic
DELETE /v1/courses/{courseId}/topics/{topicId}Course Work Materials
#### List Course Work Materials
GET /v1/courses/{courseId}/courseWorkMaterials#### Get Course Work Material
GET /v1/courses/{courseId}/courseWorkMaterials/{courseWorkMaterialId}Invitations
#### List Invitations
GET /v1/invitations?courseId={courseId}
GET /v1/invitations?userId=me**Note:** Either `courseId` or `userId` is required.
#### Create Invitation
POST /v1/invitations
Content-Type: application/json
{
"courseId": "825635865485",
"userId": "user@example.com",
"role": "STUDENT"
}**Roles:**
#### Accept Invitation
POST /v1/invitations/{invitationId}:accept#### Delete Invitation
DELETE /v1/invitations/{invitationId}User Profiles
#### Get Current User
GET /v1/userProfiles/me**Response:**
{
"id": "102753038276005039640",
"name": {
"givenName": "John",
"familyName": "Doe",
"fullName": "John Doe"
},
"emailAddress": "john.doe@example.com",
"permissions": [
{
"permission": "CREATE_COURSE"
}
],
"verifiedTeacher": false
}#### Get User Profile
GET /v1/userProfiles/{userId}Course Aliases
#### List Course Aliases
GET /v1/courses/{courseId}/aliasesPagination
The Google Classroom API uses token-based pagination. Responses include a `nextPageToken` when more results are available.
GET /v1/courses?pageSize=10**Response:**
{
"courses": [...],
"nextPageToken": "Ci8KLRIrEikKDmIMCLK8v8wGEIDQrsYBCgsI..."
}To get the next page:
GET /v1/courses?pageSize=10&pageToken=Ci8KLRIrEikKDmIMCLK8v8wGEIDQrsYBCgsI...Code Examples
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
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
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
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)**
**Permission denied (403)**
Resources
More tools from the same signal band
Order food/drinks (点餐) on an Android device paired as an OpenClaw node. Uses in-app menu and cart; add goods, view cart, submit order (demo, no real payment).
Sign plugins, rotate agent credentials without losing identity, and publicly attest to plugin behavior with verifiable claims and authenticated transfers.
The philosophical layer for AI agents. Maps behavior to Spinoza's 48 affects, calculates persistence scores, and generates geometric self-reports. Give your...