Skip to content

Developers

Your centre's data,on your terms.

A REST API for your centre's own website, spreadsheet or systems. Read lessons, rolls, families, invoices and enquiries, and send new enquiries from your own form. You make the keys, choose what each one may do, and revoke one in a click.

The API is switched on centre by centre. Ask us to switch it on for yours, then make a key under Settings, Connections, API keys.

JSON in, JSON out.
GET /lessons
$ curl https://yourcentre.xtutio.com/api/v1/lessons?limit=2 \
  -H "Authorization: Bearer xtk_..."
{
  "data": [
    {
      "id": "1a2b3c4d-...",
      "starts_at": "2026-11-02T06:00:00Z",
      "status": "scheduled",
      "subject": "maths",
      "delivery": "centre",
      "campus_id": "3f1c2a9e-..."
    }
  ],
  "next_cursor": "eyJpZCI6...",
  "has_more": true
}

Every answer

Your centre's rows only
endpoints
21
permissions a key can carry
17
requests a minute, at most
600
webhook events they match
8

Keys

You make the keys. You decide what each may do.

Settings, Connections, API keys. Name a key, tick its permissions, and copy it once. Only someone who can manage your centre's connections, signed in with two-step sign-in, can make or revoke one.

  • Shown once, stored scrambled

    A key is shown the moment you make it and never again. We keep only a scrambled copy, so a database copy cannot be turned back into a working key.

  • Permissions per key

    Each key carries only the permissions you tick, from 17: read lessons but not invoices, or send enquiries and nothing else.

  • Your addresses and websites

    Lock a key to your office's internet address, and name the websites allowed to call it from a browser. Anything else is refused.

  • Revoke in a click

    A revoked key stops working on the next request. Every key made or revoked is written to your centre's audit log.

Your CentreIntegrations ยท API keys

API keys

Make a key
  • Website enquiry formenquiries:write, campuses:readActive
  • Finance spreadsheetinvoices:read, families:readActive
  • Old booking widgetlessons:readRevoked

A new key is shown once. Copy it now: it cannot be shown again.

Your own enquiry form

Send enquiries from your own website.

Keep the form your website already has, and send what a family types straight into your enquiries. It lands with its source and campaign, ready for the front desk.

  • The same checks as your form

    The same fields and limits, your own required questions, your own campuses, and the family's marketing choice respected.

  • No surprise messages

    The API emails and texts nobody. Your admins see the enquiry in the portal, as they do from the form.

  • Duplicates caught

    The same family twice in a day is acknowledged without a second enquiry, and one parent email can send at most 3 an hour.

POST /enquiries
$ curl -X POST https://yourcentre.xtutio.com/api/v1/enquiries \
  -H "Authorization: Bearer xtk_..." \
  -H "Content-Type: application/json" \
  -d '{
    "parent_full_name": "Sam Example",
    "parent_email": "sam@example.com",
    "students": [{ "full_name": "Leo Example",
                   "year_level": "Year 4" }],
    "consent": true
  }'
HTTP/1.1 201 Created
{ "data": { "id": "4d5e6f70-...", "received": true } }

Privacy

What never leaves, whatever a key may do.

  • Never leaves

    Home addresses and home notes, a child's own contact details, safety records, AI conversations, lesson notes, custom field values and payment ids. No endpoint returns them, whatever a key may do.

  • Only your centre

    The key decides the centre, never the request. Every query names it, so one centre's key can never read another centre's rows.

  • Contact details on purpose

    An enquiry's parent email and phone come back only with their own permission, which no preset ticks. Students come back as names, year and campus only.

  • Reads, and one write

    The only thing the API can write is a new enquiry, checked exactly as your own enrolment form checks it. Lessons, the roll and anything to do with money are changed in the portal, never through the API.

Permissions

17 permissions. Tick only what a key needs.

