Every API here is available over the APIs.io API and to AI agents over MCP.
MCP server
One button, every client — Claude, Cursor, VS Code and the rest.
https://apis.io/mcp
Tools for apis
7 MCP tools reach this
find_apisBrowse and filter every API in the catalog.
get_api_artifactsOne API's artifacts, grouped by type.
get_openapiThe primary OpenAPI for this API.
find_similar_apisAPIs that look like this one.
apis_io_searchSTART HERE — APIs, providers and tags for one query, each with its total.
resolveTurn a domain, URL or GitHub org into the provider it belongs to.
find_cohortsEvery scored population of providers in the catalog.
All 92 tools →
Call it yourself
curl for this page
This API
curl "https://apis.io/api/v1/apis/classquill-com:classquill-com-curriculum-api"
All apis
curl "https://apis.io/api/v1/apis?limit=25"
Calls without X-API-Key need no key. Calls with it need a paid plan — get a key.
Get an API key
Free tier, no form to fill in. Signing in shares your email address with us — we
store it to create your key and to recognise you if you sign in with another
provider. See our Privacy Policy and
Terms.
A second provider on the same verified email joins the account you already have.
openapi: 3.2.0
info:
title: ClassQuill Public Curriculum API
description: 'REST API for ClassQuill tutoring organisations. Pipe your sessions, invoices, payments, tutor earnings, students, and more into your own tools. Most endpoints are reads; a focused set of writes (each gated by a *:write scope) create or update data, including creating student/tutor/parent accounts.
Authenticate every request with an org API key:
Authorization: Token token=cq_live_...
Mint keys in the ClassQuill app under Settings → Developers.'
version: 1.0.0
security:
- ApiKeyAuth: []
tags:
- name: Curriculum
paths:
/v1/subjects:
get:
tags:
- Curriculum
summary: List Subjects
description: 'The subjects the org teaches, derived from the subject IDs on its sessions.
`name` is the subject_registry label (the platform subject dictionary,
subject-system overhaul P1); unregistered/legacy ids fall back to the raw id.'
operationId: list_subjects_v1_subjects_get
responses:
'200':
description: Successful Response
content:
application/json:
schema:
$ref: '#/components/schemas/SubjectList'
'422':
description: Validation error — `error.details.errors` lists the fields.
content:
application/json:
schema:
$ref: '#/components/schemas/ApiError'
'401':
description: Missing, malformed, revoked, or expired credentials.
content:
application/json:
schema:
$ref: '#/components/schemas/ApiError'
'403':
description: The credential lacks the scope this endpoint requires.
content:
application/json:
schema:
$ref: '#/components/schemas/ApiError'
'429':
description: Rate limit exceeded — honour Retry-After and the RateLimit-* headers.
content:
application/json:
schema:
$ref: '#/components/schemas/ApiError'
/v1/student-groups:
get:
tags:
- Curriculum
summary: List Student Groups
description: 'List the org''s student groups, each with its accepted student-member IDs.
Scoped to groups whose `organization_id` is this org, plus null-org groups owned
by a single-org member — so a multi-org tutor''s other-org groups don''t surface.
Ordered by the tutor''s configured sort order.'
operationId: list_student_groups_v1_student_groups_get
parameters:
- name: subject_id
in: query
required: false
schema:
anyOf:
- type: string
- type: 'null'
description: Filter by subject id, e.g. methods_34
title: Subject Id
description: Filter by subject id, e.g. methods_34
- name: classroom_id
in: query
required: false
schema:
anyOf:
- type: string
- type: 'null'
description: Filter by parent classroom UUID
title: Classroom Id
description: Filter by parent classroom UUID
- name: cursor
in: query
required: false
schema:
anyOf:
- type: string
- type: 'null'
description: Opaque cursor from a previous response's meta.next_cursor, or the literal 'start' to begin cursor paging from the newest record. When set, offset is ignored and results page by a stable (created_at, id) keyset — recommended for large or incremental syncs.
title: Cursor
description: Opaque cursor from a previous response's meta.next_cursor, or the literal 'start' to begin cursor paging from the newest record. When set, offset is ignored and results page by a stable (created_at, id) keyset — recommended for large or incremental syncs.
- name: limit
in: query
required: false
schema:
type: integer
maximum: 100
minimum: 1
description: Records per page (default 20, max 100)
default: 20
title: Limit
description: Records per page (default 20, max 100)
- name: offset
in: query
required: false
schema:
type: integer
minimum: 0
description: Pagination offset (ignored when cursor is set)
default: 0
title: Offset
description: Pagination offset (ignored when cursor is set)
responses:
'200':
description: Successful Response
content:
application/json:
schema:
$ref: '#/components/schemas/Page_StudentGroup_'
'422':
description: Validation error — `error.details.errors` lists the fields.
content:
application/json:
schema:
$ref: '#/components/schemas/ApiError'
'401':
description: Missing, malformed, revoked, or expired credentials.
content:
application/json:
schema:
$ref: '#/components/schemas/ApiError'
'403':
description: The credential lacks the scope this endpoint requires.
content:
application/json:
schema:
$ref: '#/components/schemas/ApiError'
'429':
description: Rate limit exceeded — honour Retry-After and the RateLimit-* headers.
content:
application/json:
schema:
$ref: '#/components/schemas/ApiError'
/v1/student-groups/{group_id}:
get:
tags:
- Curriculum
summary: Get Student Group
description: 'Fetch a single student group (with members) by ID. 404 unless it belongs to
this org (org-owned, or a single-org member''s null-org group).'
operationId: get_student_group_v1_student_groups__group_id__get
parameters:
- name: group_id
in: path
required: true
schema:
type: string
description: Student group UUID
title: Group Id
description: Student group UUID
responses:
'200':
description: Successful Response
content:
application/json:
schema:
$ref: '#/components/schemas/StudentGroup'
'422':
description: Validation error — `error.details.errors` lists the fields.
content:
application/json:
schema:
$ref: '#/components/schemas/ApiError'
'401':
description: Missing, malformed, revoked, or expired credentials.
content:
application/json:
schema:
$ref: '#/components/schemas/ApiError'
'403':
description: The credential lacks the scope this endpoint requires.
content:
application/json:
schema:
$ref: '#/components/schemas/ApiError'
'429':
description: Rate limit exceeded — honour Retry-After and the RateLimit-* headers.
content:
application/json:
schema:
$ref: '#/components/schemas/ApiError'
'404':
description: Not found — the record doesn't exist or belongs to another organisation.
content:
application/json:
schema:
$ref: '#/components/schemas/ApiError'
/v1/classrooms:
get:
tags:
- Curriculum
summary: List Classrooms
description: 'List the org''s classrooms (most recent first).
Scoped to classrooms whose `organization_id` is this org, plus null-org legacy
classrooms owned by a single-org member — so a multi-org tutor''s other-org
classrooms don''t surface. Consistent with student-groups.'
operationId: list_classrooms_v1_classrooms_get
parameters:
- name: subject_id
in: query
required: false
schema:
anyOf:
- type: string
- type: 'null'
description: Filter by subject id, e.g. methods_34
title: Subject Id
description: Filter by subject id, e.g. methods_34
- name: cursor
in: query
required: false
schema:
anyOf:
- type: string
- type: 'null'
description: Opaque cursor from a previous response's meta.next_cursor, or the literal 'start' to begin cursor paging from the newest record. When set, offset is ignored and results page by a stable (created_at, id) keyset — recommended for large or incremental syncs.
title: Cursor
description: Opaque cursor from a previous response's meta.next_cursor, or the literal 'start' to begin cursor paging from the newest record. When set, offset is ignored and results page by a stable (created_at, id) keyset — recommended for large or incremental syncs.
- name: limit
in: query
required: false
schema:
type: integer
maximum: 100
minimum: 1
description: Records per page (default 20, max 100)
default: 20
title: Limit
description: Records per page (default 20, max 100)
- name: offset
in: query
required: false
schema:
type: integer
minimum: 0
description: Pagination offset (ignored when cursor is set)
default: 0
title: Offset
description: Pagination offset (ignored when cursor is set)
responses:
'200':
description: Successful Response
content:
application/json:
schema:
$ref: '#/components/schemas/Page_Classroom_'
'422':
description: Validation error — `error.details.errors` lists the fields.
content:
application/json:
schema:
$ref: '#/components/schemas/ApiError'
'401':
description: Missing, malformed, revoked, or expired credentials.
content:
application/json:
schema:
$ref: '#/components/schemas/ApiError'
'403':
description: The credential lacks the scope this endpoint requires.
content:
application/json:
schema:
$ref: '#/components/schemas/ApiError'
'429':
description: Rate limit exceeded — honour Retry-After and the RateLimit-* headers.
content:
application/json:
schema:
$ref: '#/components/schemas/ApiError'
post:
tags:
- Curriculum
summary: Create Classroom
description: 'Create a classroom scoped to this org. The org owner is set as the tutor (owner-as-merchant model).
Returns 422 with a `reason` field on validation failure. Honours `Idempotency-Key`.'
operationId: create_classroom_v1_classrooms_post
parameters:
- name: Idempotency-Key
in: header
required: false
schema:
anyOf:
- type: string
- type: 'null'
title: Idempotency-Key
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/ClassroomCreate'
responses:
'201':
description: Successful Response
content:
application/json:
schema:
$ref: '#/components/schemas/Classroom'
'422':
description: Validation error — `error.details.errors` lists the fields.
content:
application/json:
schema:
$ref: '#/components/schemas/ApiError'
'401':
description: Missing, malformed, revoked, or expired credentials.
content:
application/json:
schema:
$ref: '#/components/schemas/ApiError'
'403':
description: The credential lacks the scope this endpoint requires.
content:
application/json:
schema:
$ref: '#/components/schemas/ApiError'
'429':
description: Rate limit exceeded — honour Retry-After and the RateLimit-* headers.
content:
application/json:
schema:
$ref: '#/components/schemas/ApiError'
/v1/classrooms/{classroom_id}:
get:
tags:
- Curriculum
summary: Get Classroom
description: 'Fetch a single classroom by ID. 404 unless it belongs to this org (org-owned,
or a single-org member''s null-org classroom).'
operationId: get_classroom_v1_classrooms__classroom_id__get
parameters:
- name: classroom_id
in: path
required: true
schema:
type: string
description: Classroom UUID
title: Classroom Id
description: Classroom UUID
responses:
'200':
description: Successful Response
content:
application/json:
schema:
$ref: '#/components/schemas/Classroom'
'422':
description: Validation error — `error.details.errors` lists the fields.
content:
application/json:
schema:
$ref: '#/components/schemas/ApiError'
'401':
description: Missing, malformed, revoked, or expired credentials.
content:
application/json:
schema:
$ref: '#/components/schemas/ApiError'
'403':
description: The credential lacks the scope this endpoint requires.
content:
application/json:
schema:
$ref: '#/components/schemas/ApiError'
'429':
description: Rate limit exceeded — honour Retry-After and the RateLimit-* headers.
content:
application/json:
schema:
$ref: '#/components/schemas/ApiError'
'404':
description: Not found — the record doesn't exist or belongs to another organisation.
content:
application/json:
schema:
$ref: '#/components/schemas/ApiError'
/v1/classrooms/{classroom_id}/students:
post:
tags:
- Curriculum
summary: Add Student To Classroom
description: Enrol an existing org member as a student in a classroom. Idempotent.
operationId: add_student_to_classroom_v1_classrooms__classroom_id__students_post
parameters:
- name: classroom_id
in: path
required: true
schema:
type: string
title: Classroom Id
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/MemberAdd'
responses:
'200':
description: Successful Response
content:
application/json:
schema:
$ref: '#/components/schemas/MemberAddResult'
'422':
description: Validation error — `error.details.errors` lists the fields.
content:
application/json:
schema:
$ref: '#/components/schemas/ApiError'
'401':
description: Missing, malformed, revoked, or expired credentials.
content:
application/json:
schema:
$ref: '#/components/schemas/ApiError'
'403':
description: The credential lacks the scope this endpoint requires.
content:
application/json:
schema:
$ref: '#/components/schemas/ApiError'
'429':
description: Rate limit exceeded — honour Retry-After and the RateLimit-* headers.
content:
application/json:
schema:
$ref: '#/components/schemas/ApiError'
'404':
description: Not found — the record doesn't exist or belongs to another organisation.
content:
application/json:
schema:
$ref: '#/components/schemas/ApiError'
/v1/classrooms/{classroom_id}/tutors:
post:
tags:
- Curriculum
summary: Add Tutor To Classroom
description: Add an accepted org tutor/admin as a teacher on a classroom. Idempotent.
operationId: add_tutor_to_classroom_v1_classrooms__classroom_id__tutors_post
parameters:
- name: classroom_id
in: path
required: true
schema:
type: string
title: Classroom Id
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/MemberAdd'
responses:
'200':
description: Successful Response
content:
application/json:
schema:
$ref: '#/components/schemas/MemberAddResult'
'422':
description: Validation error — `error.details.errors` lists the fields.
content:
application/json:
schema:
$ref: '#/components/schemas/ApiError'
'401':
description: Missing, malformed, revoked, or expired credentials.
content:
application/json:
schema:
$ref: '#/components/schemas/ApiError'
'403':
description: The credential lacks the scope this endpoint requires.
content:
application/json:
schema:
$ref: '#/components/schemas/ApiError'
'429':
description: Rate limit exceeded — honour Retry-After and the RateLimit-* headers.
content:
application/json:
schema:
$ref: '#/components/schemas/ApiError'
'404':
description: Not found — the record doesn't exist or belongs to another organisation.
content:
application/json:
schema:
$ref: '#/components/schemas/ApiError'
components:
schemas:
Page_StudentGroup_:
properties:
data:
items:
$ref: '#/components/schemas/StudentGroup'
type: array
title: Data
meta:
$ref: '#/components/schemas/PageMeta'
type: object
required:
- data
- meta
title: Page[StudentGroup]
Classroom:
properties:
id:
type: string
title: Id
name:
anyOf:
- type: string
- type: 'null'
title: Name
tutor_id:
anyOf:
- type: string
- type: 'null'
title: Tutor Id
subject_id:
anyOf:
- type: string
- type: 'null'
title: Subject Id
join_code:
anyOf:
- type: string
- type: 'null'
title: Join Code
period_price_cents:
anyOf:
- type: integer
- type: 'null'
title: Period Price Cents
join_fee_cents:
anyOf:
- type: integer
- type: 'null'
title: Join Fee Cents
billing_interval:
anyOf:
- type: string
- type: 'null'
title: Billing Interval
billing_anchor_date:
anyOf:
- type: string
- type: 'null'
title: Billing Anchor Date
group_id:
anyOf:
- type: string
- type: 'null'
title: Group Id
created_at:
anyOf:
- type: string
- type: 'null'
title: Created At
updated_at:
anyOf:
- type: string
- type: 'null'
title: Updated At
type: object
required:
- id
title: Classroom
ApiErrorBody:
description: The `error` object every /v1 error response carries.
properties:
code:
description: 'Stable machine-readable error code: bad_request, unauthorized, forbidden, not_found, conflict, validation_error, rate_limited, or internal_error.'
examples:
- not_found
title: Code
type: string
message:
description: Human-readable explanation, safe to surface to end users.
examples:
- Session not found
title: Message
type: string
status:
description: The HTTP status code, repeated in the body.
examples:
- 404
title: Status
type: integer
details:
additionalProperties: true
description: Error-specific context. 422 carries the field errors under `errors`; 429 carries `retry_after_seconds`.
title: Details
type: object
required:
- code
- message
- status
title: ApiErrorBody
type: object
MemberAddResult:
properties:
member_id:
anyOf:
- type: string
- type: 'null'
title: Member Id
status:
anyOf:
- type: string
- type: 'null'
title: Status
type: object
title: MemberAddResult
ApiError:
description: Canonical error envelope for every /v1 error response (4xx/5xx).
properties:
error:
$ref: '#/components/schemas/ApiErrorBody'
required:
- error
title: ApiError
type: object
SubjectList:
properties:
data:
items:
$ref: '#/components/schemas/Subject'
type: array
title: Data
type: object
required:
- data
title: SubjectList
description: '`/v1/subjects` returns just `{ "data": [...] }` (no pagination).'
Subject:
properties:
id:
type: string
title: Id
name:
anyOf:
- type: string
- type: 'null'
title: Name
type: object
required:
- id
title: Subject
StudentGroup:
properties:
id:
type: string
title: Id
name:
anyOf:
- type: string
- type: 'null'
title: Name
tutor_id:
anyOf:
- type: string
- type: 'null'
title: Tutor Id
classroom_id:
anyOf:
- type: string
- type: 'null'
title: Classroom Id
subject_id:
anyOf:
- type: string
- type: 'null'
title: Subject Id
rate_per_student_cents:
anyOf:
- type: integer
- type: 'null'
title: Rate Per Student Cents
color:
anyOf:
- type: string
- type: 'null'
title: Color
avatar_url:
anyOf:
- type: string
- type: 'null'
title: Avatar Url
student_ids:
items:
type: string
type: array
title: Student Ids
default: []
created_at:
anyOf:
- type: string
- type: 'null'
title: Created At
updated_at:
anyOf:
- type: string
- type: 'null'
title: Updated At
type: object
required:
- id
title: StudentGroup
ClassroomCreate:
properties:
name:
type: string
title: Name
subject_id:
type: string
title: Subject Id
period_price_cents:
anyOf:
- type: integer
- type: 'null'
title: Period Price Cents
join_fee_cents:
anyOf:
- type: integer
- type: 'null'
title: Join Fee Cents
billing_interval:
anyOf:
- type: string
enum:
- weekly
- fortnightly
- monthly
- type: 'null'
title: Billing Interval
billing_anchor_date:
anyOf:
- type: string
- type: 'null'
title: Billing Anchor Date
additionalProperties: false
type: object
required:
- name
- subject_id
title: ClassroomCreate
Page_Classroom_:
properties:
data:
items:
$ref: '#/components/schemas/Classroom'
type: array
title: Data
meta:
$ref: '#/components/schemas/PageMeta'
type: object
required:
- data
- meta
title: Page[Classroom]
PageMeta:
properties:
limit:
type: integer
title: Limit
offset:
anyOf:
- type: integer
- type: 'null'
title: Offset
count:
anyOf:
- type: integer
- type: 'null'
title: Count
total:
anyOf:
- type: integer
- type: 'null'
title: Total
next_cursor:
anyOf:
- type: string
- type: 'null'
title: Next Cursor
description: 'Cursor-mode only: pass as ?cursor= to fetch the next page; null when this is the last page.'
type: object
required:
- limit
title: PageMeta
description: 'Pagination envelope metadata. `count` is the size of the returned page;
`total` (when present) is the full result-set size for offset paging.
In cursor mode `offset`/`total` are absent and `next_cursor` carries the
opaque token for the next page (null on the last page).'
MemberAdd:
properties:
user_id:
type: string
title: User Id
type: object
required:
- user_id
title: MemberAdd
securitySchemes:
ApiKeyAuth:
type: apiKey
in: header
name: Authorization
description: Org API key as `Token token=cq_live_...`