Extralingo Schools API

Search and compare language schools

GitHub OpenAPI

Operations 7

GET /school-finder/search Search language schools (GET) #
POST /school-finder/search Search and rank language schools #
GET /school-finder/filters List available school search filters #
GET /schools/{schoolId} School profile, images and booking flags #
GET /schools/{schoolId}/courses Live course catalogue #
GET /schools/{schoolId}/starting-dates Allowed course start dates #
GET /schools/{schoolId}/accommodations Accommodation groups #

Work with this as data

Every API here is available over the APIs.io API and to AI agents over MCP.

MCP server

One button, every client — Claude, Cursor, VS Code and the rest.

https://apis.io/mcp

Tools for apis

7 MCP tools reach this
  • find_apisBrowse and filter every API in the catalog.
  • get_api_artifactsOne API's artifacts, grouped by type.
  • get_openapiThe primary OpenAPI for this API.
  • find_similar_apisAPIs that look like this one.
  • apis_io_searchSTART HERE — APIs, providers and tags for one query, each with its total.
  • resolveTurn a domain, URL or GitHub org into the provider it belongs to.
  • find_cohortsEvery scored population of providers in the catalog.
All 92 tools →

Call it yourself

curl for this page
This API
curl "https://apis.io/api/v1/apis/extralingo-com:extralingo-com-schools-api"
All apis
curl "https://apis.io/api/v1/apis?limit=25"

Calls without X-API-Key need no key. Calls with it need a paid plan — get a key.

Get an API key

Free tier, no form to fill in. Signing in shares your email address with us — we store it to create your key and to recognise you if you sign in with another provider. See our Privacy Policy and Terms.

A second provider on the same verified email joins the account you already have.

OpenAPI Specification

extralingo-com-schools-api-openapi.yml Raw ↑
openapi: 3.2.0
info:
  title: Extralingo Public Schools API
  version: 1.0.0
  summary: Search language schools, configure trips, and submit unpaid bookings.
  description: 'Version **1.0.0** of the Extralingo agent REST API. All paths below are relative to **`https://www.extralingo.com/api/v1`** (the documented base). The same routes also work under unversioned `/api/*` and remain fully supported. Breaking changes ship under `/api/v2` with at least 6 months'' notice; deprecated endpoints will eventually send `Deprecation` and `Sunset` headers before removal. **Read** endpoints need no authentication. **Write** endpoints require OAuth 2.1 (authorization code + PKCE S256; scopes `trips`, `requests`, `bookings`; discover the resource at /.well-known/oauth-protected-resource; see /auth.md). Create endpoints accept optional **`Idempotency-Key`** (IETF draft): same key + same authenticated user + same JSON body within 24 hours returns the original response; same key + different body returns **422**. When OAuth is enabled, `POST /trips` is gated like MCP `save_trip`. Finder prices are indicative; call `POST /trips/{trip_id}/price` for a live quote. create_booking is unpaid: the school still confirms, Extralingo emails the student, and payment is only via Extralingo after confirmation. Prefer POST /mcp (MCP) if you can use tools. Keep request volumes reasonable; usage may be rate-limited. Developer overview: /en/developers. Site index: /llms.txt.'
  contact:
    name: Extralingo
    url: https://www.extralingo.com/en/contact
servers:
- url: https://www.extralingo.com/api/v1
  description: Agent REST API v1 (production)
tags:
- name: schools
  description: Search and compare language schools
