Loopwise Docs
Admin APIQueries

Consulting Queries

How to query consulting services and their time-slot meetings in the Loopwise Admin API

Endpoint and authentication. All admin queries live on POST /admin/graphqlnot the /graphql endpoint, which is the public school API. Authenticate with an sk_live_… key in the X-Teachify-API-Key header. All consulting queries require the courses:read scope.

Overview

The Consulting API exposes:

  • Consulting services — coaching/consulting offerings attached to a course
  • Consulting meetings — individual time slots booked under a service

Both resources support paginated list queries with filters, plus singular lookups by ID.

Available Queries

QueryReturnsDescription
consultingServices(filter)AdminConsultingServicePage!Paginated list of consulting services
consultingService(id)AdminConsultingServiceSingle service by ID; null if not found
consultingMeetings(filter)AdminConsultingMeetingPage!Paginated list of meetings under consulting services
consultingMeeting(id)AdminConsultingMeetingSingle meeting by ID; null if not found or not under a consulting service

consultingServices

Returns a paginated list of consulting services for the school. Ordered by createdAt DESC, id DESC.

Filter Parameters (AdminConsultingServiceFilter)

FieldTypeDescription
courseIdStringFilter by parent course ID
slugStringExact slug match (school-scoped)
publishedBooleanFilter by published flag. Checks the boolean column directly, not the time-gated effective state
keywordStringCase-insensitive substring match against name or slug

Example

query ConsultingServices {
  consultingServices(filter: { published: true, keyword: "coaching" }) {
    nodes {
      id
      name
      slug
      published
      publishedAt
      courseId
      lecturerId
      lecturer {
        id
        name
      }
      effectiveTimezone
      meetingCount(state: available)
      tags
      createdAt
      updatedAt
    }
    currentPage
    totalPages
    hasNextPage
  }
}

AdminConsultingService Fields

FieldTypeDescription
idString!
nameString!Display name
slugString!URL-friendly identifier (school-scoped)
descriptionString
publishedBoolean!Whether the service is marked as published
publishedAtIntUnix timestamp; null if never published
tags[String!]Tag list stored in settings JSON
backgroundColorStringUI background color (hex)
ratingFormIdStringID of the linked feedback form, if any
courseIdStringParent course ID. Resolve details via the courses admin query
lecturerIdStringAssigned lecturer ID
lecturerAdminLecturerAssigned lecturer object (preferred over lecturerId for one-shot fetches)
effectiveTimezoneString!IANA timezone (e.g. Asia/Taipei). Use when converting local datetimes to Unix timestamps for meeting startedAt / endedAt
meetingCount(state)Int!Number of undiscarded meetings under this service, optionally filtered by AASM state
discardedAtIntUnix timestamp; non-null when soft-deleted
createdAtInt!Unix timestamp
updatedAtInt!Unix timestamp

consultingService

Returns a single consulting service by ID, scoped to the current school. Returns null if not found or not in this school.

Example

query ConsultingService {
  consultingService(id: "35a72dba-c3cc-4a06-b7eb-d784d010386e") {
    id
    name
    slug
    effectiveTimezone
    meetingCount(state: scheduled)
    lecturer {
      id
      name
    }
  }
}

consultingMeetings

Returns a paginated list of meetings under the school's consulting services. Ordered by startedAt DESC, id DESC.

Filter Parameters (AdminConsultingMeetingFilter)

FieldTypeDescription
serviceIdStringFilter by parent ConsultingService ID
lecturerIdStringFilter by assigned lecturer ID
stateMeetingStateAASM state: available, scheduled, or canceled
startedAfterIntUnix timestamp; matches meetings with startedAt >= value
startedBeforeIntUnix timestamp; matches meetings with startedAt <= value

Example

query ConsultingMeetings {
  consultingMeetings(filter: {
    serviceId: "35a72dba-c3cc-4a06-b7eb-d784d010386e"
    state: scheduled
    startedAfter: 1747200000
  }) {
    nodes {
      id
      title
      state
      startedAt
      endedAt
      serviceId
      lecturerId
      hostUserId
      hostEmail
      hostingType
      joinUrl
      maxAttendeeCapacity
      attendeeCount
      attendees {
        id
        email
        name
      }
    }
    currentPage
    totalPages
    hasNextPage
  }
}

AdminConsultingMeeting Fields

