HomeBrowseUpload
← Back to registry
// Skill profile

Google Classroom

name: google-classroom

by byungkyu · published 2026-03-22

邮件处理开发工具加密货币
Total installs
0
Stars
★ 0
Last updated
2026-03
// Install command
$ claw add gh:byungkyu/byungkyu-google-classroom
View on GitHub
// Full documentation

---

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))
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`:

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))
EOF

Create 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))
EOF

Get 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))
EOF

Specifying 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))
EOF

If 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:**

  • `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:**

    {
      "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:**

  • `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

    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:**

  • `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

    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:**

  • `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:**

    {
      "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:**

  • `DRAFT` - Not visible to students
  • `PUBLISHED` - Visible to students
  • #### 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:**

  • `STUDENT`
  • `TEACHER`
  • `OWNER`
  • #### 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}/aliases

    Pagination

    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

  • **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)
  • // Comments
    Sign in with GitHub to leave a comment.
    // Related skills

    More tools from the same signal band