Product Revenues 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”This page documents two revenue analytics queries: productRevenues, which returns revenue metrics broken down by product and ranked by revenue, and revenueSummary, which returns a single school-wide aggregate for a period. Where revenueSummary gives one roll-up number set for the whole school, productRevenues attributes revenue to each individual course, membership plan, digital product, event, or order bump.
Revenue is computed from paid line items (payment states paid, refunding, refunded) and windowed by payment.paidAt. Line items roll up to their canonical product:
- CurriculumPlan line items roll up to their parent Course.
- Ticket line items roll up to their parent Event.
- OrderBump is treated as its own product category.
Available Queries
Section titled “Available Queries”productRevenues
Section titled “productRevenues”Returns a ranked list of products with their revenue metrics for the given period. Unlike most list queries, productRevenues is not paginated — it returns a plain array capped by limit.
Parameters:
| Parameter | Type | Description |
|---|---|---|
since | Int | Start of the period as a Unix timestamp. Defaults to 30 days ago. |
until | Int | End of the period as a Unix timestamp. Defaults to now. |
productType | AdminProductType | Restrict results to a single product category (see Product Types). |
productIds | [ID!] | Restrict results to specific canonical product ids. Requires productType — omitting it returns an error. |
paymentFilter | AdminPaymentFilter | Payment-level filters applied to the underlying payments (see Payment Filtering). |
orderBy | AdminProductRevenueOrderBy | Sort key. Defaults to TOTAL_REVENUE_DESC. |
limit | Int | Maximum number of products to return. Default 50, clamped to a maximum of 200. |
Returns:
An array of AdminProductRevenue objects, ordered by orderBy.
Example:
query { productRevenues( since: 1704067200, until: 1735689600, productType: COURSE, limit: 10 ) { productId productType productName totalRevenue refundedAmount ordersCount currency periodStart periodEnd }}revenueSummary
Section titled “revenueSummary”Returns a single school-wide revenue aggregate for the given period. Unlike productRevenues, it is not a list — it returns one AdminRevenueSummary object.
Parameters:
| Parameter | Type | Description |
|---|---|---|
since | Int | Start of the period as a Unix timestamp. Defaults to 30 days ago. |
until | Int | End of the period as a Unix timestamp. Defaults to now. |
Returns:
A single AdminRevenueSummary object (see AdminRevenueSummary Object).
totalRevenue is gross revenue, computed from payments in state paid, refunding, or refunded whose paidAt falls in the period. refundedAmount/refundedCount cover payments refunded within the period (windowed by refundedAt).
Requires an API key carrying the analytics:read scope.
Example:
query { revenueSummary( since: 1704067200, until: 1735689600 ) { totalRevenue totalOrders averageOrderValue refundedAmount refundedCount currency periodStart periodEnd }}AdminRevenueSummary Object
Section titled “AdminRevenueSummary Object”The AdminRevenueSummary object contains the following fields:
| Field | Type | Description |
|---|---|---|
totalRevenue | Float! | Sum of paid order amounts in the period (gross of refunds; includes paid, refunding, and refunded payments) |
totalOrders | Int! | Number of paid orders in the period |
averageOrderValue | Float! | Average paid order amount (totalRevenue / totalOrders, rounded to 2 decimals; 0.0 when there are no orders) |
refundedAmount | Float! | Sum of refunded amounts in the period |
refundedCount | Int! | Number of refunded orders in the period |
currency | String! | ISO 4217 currency code (defaults to TWD) |
periodStart | String! | Start of the requested period (ISO 8601) |
periodEnd | String! | End of the requested period (ISO 8601) |
AdminProductRevenue Object
Section titled “AdminProductRevenue Object”The AdminProductRevenue object contains the following fields:
| Field | Type | Description |
|---|---|---|
productId | ID! | Canonical product identifier (Course / Event / MembershipPlan / DigitalProduct / OrderBump) |
productType | String! | Canonical product class name (Course, Event, MembershipPlan, DigitalProduct, or OrderBump) |
productName | String! | Human-readable product name |
totalRevenue | Float! | Sum of post-discount line item amounts. Does not subtract refundedAmount — subtract it yourself for net-of-refund revenue |
refundedAmount | Float! | Sum of refunded line item amounts. Windowed by payment.paidAt like totalRevenue |
ordersCount | Int! | Number of distinct payments containing this product |
currency | String! | Currency code (e.g., TWD, USD) in ISO 4217 format |
periodStart | String! | Start of the requested period (ISO 8601) |
periodEnd | String! | End of the requested period (ISO 8601) |
Net revenue:
totalRevenueis gross of refunds. To compute net revenue for a product, subtractrefundedAmountfromtotalRevenueon the client.
Product Types
Section titled “Product Types”The productType argument uses the AdminProductType enum (values below). Note this differs from the productType field in the response, which is a String! containing the canonical class name (Course, Event, …) rather than the enum value (COURSE, EVENT, …):
| Value | Description |
|---|---|
COURSE | Course, aggregated across all of its curriculum plans |
MEMBERSHIP_PLAN | Membership plan |
DIGITAL_PRODUCT | Digital download product |
EVENT | Event, aggregated across all of its ticket types |
ORDER_BUMP | Order bump upsell SKU (its own product, not rolled into the underlying course/event) |
Sorting
Section titled “Sorting”The orderBy argument uses the AdminProductRevenueOrderBy enum:
| Value | Description |
|---|---|
TOTAL_REVENUE_DESC | Order by totalRevenue, highest first. This is the default. |
Payment Filtering
Section titled “Payment Filtering”The paymentFilter argument reuses the same AdminPaymentFilter input type as the Payments query, applied to the payments underlying each product’s line items. This lets you compute revenue for a slice of payments — for example, only those attributed to a given affiliate, or only a specific payment method.
| Filter Field | Type | Description |
|---|---|---|
id | StringOperator | Filter by payment ID |
amount | FloatOperator | Filter by payment amount |
paymentState | StringOperator | Filter by payment state |
paymentType | StringOperator | Filter by payment method (e.g., credit, atm, cvs, web_atm, barcode, line_pay). Only eq, neq, in, and nin are supported; values must be valid payment types |
affiliateCode | StringOperator | Filter by affiliate tracking code |
paidAt | IntOperator | Filter by payment timestamp (Unix timestamp) |
refundedAt | IntOperator | Filter by refund timestamp (Unix timestamp) |
createdAt | IntOperator | Filter by creation timestamp (Unix timestamp) |
tradeNo | StringOperator | Filter by trade/transaction number |
See the Payments query for the full operator reference (StringOperator, FloatOperator, IntOperator).
Note: The
since/untilarguments set the primary reporting window onpaidAt. ThepaymentFilterfields above are applied on top of that window — use them for non-time attributes (e.g.affiliateCode,paymentType) and, when needed, for additional timestamp constraints such asrefundedAtorcreatedAt.
Filter Examples
Section titled “Filter Examples”Revenue per course attributed to a specific affiliate:
query { productRevenues( productType: COURSE, paymentFilter: { affiliateCode: { eq: "summer-promo" } } ) { productId productName totalRevenue ordersCount }}Top-selling products paid by credit card or LINE Pay:
query { productRevenues( paymentFilter: { paymentType: { in: ["credit", "line_pay"] } }, limit: 20 ) { productId productType productName totalRevenue refundedAmount }}Revenue for specific courses by id (requires productType):
query { productRevenues( productType: COURSE, productIds: ["123", "456"] ) { productId productName totalRevenue refundedAmount ordersCount }}Relationships
Section titled “Relationships”The Product Revenues API relates to:
- Payments: Revenue is aggregated from the line items of the underlying payments
- Courses / Events / Membership Plans / Digital Products / Order Bumps: Each row maps to one canonical product
Detailed Query Structure
Section titled “Detailed Query Structure”Below is a comprehensive view of fields available in the productRevenues query:
query { productRevenues( since: 1704067200, # Period start, Unix timestamp (Int) — default 30 days ago until: 1735689600, # Period end, Unix timestamp (Int) — default now productType: COURSE, # Product category (AdminProductType) productIds: ["123"], # Canonical ids; requires productType ([ID!]) paymentFilter: { # Payment-level filters (AdminPaymentFilter) affiliateCode: { eq: "summer-promo" } paymentType: { in: ["credit", "line_pay"] } }, orderBy: TOTAL_REVENUE_DESC, # Sort key (AdminProductRevenueOrderBy) limit: 50 # Max products, clamped to 200 (Int) ) { productId # Canonical product id (ID!) productType # Canonical class name (String!) productName # Product name (String!) totalRevenue # Gross-of-refund revenue (Float!) refundedAmount # Refunded amount (Float!) ordersCount # Distinct payment count (Int!) currency # ISO 4217 currency code (String!) periodStart # Period start, ISO 8601 (String!) periodEnd # Period end, ISO 8601 (String!) }}