---
canonical: "https://findaskischool.com/help/integrations-and-technical/how-do-i-use-the-api-and-mcp-server"
language: en
last_modified: "2026-10-20T16:05:23.000Z"
---

# How do I use the public API and MCP server?

A public REST API at /api/v1 gives developers read access to school, resort, and instructor data, with scoped API keys, per-key rate limits, and a documented error shape. The MCP server at /mcp lets AI assistants search the platform — and, with a school-scoped key, manage your school's profile, lessons, bookings, and reviews.

## Quick answer

The REST API lives at /api/v1 (Swagger docs at /api/v1/docs) and accepts keys via the Authorization: Bearer or X-API-Key header. MCP uses /mcp over Streamable HTTP: public discovery needs no key; private school reads and writes need a school-scoped bearer key with the matching scopes on every request. Default shared REST/MCP key limits: 60 requests/minute, 10,000/day.

## How do I use the public API and MCP server?

For technical teams who want programmatic access to platform data — building custom dashboards, integrating with internal systems, or making your school workable by AI agents — the platform provides a public REST API and an MCP (Model Context Protocol) server.

## The REST API at a glance

The API is versioned under `/api/v1` (every response carries an `X-API-Version` header). Read endpoints:

-   `GET /api/v1/schools` and `GET /api/v1/schools/{slug}` — search and detail, with filters for country, resort, activity, level, language, school type, certified, and featured, plus `page` and `limit` (max 100 per page)
-   `GET /api/v1/resorts` and `GET /api/v1/resorts/{slug}`
-   `GET /api/v1/countries` and `GET /api/v1/countries/{slug}`
-   `GET /api/v1/instructors`
-   `GET /api/v1/activities`, `/experience-levels`, `/languages`, and `/age-ranges` — the taxonomy lists used by the filters

Interactive documentation lives at `/api/v1/docs` (Swagger UI), the machine-readable spec at `/api/v1/openapi.json`, and a developer guide at `/api-docs` on the main site. For AI agents there are also `/llms.txt` and `/llms-full.txt` site descriptions.

Every response uses one envelope:

```json
{ "success": true, "data": [ ... ], "meta": { "total": 132, "page": 1, "limit": 24, "total_pages": 6 } }
```

Errors invert it: `{ "success": false, "error": { "message": "...", "status": 404 } }`.

## Authentication and API keys

Keys start with the `fass_` prefix. For REST requests, either header works:

-   `Authorization: Bearer fass_xxx`
-   `X-API-Key: fass_xxx`

Query-string keys (`?api_key=`) are deliberately not supported — they leak long-lived credentials into proxy logs and browser history.

MCP uses `Authorization: Bearer` on every authenticated request. The REST `X-API-Key` alternative is not the MCP authentication contract.

Each key carries: a name and description, a set of **scopes**, optional per-minute and per-day **rate limits**, an optional **expiry date**, and optionally a **school link**. Scopes follow a `resource:read` / `resource:write` pattern — `schools:read`, `instructors:read`, `lessons:write`, `bookings:write`, `reviews:write`, `analytics:read`, and so on. The scope model fails closed: a request needs the matching scope for its resource and method, and endpoints outside the documented surface are denied outright.

School owners and co-owners can approve short-lived school MCP keys at `/account/school-mcp-access`, choosing only the necessary scopes. These keys require a verified active account, explicit consent, and the issuer's current ownership access; they expire within 30 days and can be rotated or revoked from that page. Inbox permission is a separate opt-in. Administrator-issued service keys remain available from the dashboard's **API keys** panel and retain their separate lifetime. The full key is shown **once**; only its hash is stored. Delegated school/customer credentials must be replaced through their consent pages; generic administrator edits cannot widen or restore their consent. Usage records include endpoint, status, and response time.

## Rate limits

Three layers apply, all per minute unless stated:

-   **With an API key** — the key's shared REST/MCP budget: by default **60 requests/minute** and **10,000/day**. Higher limits can be set per key (this is the "contact us for high volume" path).
-   **Without a key** — `/api/v1` works for anonymous reads but is limited to 60 requests/minute per IP.
-   **A broad outer fence** of 1,000 requests/minute per IP protects the whole `/api` surface against runaway clients.