FieldTypeDescription
idString!
titleStringMeeting title
descriptionString
stateString!AASM state: available, scheduled, canceled
startedAtIntUnix timestamp
endedAtIntUnix timestamp
serviceIdStringParent ConsultingService ID. Resolve details via consultingService(id)
lecturerIdStringLecturer profile id (slug, URL routing, slot-overlap detection). NOT the person who runs the session — see hostUserId. Resolve via the lecturers admin query
hostUserIdStringUser id (school owner or teaching assistant) of the person who actually hosts the meeting. Sourced from meetings.hosts[0].id; null on legacy rows where no host was selected
hostEmailStringZoom license email used when hostingType: zoom. null for non-Zoom hosting types or when the school had no Zoom license configured
hostingTypeStringzoom, live_session, or custom
hostingIdStringExternal hosting platform meeting ID (e.g. Zoom meeting ID)
joinUrlStringPre-set join URL for zoom / custom hosting types
maxAttendeeCapacityIntMaximum students allowed; null or 0 means unlimited
priceFloat
currencyString!
attendeeCountInt!Current number of enrolled students
attendees[AdminUser!]!Enrolled students
discardedAtIntUnix timestamp; non-null when soft-deleted
createdAtInt!Unix timestamp
updatedAtInt!Unix timestamp

Meeting States

StateMeaning
availableSlot is open; no students enrolled (or all have been removed)
scheduledAt least one student has been confirmed for this slot
canceledSlot has been canceled

consultingMeeting

Returns a single consulting meeting by ID, scoped to the current school. Returns null if not found, not in this school, or not under a consulting service.

Example

query ConsultingMeeting {
  consultingMeeting(id: "0186b768-c0c0-4d75-8fb7-7fee0b3ee9c1") {
    id
    state
    startedAt
    endedAt
    attendeeCount
    attendees {
      id
      email
      name
    }
  }
}

meetingHosts

Returns the school owner plus all undiscarded teaching assistants — the exact user pool accepted by hostUserId on bulkCreateConsultingMeetings and updateConsultingMeeting. Use this before writing a meeting to populate UI host pickers or to pre-validate, rather than relying on the MEETING-012 valid_options= recovery suffix after a bad write.

Each row carries an explicit role discriminator (owner or teaching_assistant) — filter by role rather than relying on response ordering when you only want one or the other. The owner is deduplicated to a single role: owner row when they also hold the teaching_assistant role; TAs are returned in user.createdAt ascending order so you can pick the most-tenured by index.

Example

query MeetingHosts {
  meetingHosts {
    role
    user {
      id
      name
      email
      createdAt   # use to pick "most senior TA" when needed
    }
  }
}

AdminMeetingHost Fields

FieldTypeDescription
roleAdminMeetingHostRole!owner (the school owner) or teaching_assistant
userAdminUser!The user record. Pass user.id as hostUserId on the mutation

Notes

  • Scope: school-wide. Returns a non-paginated array — the pool is intentionally small (1 owner + N TAs).
  • The admin API does NOT gate on the school admin UI's :learning_center feature flag; TAs are always returned regardless of the flag's state. The school admin UI may show a narrower pool.
  • Required OAuth scope: courses:read (the same scope as the other consulting queries).
  • Empty result means the school has no eligible hosts (owner was soft-deleted AND no teaching assistants exist). Consulting meeting mutations will fail MEETING-012 with empty valid_options= until either the owner is restored or a teaching assistant is invited via the school admin UI.

zoomHosts

Returns the Zoom license seats configured under the school's active Zoom integration — the exact set of values accepted by hostEmail on consulting meeting mutations when hostingType: zoom. Use this before writing a Zoom meeting, instead of relying on the MEETING-011 valid_options= recovery suffix after a bad write.

Returns an empty list when the school has no active Zoom integration (the same precondition that MEETING-009 enforces on the mutation) or when the integration has no license metadata recorded. Order matches Settings → Integrations → Zoom in the admin UI.

Example

query ZoomHosts {
  zoomHosts {
    email
    name
  }
}

AdminZoomHost Fields

FieldTypeDescription
emailString!Zoom license email. Pass as hostEmail on consulting meeting mutations
nameStringDisplay name configured for this license seat; null if not set

Notes

  • Scope: school-wide. Required OAuth scope: courses:read.
  • Result reflects only the active Zoom integration. Inactive integrations are intentionally hidden so callers can't accidentally provision against a disabled seat.

On this page