API 문서
LockTrip 호텔 예약 MCP API의 완전한 레퍼런스. 검색, 예약, 결제, 관리를 커버하는 15개 도구.
Integrating a backend service? The same product is available as a native GraphQL API with credit line billing for B2B partners. See the GraphQL B2B docs →
인증
API는 Bearer JWT 토큰을 사용합니다. 검색 및 탐색 도구는 인증이 필요 없습니다. 예약 및 관리 도구에는 유효한 토큰이 필요합니다.
토큰 받기
guest_login(이메일만, 즉시) 또는 login(이메일 + 비밀번호)을 사용하여 JWT 토큰을 받으세요.
토큰 사용
Authorization: Bearer eyJhbGciOiJIUzUxMiJ9...
OAuth 2.1 (MCP 클라이언트)
MCP 클라이언트(예: Claude, ChatGPT)는 PKCE를 사용하는 OAuth 2.1로 자동 인증되며, 별도로 설정할 필요가 없습니다. 401이 반환되면 클라이언트는 https://locktrip.com/.well-known/oauth-authorization-server 에서 서버를 검색하고 동적으로 등록(POST /register)한 뒤 authorization code 플로를 실행합니다: /authorize(사용자 동의, Cloudflare Turnstile로 보호) → /token. 스코프는 "mcp"이며, 리프레시 token이 필요하면 "offline_access"를 추가합니다. REST나 curl로 직접 연동할 때는 대신 수동 Bearer token을 사용하세요(위 참조).
Per-call auth: sessionToken
REST 또는 JSON-RPC를 직접 호출할 때 인증이 필요한 도구는 Authorization 헤더 대신 sessionToken 인자도 받습니다. guest_login token(이메일만 — 비밀번호 없이 즉시)은 게스트 세션을 만들며, 게스트 세션은 prepare_booking과 create_checkout에서만 동작합니다. get_payment_url, list_bookings, get_booking_details, cancel_booking, confirm_booking은 모두 등록된 계정이 필요하며, 해당 token은 login(이메일 + 비밀번호)으로 발급받습니다. 여신 한도를 가진 B2B 파트너는 반드시 login으로 인증해야 하며 guest_login을 사용해서는 안 됩니다. 게스트 세션에는 여신 한도가 없어 confirm_booking이 거부합니다. 호출이 AUTH_INSUFFICIENT_ROLE(HTTP 403)을 반환하면 token은 유효하고 역할이 잘못된 것이므로, guest_login token을 다시 요청하지 말고 login으로 전환하세요.
도구 분류
| 공개 (인증 없음) | 인증됨 (Bearer token) |
|---|---|
| search_location, hotel_search, get_search_results, get_hotel_rooms, get_hotel_details, check_cancellation_policy, login, guest_login | prepare_booking, confirm_booking, create_checkout, get_payment_url, list_bookings, get_booking_details, cancel_booking |
기본 URL 및 트랜스포트
모든 엔드포인트는 https://locktrip.com/mcp/에서 제공됩니다. 3가지 트랜스포트 모드가 지원됩니다:
| 트랜스포트 | 메서드 | 엔드포인트 |
|---|---|---|
| REST | POST | https://locktrip.com/mcp/tools/{tool_name} |
| MCP Streamable HTTP | POST | https://locktrip.com/mcp/rpc |
| MCP Streamable HTTP (alias) | POST | https://locktrip.com/mcp/sse |
디스커버리 엔드포인트
| URL | 설명 |
|---|---|
| GET /mcp/openapi.json | OpenAPI 3.1 사양 |
| GET /mcp/tools | 스키마가 포함된 모든 도구 목록 |
| GET /mcp/discovery | MCP 디스커버리 문서 |
모든 POST 요청에 Content-Type: application/json을 사용하세요.
오류 처리
REST 오류
| 상태 | 의미 |
|---|---|
| 200 | 성공 |
| 400 | 유효성 검사 오류 (잘못된 입력) |
| 401 | Bearer token이 없거나 유효하지 않음 |
| 403 | 인증되었지만 이 세션에는 필요한 역할이 없습니다. guest_login이 아니라 login을 사용하세요 |
| 404 | 알 수 없는 도구 이름 |
| 429 | 요율 제한 초과 |
The error envelope — read recoverable, not the message
Every classified error carries the same envelope. mcpCode is the stable machine-readable class — branch on it, never on the message text. recoverable is behavioural guidance and the field an autonomous agent should act on: true means the caller can fix the request and retry (bad input, expired search session, rate limit); false means retrying the same call is futile — change something first. A recoverable: false with AUTH_INSUFFICIENT_ROLE specifically means your token is valid but its role is wrong: switch to login, and do NOT fetch another guest_login token.
// REST — the HTTP status carries the class, and the body repeats it
HTTP 403
{
"error": {
"code": -32009,
"message": "This tool requires a registered account. ...",
"data": { "mcpCode": "AUTH_INSUFFICIENT_ROLE", "recoverable": false, "details": { ... } }
}
}Transports differ, deliberately. On /mcp/tools/* (REST) a failure returns a real HTTP status — 400, 401, 403, 404, 409, 429, 500, 502. On /mcp/rpc and /mcp/sse a failure returns HTTP 200 with the error inside the JSON-RPC body, as the JSON-RPC spec requires. If you put a circuit breaker or retry policy on HTTP status alone, it will see the RPC transport as permanently healthy — branch on data.mcpCode and data.recoverable instead.
JSON-RPC 오류
{
"jsonrpc": "2.0",
"id": 1,
"error": {
"code": -32001,
"message": "Authentication required for this tool.",
"data": {
"loginUrl": "https://users.locktrip.com/api/auth/login",
"signupTool": "guest_login"
}
}
}| 코드 | 의미 |
|---|---|
| -32700 | 잘못된 JSON — 요청 본문을 구문 분석할 수 없습니다 |
| -32600 | 유효하지 않은 JSON-RPC 요청 |
| -32601 | 알 수 없는 도구 / 메서드를 찾을 수 없음 |
| -32001 | 인증이 필요하거나 토큰이 유효하지 않음 |
| -32009 | 인증되었지만 이 세션에는 필요한 역할이 없습니다. guest_login이 아니라 login을 사용하세요 |
| -32007 | 요율 제한 초과 |
| -32603 | 내부 서버 오류 |
요율 제한
IP 기반(익명) 또는 사용자 ID 기반(인증됨) 슬라이딩 윈도우 요율 제한. 제한 초과 시 HTTP 429 또는 JSON-RPC 오류 코드 -32007이 반환됩니다.
| 도구 | 익명 | 인증됨 |
|---|---|---|
| hotel_search | 5/ 분 | 20/ 분 |
| 기타 모든 도구 | 30/ 분 | 120/ 분 |
도구 레퍼런스
권장 워크플로우 순서로 나열된 15개 도구.
search_location
공개위치(도시, 지역, 호텔)를 검색하여 호텔 검색용 ID를 가져옵니다. 유형과 전체 이름이 포함된 일치하는 위치를 반환합니다.
요청
| 필드 | 유형 | 필수 | 설명 |
|---|---|---|---|
| query | string | Yes | Search query (city name, region, or hotel name) |
| language | string | No | Language code (default: "en") |
응답
| 필드 | 유형 | 설명 | |
|---|---|---|---|
| locations | Location[] | Array of matching locations | |
| locations[].id | string | Location ID (use as regionId in hotel_search) | |
| locations[].name | string | Location name | |
| locations[].type | string | Location type (e.g., "CITY") | |
| locations[].fullName | string | Full location name with country | |
| locations[].country | string | Country name | |
| totalCount | number | Total number of matches returned |
예시
curl -X POST https://locktrip.com/mcp/tools/search_location \
-H "Content-Type: application/json" \
-d '{"query": "Paris"}'
# Response (200 OK):
{
"locations": [
{
"id": "5f078e431fd614748f9037f9",
"name": "Paris, France",
"country": "",
"type": "CITY",
"fullName": "Paris, France"
},
{
"id": "5f080b92b8f3040a9045c3e8",
"name": "Disneyland Paris, Boulevard de Parc, Coupvray, France",
"country": "",
"type": "CITY",
"fullName": "Disneyland Paris, Boulevard de Parc, Coupvray, France"
}
],
"totalCount": 10
}hotel_search
공개호텔 검색을 시작합니다. search_location의 regionId 또는 위도/경도 좌표를 제공합니다. get_search_results로 폴링하기 위한 searchKey를 반환합니다. 검색은 비동기적으로 실행됩니다.
요청
| 필드 | 유형 | 필수 | 설명 |
|---|---|---|---|
| regionId | string | No | Location ID from search_location. Required unless lat/lng provided. |
| startDate | string | Yes | Check-in date (YYYY-MM-DD). MUST be in the future — a past date is rejected with "Check-in date cannot be in the past". The dates in the examples are illustrative; substitute your own future window. |
| endDate | string | Yes | Check-out date (YYYY-MM-DD) |
| currency | string | No | Currency code (default: "USD") |
| rooms | Room[] | Yes | Room configurations |
| rooms[].adults | number | Yes | Number of adults (1-4) |
| rooms[].childrenAges | number[] | No | Ages of children (0-17) |
| nationality | string | Yes | 2-letter country code (e.g., US, GB) |
| latitude | number | No | Latitude (-90 to 90). Use with longitude instead of regionId. |
| longitude | number | No | Longitude (-180 to 180). Use with latitude instead of regionId. |
| radiusInMeters | number | No | Search radius in meters (default: 30000, max: 100000). Only with lat/lng. |
응답
| 필드 | 유형 | 설명 | |
|---|---|---|---|
| searchKey | string | Key to poll results with get_search_results | |
| sessionId | string | Internal session identifier | |
| status | string | Search status (e.g., "IN_PROGRESS") |
예시
curl -X POST https://locktrip.com/mcp/tools/hotel_search \
-H "Content-Type: application/json" \
-d '{
"regionId": "5f078e431fd614748f9037f9",
"startDate": "2027-04-15",
"endDate": "2027-04-17",
"currency": "EUR",
"rooms": [{"adults": 2}],
"nationality": "US"
}'
# Response (200 OK):
{
"searchKey": "47de06e3262ea3822bdc384a04470783",
"sessionId": "/280/137970/D20260228T093158/4fcf789dd1294b4194cdb2c263bdf264",
"status": "IN_PROGRESS"
}get_search_results
공개페이지별 호텔 검색 결과를 가져옵니다. searchStatus가 "COMPLETED"가 될 때까지 폴링합니다. 가격, 별점, 편의시설, 식사 유형별 필터링을 지원합니다. 가격, 평점, 거리별 정렬이 가능합니다.
가격 인텔리전스
각 호텔 결과에는 discountScore가 포함됩니다. 이는 다른 여행 웹사이트와 비교하여 얼마나 저렴한지 계산하는 LockTrip의 독자적인 머신러닝 점수입니다. V8 ML 모델은 여러 호텔 공급업체의 실시간 가격 데이터를 분석하여 절약액을 예측합니다. minPrice(LockTrip 가격)와 originalPrice(경쟁 사이트의 마지막 최저가)를 discountScore와 함께 사용하여 사용자에게 최고의 할인 정보를 제공하세요.
요청
| 필드 | 유형 | 필수 | 설명 |
|---|---|---|---|
| searchKey | string | Yes | Search key from hotel_search |
| page | number | No | Page number, 0-indexed (default: 0) |
| size | number | No | Results per page (default: 100, max: 5000) |
| currency | string | No | Currency code from hotel_search |
| sortBy | string | No | PRICE_ASC, PRICE_DESC, RATING_DESC, or DISTANCE |
| filters | object | No | Optional filters (see below) |
| filters.minPrice | number | No | Minimum price |
| filters.maxPrice | number | No | Maximum price |
| filters.starRatings | number[] | No | Star ratings to include (1-5) |
| filters.amenities | string[] | No | Required amenities |
| filters.mealTypes | string[] | No | Required meal types |
| filters.hotelName | string | No | Hotel name search |
응답
| 필드 | 유형 | 설명 | |
|---|---|---|---|
| hotels | Hotel[] | Array of matching hotels | |
| hotels[].hotelId | string | Hotel ID (use in get_hotel_rooms, get_hotel_details) | |
| hotels[].name | string | Hotel name | |
| hotels[].starRating | number | Star rating (1-5) | |
| hotels[].address | string | Street address | |
| hotels[].latitude | number | Latitude coordinate | |
| hotels[].longitude | number | Longitude coordinate | |
| hotels[].images | string[] | Hotel image URLs | |
| hotels[].amenities | string[] | Available amenities | |
| hotels[].minPrice | number | LockTrip's price for this hotel (lowest available rate) | |
| hotels[].originalPrice | number | Last best price found on competing travel websites (e.g. Booking.com, Expedia). When equal to minPrice, no discount was detected. | |
| hotels[].currency | string | Price currency code | |
| hotels[].discountScore | number | LockTrip's proprietary machine learning score indicating how much cheaper this offer is compared to other travel websites. Powered by a V8 ML model that analyzes real-time pricing data from multiple hotel suppliers. Higher = bigger savings. 0 means no significant discount was detected. RELATIVE, WITH NO FIXED UPPER BOUND — the model output is not clamped. Across millions of live results we observed a range of roughly 0 to 60, with about one result in ten above 10. Rank and compare results against each other; do NOT normalise against a constant maximum. | |
| hotels[].quality | number | Internal ranking scalar (the default sort key) derived from discountScore, distance and review score. RELATIVE, WITH NO FIXED UPPER BOUND and no absolute meaning — over the same data we observed roughly 0 to 23, with under a third above 1. 0 means the hotel has no discount score or no qualifying reviews. Use it to order results; do not display it as a rating or normalise it against a constant. | |
| hotels[].reviewScore | number | Guest review score (0-10). This is the one to show a user. | |
| hotels[].reviewCount | number|null | Number of guest reviews | |
| hotels[].hasFreeCancellation | boolean | Whether any room has free cancellation | |
| hotels[].isRefundable | boolean | Whether any room is refundable | |
| hotels[].refundableUntil | string|null | ISO date until which free cancellation is available | |
| hotels[].payment | string | Payment type (e.g., "Cash") | |
| hotels[].distance | number | Distance from search center (km) | |
| hotels[].boardType | string|null | Default board type | |
| hotels[].availableMealTypes | string[] | Available meal types | |
| totalCount | number | Total hotels matching search | |
| page | number | Current page number, 0-indexed — the SAME indexing as the request. Request page 0 and this echoes 0. To walk pages, request page + 1. | |
| pageSize | number | Results per page | |
| hasMore | boolean | Whether more pages are available | |
| searchStatus | string | "IN_PROGRESS" or "COMPLETED" |
예시
curl -X POST https://locktrip.com/mcp/tools/get_search_results \
-H "Content-Type: application/json" \
-d '{
"searchKey": "47de06e3262ea3822bdc384a04470783",
"page": 0,
"size": 2
}'
# Response (200 OK):
{
"hotels": [
{
"hotelId": "4703420",
"name": "Premiere Classe Boissy Saint Leger",
"starRating": 1,
"address": "P.A De La Haie Griselle 4 Rue Pompadour, Boissy-Saint-Leger",
"latitude": 48.759967,
"longitude": 2.501443,
"images": [
"https://imagecontent.net/images/full/5a0d94a0-5f7e-4e4e-b457-5e0673a96a95.jpeg"
],
"amenities": ["Family rooms", "Free Wifi", "Parking", "Air conditioning"],
"minPrice": 71.51,
"originalPrice": 71.51,
"currency": "EUR",
"discountScore": 0,
"quality": 0.19,
"reviewScore": 2.5,
"reviewCount": null,
"hasFreeCancellation": false,
"isRefundable": false,
"refundableUntil": null,
"payment": "Cash",
"distance": 15.32,
"boardType": null,
"availableMealTypes": []
}
],
"totalCount": 2403,
"page": 0,
"pageSize": 2,
"hasMore": true,
"searchStatus": "COMPLETED"
}get_hotel_rooms
공개특정 호텔의 이용 가능한 객실 패키지를 가져옵니다. 예약에 필요한 quoteIds를 반환합니다. 각 패키지에는 가격, 식사 유형, 편의시설, 취소 정보가 포함됩니다.
요청
| 필드 | 유형 | 필수 | 설명 |
|---|---|---|---|
| hotelId | string | Yes | Hotel ID from search results |
| searchKey | string | Yes | Search key from hotel_search |
| startDate | string | Yes | Check-in date (YYYY-MM-DD). MUST be in the future — a past date is rejected with "Check-in date cannot be in the past". The dates in the examples are illustrative; substitute your own future window. |
| endDate | string | Yes | Check-out date (YYYY-MM-DD) |
| rooms | Room[] | Yes | Room occupancy (same as hotel_search) |
| nationality | string | Yes | 2-letter country code |
| regionId | string | Yes | Region ID from search_location |
| currency | string | No | Currency code (default: "USD") |
응답
| 필드 | 유형 | 설명 | |
|---|---|---|---|
| hotelId | string | Hotel ID | |
| hotelName | string | Hotel name | |
| checkIn | string | Check-in date (YYYY-MM-DD) | |
| checkOut | string | Check-out date (YYYY-MM-DD) | |
| packages | Package[] | Available room packages | |
| packages[].quoteId | string | Quote ID (use in prepare_booking) | |
| packages[].packageId | string | Package identifier | |
| packages[].roomName | string | Room type name (e.g., "Standard, 3 Beds") | |
| packages[].roomDescription | string | HTML description of room features | |
| packages[].mealType | string | "Room Only", "Breakfast Included", etc. | |
| packages[].mealDescription | string | Meal plan description | |
| packages[].maxOccupancy | number | Maximum guests per room | |
| packages[].amenities | string[] | Room amenities list | |
| packages[].price | number | Total price for all nights | |
| packages[].currency | string | Price currency | |
| packages[].pricePerNight | number | Price per night | |
| packages[].totalNights | number | Number of nights | |
| packages[].isRefundable | boolean | Whether room is refundable |
예시
curl -X POST https://locktrip.com/mcp/tools/get_hotel_rooms \
-H "Content-Type: application/json" \
-d '{"hotelId":"4384127","searchKey":"47de06e3262ea3822bdc384a04470783","startDate":"2027-04-15","endDate":"2027-04-17","rooms":[{"adults":2}],"nationality":"US","regionId":"5f078e431fd614748f9037f9","currency":"EUR"}'
# Response (200 OK):
{
"hotelId": "4384127",
"hotelName": "",
"checkIn": "2027-04-15",
"checkOut": "2027-04-17",
"packages": [
{
"quoteId": "3e242771-1c15-4356-9a3b-1cd4bfc6d9fc_4384127",
"packageId": "3e242771-1c15-4356-9a3b-1cd4bfc6d9fc_4384127",
"roomName": "Standard, 3 Beds",
"mealType": "Room Only",
"price": 71.34,
"currency": "EUR",
"pricePerNight": 35.67,
"totalNights": 2,
"isRefundable": false
}
]
}get_hotel_details
공개설명, 편의시설, 리뷰, 사진, 위치를 포함한 호텔의 상세 정보를 가져옵니다. 예약 전에 호텔의 전체 정보를 얻기 위해 검색 후 사용합니다.
요청
| 필드 | 유형 | 필수 | 설명 |
|---|---|---|---|
| hotelId | number | Yes | Hotel ID (numeric, from search results) |
| language | string | No | Language code (default: "en") |
| includeImages | boolean | No | Fetch additional images (default: false) |
| imageLimit | number | No | Max additional images (default: 20, max: 100) |
응답
| 필드 | 유형 | 설명 | |
|---|---|---|---|
| hotel | object | Hotel details object | |
| hotel.id | number | Hotel ID | |
| hotel.name | string | Hotel name | |
| hotel.country | string | Country | |
| hotel.city | string | City | |
| hotel.star | number | Star rating (1-5) | |
| hotel.address | string | Street address | |
| hotel.latitude | number | Latitude | |
| hotel.longitude | number | Longitude | |
| hotel.description | string | HTML description with sections | |
| hotel.phone | string|null | Phone number | |
| hotel.hotelPhotos | Photo[] | Photo URLs (relative paths) | |
| hotel.reviews | object | Review summary with score, count, keywords | |
| hotel.hotelAmenities | Category[] | Amenities grouped by category | |
| additionalImages | Photo[] | Extra images (if includeImages=true) |
예시
curl -X POST https://locktrip.com/mcp/tools/get_hotel_details \
-H "Content-Type: application/json" \
-d '{"hotelId": 4384127}'
# Response (200 OK):
{
"hotel": {
"id": 4384127,
"name": "Premiere Classe Plaisir",
"country": "France",
"city": "Plaisir",
"star": 1,
"address": "Za De Sainte Apolline Rue Des Poiriers",
"description": "<h2>Hotel Details</h2><p>Property Location...</p>",
"hotelPhotos": [{"url": "/gmx/full/d174a039-ebf9-4e42-8b42-5e31a6950b0e.jpeg"}],
"reviews": {"scoreSummary": 0, "reviewsCount": 0, "keyWords": []},
"hotelAmenities": [{"categoryName": "Hotel Facilities & Services", "features": [{"name": "Free Wifi"}]}]
}
}check_cancellation_policy
공개객실 패키지의 상세 취소 정책을 가져옵니다. 무료 취소 기한과 날짜 범위별 위약금을 표시합니다.
요청
| 필드 | 유형 | 필수 | 설명 |
|---|---|---|---|
| searchKey | string | Yes | Search key from hotel_search |
| hotelId | string | Yes | Hotel ID |
| packageIds | string[] | Yes | Package UUIDs, WITHOUT the _hotelId suffix — take the quoteId from get_hotel_rooms and truncate it: quoteId.split('_')[0]. Passing the full quoteId here fails with a misleading SESSION_EXPIRED even on a live session, because the policy lookup matches the bare UUID. |
응답
| 필드 | 유형 | 설명 | |
|---|---|---|---|
| hotelId | string | Hotel ID | |
| policies | Policy[] | Cancellation policy per package | |
| policies[].packageId | string | Package identifier | |
| policies[].isRefundable | boolean | Whether package is refundable | |
| policies[].freeCancellationUntil | string|null | Last date for free cancellation (YYYY-MM-DD) | |
| policies[].fees | Fee[] | Cancellation penalty fees | |
| policies[].fees[].fromDate | string | Penalty period start (YYYY-MM-DD) | |
| policies[].fees[].toDate | string|null | Penalty period end | |
| policies[].fees[].amount | number | Penalty amount | |
| policies[].fees[].currency | string|absent | The supplier's own currency for this penalty. OMITTED, never guessed, when the supplier states none — treat an absent currency as unpriced rather than assuming your search currency. (Before 2026-08 this field was hardcoded to USD and was wrong for every non-USD search.) | |
| policies[].fees[].percentage | number|null | Percentage of booking price | |
| policies[].remarks | string[]|null | Additional policy notes |
예시
curl -X POST https://locktrip.com/mcp/tools/check_cancellation_policy \
-H "Content-Type: application/json" \
-d '{"searchKey":"47de06e3262ea3822bdc384a04470783","hotelId":"4384127","packageIds":["e3fca710-0a05-4b96-a472-a93c941a58fc"]}'
# NOTE the packageId has NO _4384127 suffix. Passing the full quoteId here returns
# 409 SESSION_EXPIRED even on a live session.
# Response (200 OK):
{
"hotelId": "4384127",
"policies": [{
"packageId": "e3fca710-0a05-4b96-a472-a93c941a58fc_4384127",
"isRefundable": true,
"freeCancellationUntil": "2027-04-13",
"fees": [{"fromDate":"2027-04-13","toDate":"2027-04-15","amount":77.53,"currency":"EUR","percentage":100}],
"remarks": ["Room: Standard, 3 Beds", "Board: Room Only"]
}]
}guest_login
공개이메일 주소만으로 게스트로 등록 또는 로그인합니다. 인증된 도구용 Bearer token을 반환합니다. 이미 존재하는 계정을 포함해 호출할 때마다 해당 주소로 확인 이메일이 발송됩니다. token은 한 번만 발급받아 재사용하세요. 생성되는 것은 게스트 세션입니다.
요청
| 필드 | 유형 | 필수 | 설명 |
|---|---|---|---|
| string | Yes | User email address |
응답
| 필드 | 유형 | 설명 | |
|---|---|---|---|
| token | string | JWT Bearer token for authenticated API calls | |
| userId | number | Numeric user ID | |
| string | User email address | ||
| isNewUser | boolean | Whether a new account was created |
예시
curl -X POST https://locktrip.com/mcp/tools/guest_login \
-H "Content-Type: application/json" \
-d '{"email": "[email protected]"}'
# Response (200 OK):
{"token":"eyJhbGciOiJIUzUxMiJ9...","userId":413900,"email":"[email protected]","isNewUser":true}login
공개이메일과 비밀번호로 로그인하여 Bearer token을 받습니다. 계정이 확인된 등록 사용자용입니다.
요청
| 필드 | 유형 | 필수 | 설명 |
|---|---|---|---|
| string | Yes | User email address | |
| password | string | Yes | User password |
응답
| 필드 | 유형 | 설명 | |
|---|---|---|---|
| token | string | JWT Bearer token for authenticated API calls | |
| userId | number | Numeric user ID | |
| string | User email address |
예시
curl -X POST https://locktrip.com/mcp/tools/login \
-H "Content-Type: application/json" \
-d '{"email":"[email protected]","password":"yourpassword"}'
# Response (200 OK):
{"token":"eyJhbGciOiJIUzUxMiJ9...","userId":12345,"email":"[email protected]"}prepare_booking
인증 필요게스트 정보로 예약을 생성합니다. 확인용 preparedBookingId를 반환합니다. 준비된 예약에는 고정된 만료 시간이 없습니다. 만료되는 것은 quoteId 뒤의 검색 세션입니다. 객실당 게스트 수는 검색 시의 성인 수와 일치해야 합니다.
요청
| 필드 | 유형 | 필수 | 설명 |
|---|---|---|---|
| quoteId | string | Yes | Quote ID from get_hotel_rooms |
| searchKey | string | Yes | Search key from hotel_search — the SAME one used for get_hotel_rooms. REQUIRED: omitting it returns 400 VALIDATION_ERROR naming searchKey as the failing path. It warms the cancellation-policy cache the backend needs in order to book. |
| rooms | Room[] | Yes | Guest assignments per room |
| rooms[].roomIndex | number | Yes | Room index (0-based) |
| rooms[].guests | Guest[] | Yes | Adult guests in this room |
| rooms[].guests[].firstName | string | Yes | First name |
| rooms[].guests[].lastName | string | Yes | Last name |
| rooms[].guests[].title | string | No | "Mr", "Mrs", or "Ms" (default: "Mr") |
| rooms[].guests[].email | string | No | Email address |
| rooms[].guests[].phone | string | No | Phone number |
| rooms[].guests[].isLeadGuest | boolean | No | Whether this is the lead guest |
| rooms[].children | Child[] | No | Children in this room |
| rooms[].children[].firstName | string | Yes | First name |
| rooms[].children[].lastName | string | Yes | Last name |
| rooms[].children[].age | number | Yes | Child age (0-17) |
| contactPerson | object | Yes | Contact person details |
| contactPerson.firstName | string | Yes | First name |
| contactPerson.lastName | string | Yes | Last name |
| contactPerson.email | string | Yes | Email address |
| contactPerson.phone | string | Yes | Phone number (min 5 chars) |
| contactPerson.title | string | No | "Mr", "Mrs", or "Ms" |
| contactPerson.countryCode | string | No | 2-letter country code |
| specialRequests | string | No | Special requests for the hotel |
응답
| 필드 | 유형 | 설명 | |
|---|---|---|---|
| preparedBookingId | string | Booking ID for confirm_booking | |
| bookingInternalId | string | Internal booking identifier | |
| price | number | Total price | |
| currency | string | Price currency | |
| payment | string | Payment type (e.g., "Cash") | |
| discount | object | Discount details (amount, currency) | |
| taxes | Tax[] | Itemized taxes and fees | |
| essentialInformation | string[] | Check-in instructions, mandatory fees, policies |
예시
curl -X POST https://locktrip.com/mcp/tools/prepare_booking \
-H "Content-Type: application/json" \
-H "Authorization: Bearer eyJhbGciOiJIUzUxMiJ9..." \
-d '{"quoteId":"3e242771-1c15-4356-9a3b-1cd4bfc6d9fc_4384127","searchKey":"47de06e3262ea3822bdc384a04470783","rooms":[{"roomIndex":0,"guests":[{"firstName":"John","lastName":"Smith","title":"Mr","email":"[email protected]","phone":"+1234567890","isLeadGuest":true}]}],"contactPerson":{"firstName":"John","lastName":"Smith","email":"[email protected]","phone":"+1234567890"}}'
# Response (200 OK):
{"preparedBookingId":"69a2b7540a93415a4b4dbf13","price":71.34,"currency":"EUR","payment":"Cash","discount":{"amount":0,"currency":"EUR"},"taxes":[{"feeTitle":"Taxes and Fees","value":"1.59","currency":"EUR","isIncludedInPrice":true}],"essentialInformation":["CheckIn instructions: ..."]}confirm_booking
인증 필요B2B 크레딧 라인을 사용하여 준비된 예약을 확인하고 결제합니다. 바우처 URL이 포함된 예약 확인을 반환합니다. 소비자 결제에는 create_checkout 또는 get_payment_url을 사용하세요.
요청
| 필드 | 유형 | 필수 | 설명 |
|---|---|---|---|
| bookingInternalId | string | Yes | Booking ID from prepare_booking (preparedBookingId) |
| quoteId | string | Yes | Quote ID used in prepare_booking |
| paymentMethod | string | No | Payment method (default: "CREDIT_LINE" for B2B) |
응답
| 필드 | 유형 | 설명 | |
|---|---|---|---|
| accepted | boolean | Whether booking confirmation was accepted | |
| message | string|null | Confirmation status message | |
| voucherUrl | string|null | URL to booking voucher (if accepted) | |
| serviceUnavailable | boolean|absent | Present, and always true, ONLY when our credit service did not answer. Otherwise the key is OMITTED - test for PRESENCE, never for false (=== false never matches). Its absence is meaningful: the service answered, so accepted:false is a real refusal. See the warning below. |
예시
curl -X POST https://locktrip.com/mcp/tools/confirm_booking \
-H "Content-Type: application/json" \
-H "Authorization: Bearer eyJhbGciOiJIUzUxMiJ9..." \
-d '{"bookingInternalId":"69a2b7540a93415a4b4dbf13","quoteId":"3e242771-1c15-4356-9a3b-1cd4bfc6d9fc_4384127"}'
# Response (200 OK):
{"accepted":true,"message":"Booking confirmed successfully","voucherUrl":"https://locktrip.com/booking/hotel/voucher/69a2b7540a93415a4b4dbf13"}A credit-line refusal is not an error. If your line has insufficient balance, this tool returns HTTP 200 with accepted: false and the reason in message — it does not raise an error code. Branch on accepted, not on the HTTP status.
Treat serviceUnavailable: true differently from a refusal. It means our credit service did not answer, so we cannot tell you whether the reservation was applied. It may already be held against your line. Do not blindly retry — the reserve call is not idempotent and a retry can reserve the amount twice. Re-check the booking with get_booking_details before any second attempt.
create_checkout
인증 필요준비된 예약을 위한 Revolut 결제 체크아웃 URL을 생성합니다. 사용자가 클릭하여 결제할 수 있는 호스팅 체크아웃 링크를 반환합니다. 결제 완료 후, webhook을 통해 예약이 자동으로 확인됩니다. B2C 소비자용으로 사용하세요.
요청
| 필드 | 유형 | 필수 | 설명 |
|---|---|---|---|
| bookingId | string | Yes | Booking ID from prepare_booking (preparedBookingId) |
| currency | string | Yes | 3-letter currency code (e.g., USD, EUR, GBP) |
| backUrl | string | No | Cancel/back redirect URL (defaults to locktrip.com) |
| successUrl | string | No | Success redirect URL |
응답
| 필드 | 유형 | 설명 | |
|---|---|---|---|
| checkoutUrl | string | Revolut hosted checkout URL for payment | |
| checkoutToken | string | Payment token for tracking | |
| expiresInMinutes | number | Token expiration time (20 minutes) | |
| message | string | User instruction message |
예시
curl -X POST https://locktrip.com/mcp/tools/create_checkout \
-H "Content-Type: application/json" \
-H "Authorization: Bearer eyJhbGciOiJIUzUxMiJ9..." \
-d '{"bookingId":"69a2b7540a93415a4b4dbf13","currency":"EUR"}'
# Response (200 OK):
{"checkoutUrl":"https://checkout.revolut.com/pay/abc123...","checkoutToken":"rev_tok_abc123...","expiresInMinutes":20,"message":"Payment checkout link created. Share this URL with the user to complete payment."}get_payment_url
인증 필요준비된 예약의 결제를 위한 Stripe 체크아웃 URL을 가져옵니다. 신용카드 결제를 완료하기 위해 고객을 리디렉션할 URL을 반환합니다.
요청
| 필드 | 유형 | 필수 | 설명 |
|---|---|---|---|
| bookingId | string | Yes | Booking ID from prepare_booking (preparedBookingId) |
| currency | string | Yes | Payment currency code (e.g., USD, EUR) |
| backUrl | string | Yes | URL to redirect on cancel/back |
| successUrl | string | No | Custom URL to redirect on success |
응답
| 필드 | 유형 | 설명 | |
|---|---|---|---|
| url | string | Stripe checkout URL to redirect customer to | |
| sessionId | string | Stripe session ID for tracking |
예시
curl -X POST https://locktrip.com/mcp/tools/get_payment_url \
-H "Content-Type: application/json" \
-H "Authorization: Bearer eyJhbGciOiJIUzUxMiJ9..." \
-d '{"bookingId":"69a2b7540a93415a4b4dbf13","currency":"EUR","backUrl":"https://example.com/cancel"}'
# Response (200 OK):
{"url":"https://checkout.stripe.com/c/pay/cs_live_abc123...","sessionId":"cs_live_abc123..."}list_bookings
인증 필요인증된 사용자의 예약 목록을 가져옵니다. 상태별 필터링: UPCOMING, COMPLETED, CANCELLED 또는 PENDING.
요청
| 필드 | 유형 | 필수 | 설명 |
|---|---|---|---|
| type | string | No | "UPCOMING", "COMPLETED", "CANCELLED", or "PENDING" (default: "UPCOMING") |
| page | ignored | No | NOT SUPPORTED — accepted by the transport but silently discarded; this tool does not paginate. |
| size | ignored | No | NOT SUPPORTED — silently discarded. list_bookings returns the whole filtered set in one response. |
응답
| 필드 | 유형 | 설명 | |
|---|---|---|---|
| bookings | BookingSummary[] | Array of booking summaries | |
| bookings[].bookingId | string | Booking identifier | |
| bookings[].bookingReferenceId | string | Provider reference ID | |
| bookings[].hotelName | string | Hotel name | |
| bookings[].hotelCity | string | ALWAYS an empty string — the upstream list record carries no city. Use get_booking_details for the hotel’s city. | |
| bookings[].checkIn | string | Check-in date (YYYY-MM-DD) | |
| bookings[].checkOut | string | Check-out date (YYYY-MM-DD) | |
| bookings[].status | string | Booking status (DONE, PENDING, CANCELLED) | |
| bookings[].totalPrice | absent | NOT RETURNED. The upstream booking-list record carries no price, so this field is omitted rather than filled with a placeholder. Call get_booking_details for the real amount. | |
| bookings[].currency | absent | NOT RETURNED, for the same reason. Call get_booking_details, which returns both totalPrice and currency. | |
| bookings[].guestName | string | ALWAYS the literal "Guest" — the upstream list record carries no guest name. Use get_booking_details for the real guests. | |
| bookings[].roomCount | number | Number of rooms | |
| bookings[].createdAt | string | Booking creation timestamp (ISO 8601) | |
| bookings[].hotelPhoto | string|null | Hotel image URL | |
| totalCount | number | Number of bookings in THIS response. There is no pagination, so this is the full filtered set. | |
| page | number | Always 0 — this tool does not paginate. | |
| pageSize | number | Equal to totalCount; present for shape compatibility only. |
예시
curl -X POST https://locktrip.com/mcp/tools/list_bookings \
-H "Content-Type: application/json" \
-H "Authorization: Bearer eyJhbGciOiJIUzUxMiJ9..." \
-d '{"type": "UPCOMING"}'
# Response (200 OK):
{"bookings":[{"bookingId":"69a2b7540a93415a4b4dbf13","bookingReferenceId":"LT-2026-AB12CD","hotelName":"Premiere Classe Plaisir","hotelCity":"","checkIn":"2027-04-15","checkOut":"2027-04-17","status":"DONE","guestName":"Guest","roomCount":1,"createdAt":"2026-02-28T09:35:00.000Z","hotelPhoto":"https://imagecontent.net/images/full/d174a039.jpeg"}],"totalCount":1,"page":0,"pageSize":1}
# NOTE: this endpoint is a summary index, not a detail view. totalPrice and currency are
# absent, and hotelCity / guestName are not populated by the upstream list record.
# Fetch a bookingId with get_booking_details for price, currency, guests and city.get_booking_details
인증 필요호텔 정보, 게스트, 객실, 결제 상태, 취소 정책을 포함한 특정 예약의 전체 상세 정보를 가져옵니다.
요청
| 필드 | 유형 | 필수 | 설명 |
|---|---|---|---|
| bookingId | string | Yes | Booking ID to retrieve |
응답
| 필드 | 유형 | 설명 | |
|---|---|---|---|
| bookingId | string | Booking identifier | |
| bookingReferenceId | string | Provider reference ID | |
| status | string | Booking status (DONE, PENDING, CANCELLED) | |
| hotel | object | Hotel details | |
| hotel.name | string | Hotel name | |
| hotel.address | string | Street address | |
| hotel.city | string | City | |
| hotel.country | string | Country | |
| hotel.starRating | number | Star rating (1-5) | |
| checkIn | string | Check-in date (YYYY-MM-DD) | |
| checkOut | string | Check-out date (YYYY-MM-DD) | |
| rooms | Room[] | Booked rooms with guests | |
| contactPerson | object | Contact person (firstName, lastName, email, phone) | |
| totalPrice | number | Total booking price | |
| currency | string | Currency code | |
| paymentStatus | string | Payment status (PAID, PENDING) | |
| cancellationPolicy | object|null | Cancellation policy with fees and deadlines | |
| createdAt | string | Booking creation date | |
| confirmedAt | string|null | Confirmation date (null if pending) |
예시
curl -X POST https://locktrip.com/mcp/tools/get_booking_details \
-H "Content-Type: application/json" \
-H "Authorization: Bearer eyJhbGciOiJIUzUxMiJ9..." \
-d '{"bookingId": "69a2b7540a93415a4b4dbf13"}'
# Response (200 OK):
{"bookingId":"69a2b7540a93415a4b4dbf13","bookingReferenceId":"LT-2026-AB12CD","status":"DONE","hotel":{"id":4384127,"name":"Premiere Classe Plaisir","city":"Plaisir","country":"France","starRating":1},"checkIn":"2027-04-15","checkOut":"2027-04-17","totalPrice":71.34,"currency":"EUR","paymentStatus":"PAID","createdAt":"2026-02-28","confirmedAt":"2026-02-28"}cancel_booking
인증 필요예약 취소를 요청합니다. 먼저 confirmed=false로 취소 수수료를 미리 확인한 다음, confirmed=true로 실행합니다. 환불 금액과 취소 수수료를 반환합니다.
요청
| 필드 | 유형 | 필수 | 설명 |
|---|---|---|---|
| bookingId | string | Yes | Booking ID to cancel |
| confirmed | boolean | Yes | Set true to execute cancellation |
| reason | string | No | Reason for cancellation |
응답
| 필드 | 유형 | 설명 | |
|---|---|---|---|
| success | boolean | Whether cancellation was executed | |
| message | string | Status message (preview or confirmation) |
예시
# Step 1: Preview cancellation (dry run)
curl -X POST https://locktrip.com/mcp/tools/cancel_booking \
-H "Content-Type: application/json" \
-H "Authorization: Bearer eyJhbGciOiJIUzUxMiJ9..." \
-d '{"bookingId":"69a2b7540a93415a4b4dbf13","confirmed":false}'
# Response (200 OK):
{"success":false,"message":"Cancellation not confirmed. Set confirmed=true to proceed."}
# Step 2: Execute cancellation
curl -X POST https://locktrip.com/mcp/tools/cancel_booking \
-H "Content-Type: application/json" \
-H "Authorization: Bearer eyJhbGciOiJIUzUxMiJ9..." \
-d '{"bookingId":"69a2b7540a93415a4b4dbf13","confirmed":true,"reason":"Change of plans"}'
# Response (200 OK):
{"success":true,"message":"Booking cancelled successfully"}기계 판독 가능 사양: OpenAPI 3.1 | Tool List | MCP Discovery | GraphQL B2B Docs
LockTrip Hotel Booking MCP API v1.0.0