Keyed responses include live quota headers: `X-RateLimit-Limit-Minute`, `X-RateLimit-Remaining-Minute`, `X-RateLimit-Limit-Day`, and `X-RateLimit-Remaining-Day`. Watch the remaining counts and back off before you hit zero.

### What a 429 looks like

When you exceed a key's limit you get HTTP 429 with a `Retry-After` header (in seconds) and:

```json
{
  "error": "Rate limit exceeded",
  "retryAfter": 42,
  "limits": { "perMinute": 60, "perDay": 10000 }
}
```

The outer per-IP fence uses a shorter body: `{ "error": "rate_limited", "retryAfter": 60 }`, also with `Retry-After`. Honour the header — sleeping for `retryAfter` seconds and retrying is the correct client behaviour. If you hit limits routinely, that's usually a polling pattern that should be a cache.

## REST error handling

The codes you'll meet, and what they mean:

-   **401** — no key where one is required, or an invalid, expired, or revoked key: `{ "error": "Invalid API key", "message": "The provided API key is invalid, expired, or has been revoked." }`
-   **403** — your key is valid but lacks the scope: the body names the missing scope and lists what the key was granted, so the fix is self-evident
-   **404** — resource not found, in the standard `success: false` envelope
-   **429** — rate limited, as above
-   **500** — server error. Read requests can normally be retried with backoff. For a write, first read the current record to establish whether the change completed; retrying blindly can duplicate work. Honour any documented idempotency rules for the operation.

## The MCP server

The MCP server is the API's equivalent for AI agents. It runs at:

```
https://findaskischool.com/mcp
```

using the **Streamable HTTP** transport (POST for JSON-RPC requests, GET for the notification stream, DELETE to close a session — your MCP client handles all of that). A discovery document at `/mcp/info` lists every tool, and the full developer guide is at `/mcp-docs`.

For school users, the main tool groups are:

-   **Public tools — no key needed**: `search_schools`, `get_school_detail`, `search_resorts`, `get_resort_detail`, `list_countries`, `list_activities`, `search_instructors`, `compare_schools`, `search_lessons`, `get_lesson_detail`, `get_lesson_availability`, and `get_lesson_quote`. These expose public school, resort, instructor, and lesson information. Lesson search shares the website's filters. Availability is provisional: typical school times do not establish remaining capacity, and quotes reserve no places. The booking form rechecks eligibility, capacity, and price.
-   **Management tools — school-scoped key required**: get and update basic school contact/profile details, list/add/update/remove instructors, list/add/update/delete basic lessons, list/read/confirm/cancel/complete school bookings, list and respond to reviews, and pull analytics and dashboard summaries. Read and write scopes are both enforced. `get_my_school` requires `schools:read`, `instructors:read`, and `lessons:read`; `get_my_dashboard` requires `analytics:read`, `bookings:read`, `reviews:read`, and `instructors:read`.

Additional platform-administration and content tools have separate restricted keys and scopes; a school key does not grant that access.

Four operational read tools are also available. `get_my_calendar` and `get_instructor_availability` read up to 31 school-local days with the required booking/instructor/availability scopes and omit learner contact, medical, and payment fields. `list_school_conversations` and `get_school_conversation` require `messages:read`, current owner/co-owner inbox permission, and the account's existing history cutoff. Administrator observer powers are not delegated through school keys. Message text is included only on explicit request, is bounded, and reading does not mark a thread read.

Customers can grant separate, short-lived personal access at `/account/mcp-access` after signing in with a verified email. The customer scopes are `customer:bookings:read` and `customer:bookings:write`; they cannot be combined with school or administration scopes. `list_my_customer_bookings` and `get_customer_booking_status` read only the customer's account-owned bookings. `prepare_customer_booking` returns a signed handoff for the same customer to continue in the browser. It creates no booking or capacity hold until the customer submits the booking form with participant details, policy acceptance, and CAPTCHA; online checkout then uses the existing browser payment flow where supported. Keys expire within 30 days and can be revoked or rotated from the same account page.