Each one reads one kind of record, and one sends enquiries. A key that tries anything else is answered 403 scope_missing.

  • campuses:read

    Campuses

  • services:read

    Services and prices

  • tutors:read

    Tutors (first name, subjects, campus)

  • families:read

    Families (name and campus)

  • students:read

    Students (names, year, campus)

  • lessons:read

    Lessons

  • invoices:read

    Invoices

  • enquiries:read

    Enquiries

  • enquiries:write

    Send new enquiries

  • enquiry_contacts:read

    Enquiry contact details (the parent's name, email and phone they sent)

    Contact details: never in a preset.

  • attendance:read

    Attendance (the roll for each lesson)

  • subjects:read

    Subjects the centre teaches

  • tags:read

    Tags on families and students

  • tasks:read

    Staff tasks (title, status, due date; never the notes)

  • waitlist:read

    Waitlist (what each family is waiting for; no contact details)

  • classes:read

    Group classes (times, seats and enrolment counts)

  • reviews:read

    Term progress reviews (only those released to families)

Reference

Every endpoint.

Under /api/v1 on your centre's own address. 7 of them read a feature that is switched on separately, and answer 501 feature_not_enabled until it is. The full description, with every field and example, is the OpenAPI document.

  • GET/me

    The key making the request: its name, centre and permissions.

    any key
  • GET/campuses

    The centre's campuses.

    campuses:read
  • GET/services

    The services the centre sells, with their prices in cents (AUD).

    services:read
  • GET/tutors

    Active tutors: first name, subjects and campus.

    tutors:read
  • GET/families

    Families: name, campus and number of students.

    families:read
  • GET/students

    Students: first and last name, year level, family and campus.

    students:read
  • GET/lessons

    Lessons in date order. Defaults to lessons from today; give from and to (ISO dates) to change that.

    lessons:read
  • GET/lessons/{id}

    One lesson.

    lessons:read
  • GET/invoices

    Invoices, newest first, with totals in cents (AUD).

    invoices:read
  • POST/enquiries

    Send an enquiry, as the centre's own enrolment form does (same checks, same limits). Returns the enquiry's id.

    enquiries:write
  • GET/enquiries

    Enquiries, newest first: status, source, campus, the children's first names and years, and answers to the centre's own questions.

    enquiries:read
  • GET/enquiries/{id}

    One enquiry. The id is the one enquiry.created webhooks carry.

    enquiries:read
  • GET/attendance

    The roll for each lesson, in date order: who was expected, present, absent or late.

    attendance:read
  • GET/subjects

    The subjects the centre teaches.

    subjects:read
  • GET/tags

    The centre's tags.

    Available once tags and groups is switched on.

    tags:read
  • GET/tags/{id}/members

    The families and students carrying a tag.

    Available once tags and groups is switched on.

    tags:read
  • GET/tasks

    Staff tasks: title, status, due date and what each is about. Never the notes or comments.

    Available once staff tasks is switched on.

    tasks:read
  • GET/waitlist

    Families waiting for a place: the subject, days, times and campus they want. No contact details.

    Available once the waitlist is switched on.

    waitlist:read
  • GET/classes

    Group classes with their times, capacity, seats left and how many are waiting. Published classes unless status is given.

    Available once group classes is switched on.

    classes:read
  • GET/classes/{id}

    One group class.

    Available once group classes is switched on.

    classes:read
  • GET/progress-reviews

    Term progress reviews released to families, exactly as the family reads them.

    Available once term progress reviews is switched on.

    reviews:read

Limits and pages

Plain limits. Plain errors.

Each key has its own limit, from 10 to 600 requests a minute (60 unless you choose otherwise), and every answer says how many are left. Lists come 25 at a time, up to 100, with a cursor for the next page.

Every error is JSON with a code and a sentence you can show a person. It never carries the database's words.

Over the limit
$ curl https://yourcentre.xtutio.com/api/v1/lessons?limit=2 \
  -H "Authorization: Bearer xtk_..."
HTTP/1.1 429 Too Many Requests
Retry-After: 30
X-RateLimit-Limit: 60
X-RateLimit-Remaining: 0

{ "error": { "code": "rate_limited",
  "message": "Too many requests. Slow down and try again." } }

Errors

The codes you will meet.

Error codes the API answers with
StatusCodeWhat it says
400invalid_requestThe request is not valid.
401unauthorisedSend a valid API key as 'Authorization: Bearer <key>'.
401key_revokedThis API key has been revoked.
403scope_missingThis key does not have the permission this needs.
403address_not_allowedThis key may not be used from this address.
404not_foundNot found.
413payload_too_largeThe request is too large.
429rate_limitedToo many requests. Slow down and try again.
501feature_not_enabledThis feature is not switched on for this centre yet.
500server_errorSomething went wrong on our side. Try again shortly.

With webhooks

Hear about it. Then read it.

Where your centre has outgoing webhooks switched on, each event carries an id. These are the endpoints that read the thing each event is about.

  • enquiry.createdGET /enquiries/{id}
  • family.createdGET /families
  • student.createdGET /students
  • lesson.bookedGET /lessons/{id}
  • lesson.cancelledGET /lessons/{id}
  • lesson.completedGET /attendance?lesson_id={id}
  • invoice.issuedGET /invoices
  • payment.receivedGET /invoices

In short

Developers

XTutio has a REST API for a centre's own website, spreadsheet or systems: it reads lessons, rolls, families, invoices and enquiries, and its one write is a new enquiry, checked as the enrolment form checks it. A centre makes its own keys, chooses what each may do and can revoke one at any time. It is switched on centre by centre.

Questions centres ask

Can the API change lessons or money?

No. Its only write is a new enquiry. Lessons, the roll and anything to do with money are changed in the portal.

Can one centre's key read another centre's data?

No. The key decides the centre, and every query names it.

Is the API on for every centre?

No. It is switched on centre by centre; then the centre makes a key under Settings, Connections, API keys.

Tell us what you want to connect. We will switch the API on for your centre.