Extralingo Trips API
Saved trip configurations (not bookings)
Saved trip configurations (not bookings)
Every API here is available over the APIs.io API and to AI agents over MCP.
One button, every client — Claude, Cursor, VS Code and the rest.
https://apis.io/mcp
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.curl "https://apis.io/api/v1/apis/extralingo-com:extralingo-com-trips-api"
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.
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: 3.2.0
info:
title: Extralingo Public Trips 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: trips
description: Saved trip configurations (not bookings)
paths:
/trips:
post:
tags:
- trips
operationId: saveTrip
summary: Create or update a trip draft
description: Returns trip_id, url (legacy), trip_url, and continue_url (/s/{id}) so the student can continue on Extralingo.com with selections restored. Not a booking. No OTP.
requestBody:
content:
application/json:
schema:
type: object
properties:
school_id:
type: integer
trip_id:
type: string
configuration:
type: object
locale:
type: string
responses:
'200':
description: OK
content:
application/json:
schema:
$ref: '#/components/schemas/TripSavedResponse'
'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'
/trips/{tripId}:
get:
tags:
- trips
operationId: getTrip
summary: Load a saved trip
description: Returns continue_url for website handoff with the configuration restored.
parameters:
- name: tripId
in: path
required: true
schema:
type: string
responses:
'200':
description: OK
content:
application/json:
schema:
$ref: '#/components/schemas/TripSavedResponse'
'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'
/trips/{tripId}/email:
post:
tags:
- trips
operationId: emailTrip
summary: Email continue_url to the verified account
security:
- agentToken: []
description: Requires auth_token. Sends only to the verified account email. A different email is rejected. Without auth, use continue_url from save_trip.
parameters:
- name: tripId
in: path
required: true
schema:
type: string
requestBody:
content:
application/json:
schema:
type: object
properties:
email:
type: string
description: Optional. Must match the verified account email if sent.
firstName:
type: string
lastName:
type: string
locale:
type: string
responses:
'200':
description: OK
content:
application/json:
schema:
$ref: '#/components/schemas/TripEmailedResponse'
'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'
/trips/{tripId}/price:
post:
tags:
- trips
operationId: calculateTripPrice
summary: Live checkout quote (not a booking)
parameters:
- name: tripId
in: path
required: true
schema:
type: string
requestBody:
content:
application/json:
schema:
type: object
properties:
school_id:
type: integer
configuration:
type: object
currency:
type: string
default: EUR
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:
TripSavedResponse:
type: object
properties:
success:
type: boolean
trip_id:
type: string
url:
type: string
description: Saved trip URL (/s/{trip_id}). Alias of continue_url; kept for backwards compatibility.
trip_url:
type: string
description: 'Same as url: the /s/{trip_id} link for this saved trip draft.'
continue_url:
type: string
description: URL for the student to continue this configured trip on Extralingo.com with their current school, dates, course, accommodation and other saved selections restored.
school_url:
type: string
description: Locale-specific school page URL for browsing without the saved configuration.
school_id:
type: integer
school_name:
type: string
configuration:
type: object
additionalProperties: true
summary:
type: string
note:
type: string
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).
TripEmailedResponse:
type: object
properties:
success:
type: boolean
trip_id:
type: string
url:
type: string
description: Saved trip URL (/s/{trip_id}). Alias of continue_url; kept for backwards compatibility.
trip_url:
type: string
description: 'Same as url: the /s/{trip_id} link for this saved trip draft.'
continue_url:
type: string
description: URL for the student to continue this configured trip on Extralingo.com with their current school, dates, course, accommodation and other saved selections restored.
emailed_to:
type: string
message:
type: string
securitySchemes:
agentToken:
type: http
scheme: bearer
description: OAuth 2.1 access token from POST /oauth/token (authorization code + PKCE). See /auth.md.