To connect an MCP-capable client, add a remote server with the URL above. For management access, send your key as an `Authorization: Bearer fass_xxx` header on every request, including session POST, GET, and DELETE requests. A session ID alone does not authenticate the client. Start a new session when changing keys or scopes. Public access needs no authentication header.

MCP has its own limits: 60 requests/minute per IP, 30 authenticated tool calls/minute per key, and a deliberately tight 5/minute throttle on failed key attempts. Authenticated requests also consume the shared REST/MCP key budget described above. Invalid-key failures come back as JSON-RPC errors — code `-32001` (HTTP 401), or `-32002` when failed attempts are throttled (HTTP 429). Tool-level scope or ownership refusals are returned as MCP tool errors.

Native clients that omit `Origin` are supported. Browser clients that supply `Origin` must match the deployment's configured trusted origins. Sessions have idle timeouts and count limits; reconnect if a session expires, and close unused sessions.

### Reading school bookings

`list_my_bookings` accepts optional `status`, `start_date` (inclusive), and `end_date` (exclusive) filters. Dates are ISO 8601 timestamps with a timezone. Pagination uses `limit` (default 50, maximum 100) and `offset` (default 0). The result includes `total`, `limit`, `offset`, `nextOffset`, and `bookings`. Repeat the same filters with `offset` set to `nextOffset` until it is `null`.

`get_my_booking` accepts `booking_id` to retrieve one booking belonging to your school. Both booking read tools require `bookings:read`.

### What still needs the website

Customer booking confirmation, participant details, consent, CAPTCHA, and payment require the browser. Selected-instructor slots may report observed 0/1 session capacity; unverified staffing and remaining group seats remain unknown. Availability reserves no capacity. Customer cancellation/refunds, school inbox replies, calendar/availability changes, rescheduling, instructor assignments, refunds, photo galleries, school policies/FAQs, support tickets, and full lesson configuration still require the website. `cancel_booking` changes booking status; it does not issue a refund. `update_my_school` accepts description, website, email, phone, and default currency, rather than school name, hours, or pricing.

## Using an AI assistant safely

An **Ask ChatGPT** or **Ask Claude** link can open a prepared prompt about a public guide. It does not automatically connect the assistant to your FASS account, grant a key, or give it access to a private dashboard. Provider support for prefilled prompts and remote MCP depends on the client and account.

To act on school data, configure an MCP-capable client separately using the current [MCP guide](https://findaskischool.com/mcp-docs) and a school-scoped key. Start with the minimum read permissions you need. Review proposed changes before authorising write actions; an AI answer is not proof the change was saved.

Keep API keys in the connector's secure configuration, never in a prompt, guide URL, screenshot, or public message. Do not paste private learner details into an external assistant unless you are authorised to share them. Public guide links can help explain a process without disclosing account data.

## A worked example

Search French schools, five results per page, with a key:

```bash
curl "https://findaskischool.com/api/v1/schools?country=france&limit=5" \
  -H "Authorization: Bearer fass_YOUR_KEY"
```

The response's `data` array contains school objects (slug, name, type, description, country, resort, contact details, private and group lesson prices, currency, and canonical URL), with pagination in `meta`. Drop the header and the same call still works under the anonymous per-IP limit — useful for trying things out before a key is issued.

## Webhooks

Outbound webhooks currently cover **support-ticket events only**: `ticket.created`, `ticket.replied`, `ticket.status_changed`, and `ticket.resolved`, configured from the dashboard's ticket webhooks tab. Payloads are signed with HMAC-SHA256 in an `X-Ticket-Signature` header so your handler can verify authenticity. There are no booking or review webhooks yet; use the school's MCP read tools at a sensible polling interval.

## Support

API and MCP support is best-effort for Starter and Independent Instructor plans, and prioritised for School and Multi-School plans. For most integrations the Swagger docs and `/mcp-docs` are enough; for edge cases or higher rate limits, contact us through the dashboard support channel.