paths:
  /school-finder/search:
    get:
      tags:
      - schools
      operationId: searchSchoolsGet
      summary: Search language schools (GET)
      description: Same search as POST. Agents may GET. Limit is capped at 20. Each hit includes `school_id` (Craft id) for later calls. Prices are indicative.
      parameters:
      - $ref: '#/components/parameters/Locale'
      - name: query
        in: query
        schema:
          type: string
      - name: language
        in: query
        schema:
          type: string
      - name: country
        in: query
        schema:
          type: string
      - name: cities
        in: query
        schema:
          type: string
        description: Comma-separated city names.
      - name: limit
        in: query
        schema:
          type: integer
          minimum: 1
          maximum: 20
          default: 10
      responses:
        '200':
          description: Ranked search results
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/SchoolSearchResponse'
    post:
      tags:
      - schools
      operationId: searchSchools
      summary: Search and rank language schools
      description: Typo-tolerant search over approved language schools, ranked by match against the supplied preferences. Free-text `query` plus optional structured filters. Each hit includes a school URL on Extralingo for booking/details.
      requestBody:
        required: false
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/SchoolSearchRequest'
            examples:
              spanish-in-barcelona:
                summary: Spanish courses in Barcelona, 3 results
                value:
                  query: ''
                  language: spanish
                  cities:
                  - Barcelona
                  limit: 3
                  locale: en
      responses:
        '200':
          description: Ranked search results
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/SchoolSearchResponse'
  /school-finder/filters:
    get:
      tags:
      - schools
      operationId: getSchoolFilters
      summary: List available school search filters
      description: Returns the facet values (languages, countries, cities, course types, accommodation types, atmosphere tags, school/class sizes, etc.) that can be used as filters in POST /api/school-finder/search.
      parameters:
      - $ref: '#/components/parameters/Locale'
      responses:
        '200':
          description: Available filter options
          content:
            application/json:
              schema:
                type: object
                properties:
                  success:
                    type: boolean
                  data:
                    type: object
                    additionalProperties: true
  /schools/{schoolId}:
    get:
      tags:
      - schools
      operationId: getSchool
      summary: School profile, images and booking flags
      description: Pass include_hero_image=1 to also receive a compressed JPEG (base64) for chat display. Image URLs are always included.
      parameters:
      - name: schoolId
        in: path
        required: true
        schema:
          type: integer
        description: Craft school id from search hits (`school_id`).
      - $ref: '#/components/parameters/Locale'
      - name: include_hero_image
        in: query
        schema:
          type: boolean
          default: false
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '400':
          description: Bad request
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '401':
          description: Email verification required
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '404':
          description: Not found
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '422':
          description: Validation failed or idempotency key reused with a different payload
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '429':
          description: Rate limited
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
  /schools/{schoolId}/courses:
    get:
      tags:
      - schools
      operationId: listCourses
      summary: Live course catalogue
      parameters:
      - name: schoolId
        in: path
        required: true
        schema:
          type: integer
        description: Craft school id from search hits (`school_id`).
      - $ref: '#/components/parameters/Locale'
      - name: currency
        in: query
        schema:
          type: string
          default: EUR
      - name: startDate
        in: query
        schema:
          type: string
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '400':
          description: Bad request
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '401':
          description: Email verification required
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '404':
          description: Not found
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '422':
          description: Validation failed or idempotency key reused with a different payload
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '429':
          description: Rate limited
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
  /schools/{schoolId}/starting-dates:
    get:
      tags:
      - schools
      operationId: listStartingDates
      summary: Allowed course start dates
      parameters:
      - name: schoolId
        in: path
        required: true
        schema:
          type: integer
        description: Craft school id from search hits (`school_id`).
      - $ref: '#/components/parameters/Locale'
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '400':
          description: Bad request
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '401':
          description: Email verification required
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '404':
          description: Not found
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '422':
          description: Validation failed or idempotency key reused with a different payload
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '429':
          description: Rate limited
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
  /schools/{schoolId}/accommodations:
    get:
      tags:
      - schools
      operationId: listAccommodations
      summary: Accommodation groups
      parameters:
      - name: schoolId
        in: path
        required: true
        schema:
          type: integer
        description: Craft school id from search hits (`school_id`).
      - $ref: '#/components/parameters/Locale'
      - name: currency
        in: query
        schema:
          type: string
          default: EUR
      - name: startDate
        in: query
        schema:
          type: string
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '400':
          description: Bad request
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '401':
          description: Email verification required
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '404':
          description: Not found
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '422':
          description: Validation failed or idempotency key reused with a different payload
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '429':
          description: Rate limited
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
components:
  schemas:
    Error:
      type: object
      properties:
        success:
          type: boolean
          examples:
          - false
        error:
          type: string
        code:
          type: string
        hint:
          type: string
        retryAfter:
          type: integer
          description: Seconds until the daily account-school limit resets (Europe/Amsterdam midnight).
    SchoolSearchResponse:
      type: object
      properties:
        success:
          type: boolean
        data:
          type: object
          properties:
            hits:
              type: array
              description: Ranked schools. Each hit includes school_id, title, location, Extralingo URL, and indicative pricing. Prices are not a booking quote.
              items:
                type: object
                additionalProperties: true
            totalHits:
              type: integer
            query:
              type: string
            facetDistribution:
              type: object
              additionalProperties: true
    SchoolSearchRequest:
      type: object
      description: All fields optional. Omitted fields are not constrained.
      properties:
        query:
          type: string
          description: Free-text query (school name, keywords).
        locale:
          type: string
          enum:
          - en
          - nl
          - da
          - sv
          default: en
        language:
          type: string
          description: Language slug, e.g. "spanish".
        country:
          type: string
          description: Country name as returned by /filters.
        cities:
          type: array
          items:
            type: string
          description: City names as returned by /filters.
        course_type_titles:
          type: array
          items:
            type: string
        accommodation_type_titles:
          type: array
          items:
            type: string
        atmosphere_tags:
          type: array
          items:
            type: string
        accreditations:
          type: array
          items:
            type: string
        class_size:
          type: string
        school_size:
          type: string
        age:
          type: string
        facets:
          type: array
          items:
            type: string
          description: Facet fields to return distributions for.
        limit:
          type: integer
          minimum: 1
          maximum: 200
          default: 50
        offset:
          type: integer
          minimum: 0
          default: 0
  parameters:
    Locale:
      name: Locale
      in: query
      required: false
      schema:
        type: string
      description: Referenced by this document but never defined in it. API Evangelist added this empty placeholder so the document resolves; the shape is unknown and is NOT a claim about the API.
      x-ae-placeholder: true
  securitySchemes:
    agentToken:
      type: http
      scheme: bearer
      description: OAuth 2.1 access token from POST /oauth/token (authorization code + PKCE). See /auth.md.