Courses Query
Note: The Teachify Admin API is currently under development and not yet available for public use. This documentation is provided for preview purposes only.
Overview
Section titled “Overview”The Courses API allows you to retrieve information about courses in your school. You can list all courses, get details for a specific course, and access related data.
Available Queries
Section titled “Available Queries”courses
Section titled “courses”Returns a paginated list of courses for the school.
Parameters:
| Parameter | Type | Description |
|---|---|---|
filter | CourseFilter | Filter criteria (see Filtering) |
page | Int | Page number for pagination |
perPage | Int | Number of items per page (default: 20, max: 50) |
limit | Int | Alternative to perPage |
Returns:
- CoursePage object with:
nodes: Array of Course objectscurrentPage: Current page numberhasNextPage: Whether there are more pageshasPreviousPage: Whether there are previous pagesnodesCount: Total number of items across all pagestotalPages: Total number of pages
Example:
query { courses( page: 1 perPage: 10 ) { nodes { id name description slug featured } currentPage hasNextPage totalPages }}Course Object
Section titled “Course Object”The Course object contains the following fields based on the schema:
| Field | Type | Description |
|---|---|---|
id | String! | Unique identifier |
name | String! | Course name |
slug | String! | URL-friendly identifier |
description | String | Course description |
image | String | Course image URL |
featured | Boolean! | Whether the course is featured |
invisible | Boolean! | Whether the course is hidden |
publishedAt | Int | Unix timestamp when the course was published |
courseType | String! | Possible values: paid, public_access, free_redeem or pre_order |
contentType | String! | Content type of the course |
template | String! | Possible values: default, video_on_top |
playerTheme | String! | Possible values: classic, theater |
sections | [Section!]! | List of course sections |
categories | [Category!] | List of course categories |
tags | [String!] | List of course tags |
lecturer | Lecturer | Primary lecturer |
lecturers | [Lecturer!] | All lecturers for the course |
assignments | [Assignment!] | List of course assignments |
totalHours | Float | Total duration of the course in hours |
lecturesCount | Int | Number of lectures in the course |
courseFeatures | CourseFeatures | Additional course features |
preOrderInfo | CoursePreOrderInfo | Pre-order information if applicable |
rating | Rating | Course rating information |
faqSections | [FaqSection!] | FAQ sections for the course |
plans | [CurriculumPlan!] | Available pricing plans for the course |
metadata | JSON | Custom external metadata as a JSON object of string key-value pairs. Returns null unless the school has the external_metadata feature enabled. See External Metadata. |
users | UserPage | Paginated list of users for this course |
Users Field
Section titled “Users Field”The UserPage object includes user information through the user field. This returns a paginated list of users associated with the course.
- UserPage object with:
nodes: Array of Course objectscurrentPage: Current page numberhasNextPage: Whether there are more pageshasPreviousPage: Whether there are previous pagesnodesCount: Total number of items across all pagestotalPages: Total number of pages
User Information in Users
Section titled “User Information in Users”Each subscription includes user information through the user field:
| Field | Type | Description |
|---|---|---|
id | String! | User’s unique identifier |
name | String | User’s full name |
email | String | User’s email address |
Users Filter Parameters
Section titled “Users Filter Parameters”| Parameter | Type | Description |
|---|---|---|
id | StringOperator | Filter by user ID |
email | StringOperator | Filter by user’s email |
name | StringOperator | Filter by user’s name |
Example with filtered users:
query { courses( page: 1 perPage: 10 ) { nodes { id name description slug featured
users( filter: { email: { eq: "student@example.com" } } ) { nodes { id name } } } currentPage hasNextPage totalPages }}Detailed Query Structure
Section titled “Detailed Query Structure”Below is a comprehensive view of fields available in the courses query based on the schema:
query { courses( filter: { id: { eq: "course-123" } tags: ["beginner"] featured: true state: { eq: "published" } } page: 1 perPage: 20 ) { nodes { id # Unique identifier (String!) name # Course name (String!) slug # URL-friendly identifier (String!) description # Course description (String) image # Course image URL (String)
# Course settings featured # Whether the course is featured (Boolean!) invisible # Whether the course is hidden (Boolean!) publishedAt # When the course was published (Int) courseType # Type of course (String!) contentType # Content type (String!) template # Template style (String!) playerTheme # Player theme (String!)
# Course content sections { # Course sections ([Section!]!) id title position duration lectures { # Lectures within sections id title position duration isFreePreview isLocked } }
# Categorization categories { # Course categories ([Category!]) id name slug } tags # Course tags ([String!])
# Instructors lecturer { # Primary lecturer (Lecturer) id name avatar slug } lecturers { # All lecturers ([Lecturer!]) id name avatar slug }
# Assignments assignments { # Course assignments ([Assignment!]) id name description dueAt }
# Course metrics totalHours # Total duration in hours (Float) lecturesCount # Number of lectures (Int)
# Additional information courseFeatures { # Course features (CourseFeatures) studentsCount lecturesCount videoTotalHours audioTotalHours downloadableResourcesCount certificateOfCompletion lifetimeAccess moneyBackGuarantee }
# Pre-order information preOrderInfo { # Pre-order details (CoursePreOrderInfo) startedAt endedAt releasedAt buyersGoal buyersPledged moneyGoal moneyPledged goalType achievedPercentage }
# Ratings rating { # Course rating (Rating) average total }
# FAQ sections faqSections { # FAQ sections ([FaqSection!]) id name position faqContents { id title body position isPublished } }
# Pricing plans plans { # Pricing plans ([CurriculumPlan!]) id name description amount compareAtPrice currency currencySymbol planType position quantity interval intervalCount groupSize displayRemainingCount displaySoldCount remainingItemsCount soldItemsCount repeatPurchasable endedAt releaseAt coverPhoto createdAt metadata # Plan-level external metadata (JSON, nullable) }
# External metadata metadata # Course-level external metadata (JSON, nullable)
# Users # Users (UserPage) users ( filter: { email: { eq: "student@example.com" } } ) { nodes { id name email } } }
# Pagination information currentPage # Current page number (Int!) hasNextPage # Whether there are more pages (Boolean!) hasPreviousPage # Whether there are previous pages (Boolean!) nodesCount # Total number of items across all pages (Int!) totalPages # Total number of pages (Int!) }}Plans Field
Section titled “Plans Field”The plans field returns an array of CurriculumPlan objects representing the available pricing plans for the course. Each plan defines how students can access the course (free, one-time purchase, subscription, etc.).
CurriculumPlan Fields
Section titled “CurriculumPlan Fields”| Field | Type | Description |
|---|---|---|
id | String! | Unique identifier for the plan |
name | String | Display name of the pricing plan |
description | String | Detailed description of what’s included |
amount | Float | Price amount for the plan |
compareAtPrice | Int | Original price before discount/sale |
currency | String! | ISO currency code (e.g., TWD, USD) |
currencySymbol | String! | Currency symbol (e.g., $, €, £) |
planType | String! | Plan type: free, one_time_purchase, subscription, pre_order, group_buy, fixed_date, specific_length, web3_discount |
position | Int | Display order position |
quantity | Int | Available quantity for purchase |
interval | String | Billing interval for subscription plans |
intervalCount | Int | Number of intervals between billing |
groupSize | Int | Required group size for group_buy plans |
displayRemainingCount | Boolean | Whether to show remaining quantity |
displaySoldCount | Boolean | Whether to show sold count |
remainingItemsCount | Int | Number of items remaining |
soldItemsCount | Int | Number of items sold |
repeatPurchasable | Boolean! | Whether plan can be purchased multiple times |
endedAt | Int | Unix timestamp when plan expires |
releaseAt | Int | Unix timestamp when plan becomes available |
coverPhoto | String | Plan cover image URL |
createdAt | Int! | Unix timestamp when plan was created |
metadata | JSON | Custom external metadata as a JSON object of string key-value pairs. Returns null unless the school has the external_metadata feature enabled. See External Metadata. |
Example with plans:
query { courses { nodes { id name plans { id name description amount currencySymbol planType remainingItemsCount soldItemsCount } } }}External Metadata
Section titled “External Metadata”The metadata field on both Course and CurriculumPlan returns a JSON object of string key-value pairs that you have configured under your school’s Settings → 進階 → 產品自訂欄位. This is the same data delivered with the payment.paid webhook’s lineitems[].metadata payload.
Behavior:
- Returns
nullif the school does not have theexternal_metadatafeature enabled. - Returns
nullif no metadata has been set (an empty object is also serialized asnull). - Otherwise returns the stored hash, e.g.
{ "erp_product_id": "BK-9789861788888" }.
Allowed keys: Keys and values are limited to those allowed by the schema you configure per resource type (course, curriculum_plan, membership_plan) when a metadata schema is present. Keys must be ≤ 40 characters, values ≤ 255 characters, and each resource may have at most 50 pairs. Writes that violate these limits are rejected; writes using unknown keys are rejected when a metadata schema is configured for that resource type.
Example:
query { courses(filter: { id: { eq: "course-123" } }) { nodes { id name metadata # e.g. { "erp_product_id": "BK-9789861788888" } plans { id name metadata # e.g. { "sales_channels_ic": "IC-1000" } } } }}Filtering
Section titled “Filtering”The courses query accepts a filter parameter of type CourseFilter. This allows you to narrow down results based on various criteria.
Available Filters
Section titled “Available Filters”| Filter Field | Type | Description |
|---|---|---|
id | StringOperator | Filter by course ID |
tags | [String!] | Filter by course tags |
categoryIds | [String!] | Filter by category IDs |
categorySlugs | [String!] | Filter by category slugs |
featured | Boolean | Filter for featured courses |
state | StringOperator | Filter by course state (unpublished, published) |
preOrderState | String | Filter by pre-order state (upcoming, started, to_be_released, released) |
hasAssignments | Boolean | Filter for courses with published assignments |
StringOperator
Section titled “StringOperator”The StringOperator used in filters has these operations:
| Operation | Description |
|---|---|
eq | Equal to |
neq | Not equal to |
in | In a list of values |
nin | Not in a list of values |
like | Match text values against a pattern using wildcards (case-sensitive) |
Filter Examples
Section titled “Filter Examples”Find courses with specific tags:
query { courses( filter: { tags: ["beginner", "programming"] } ) { nodes { id name tags } }}Find featured courses in specific categories:
query { courses( filter: { featured: true, categorySlugs: ["programming", "web-development"] } ) { nodes { id name featured categories { name slug } } }}Find courses by ID:
query { courses( filter: { id: { eq: "course-123" } } ) { nodes { id name } }}Find courses by state:
query { courses( filter: { state: { eq: "published" } } ) { nodes { id name publishedAt } }}Find courses with multiple states:
query { courses( filter: { state: { in: ["published", "unpublished"] } } ) { nodes { id name publishedAt } }}