{"openapi":"3.1.0","info":{"title":"ONDA Channel API","version":"1.0.0","description":"ONDA 채널 API — OTA, 메타서치, 여행사를 위한 숙소 검색·예약 인터페이스","contact":{"name":"ONDA Developer Support","url":"https://developers.tport.dev","email":"dev-support@onda.me"}},"servers":[{"url":"https://api.tport.dev/channel/v1","description":"Production"},{"url":"https://sandbox.api.tport.dev/channel/v1","description":"Sandbox"}],"security":[{"ApiKeyAuth":[]},{"OAuth2":[]}],"components":{"securitySchemes":{"ApiKeyAuth":{"type":"apiKey","in":"header","name":"X-Api-Key","description":"채널 API 키 (개발자 포털에서 발급). Server-to-Server(S2S) 인증의 기본 방식입니다."},"OAuth2":{"type":"oauth2","description":"Server-to-Business(S2B) OAuth 2.0 client_credentials grant. POST /oauth/token 에서 client_id/client_secret 으로 access_token(oat_...)을 발급받아 Authorization: Bearer 헤더로 전달합니다.","flows":{"clientCredentials":{"tokenUrl":"https://api.tport.dev/channel/v1/oauth/token","scopes":{"properties:read":"숙소/객실/요금제 조회","roomtypes:read":"객실 타입 조회","search:availability":"가용성 및 가격 검색","reservations:read":"예약 조회","reservations:write":"예약 생성/수정/취소","voucher:read":"예약 확인서 조회","channels:read":"채널 정보 조회","channels:write":"채널 정보 수정","tax-invoices:read":"세금계산서 조회"}}}}},"schemas":{"Error":{"type":"object","description":"표준 에러 응답 envelope. request_id 는 error 가 아니라 meta 하위에 있습니다.","properties":{"error":{"type":"object","properties":{"code":{"type":"string","example":"INVALID_REQUEST"},"message":{"type":"string","example":"Required parameter missing."},"details":{"type":"object","nullable":true,"description":"에러별 추가 정보 (선택적)"}},"required":["code","message"]},"meta":{"type":"object","properties":{"request_id":{"type":"string","format":"uuid"},"timestamp":{"type":"string","format":"date-time"}},"required":["request_id","timestamp"]}},"required":["error","meta"]},"OAuthError":{"type":"object","description":"OAuth 2.0 토큰 엔드포인트 전용 에러 형식 ({data,meta} envelope 아님). RFC 6749 형식.","properties":{"error":{"type":"string","example":"invalid_client","enum":["invalid_request","unsupported_grant_type","invalid_client","invalid_scope","rate_limit_exceeded"]},"error_description":{"type":"string"}},"required":["error"]},"OAuthTokenRequest":{"type":"object","required":["grant_type","client_id","client_secret"],"properties":{"grant_type":{"type":"string","enum":["client_credentials"],"description":"client_credentials 만 지원"},"client_id":{"type":"string","description":"앱 클라이언트 ID"},"client_secret":{"type":"string","description":"앱 클라이언트 시크릿"},"scope":{"type":"string","description":"공백 구분 스코프 (앱이 부여받은 스코프의 부분집합). 생략 시 앱의 전체 스코프 발급"}}},"Pagination":{"type":"object","properties":{"total":{"type":"integer"},"page":{"type":"integer"},"per_page":{"type":"integer"},"total_pages":{"type":"integer"},"has_next":{"type":"boolean"}}},"Pricing":{"type":"object","properties":{"request_currency":{"type":"string","example":"KRW"},"billable_currency":{"type":"string","example":"KRW"},"totals":{"type":"object","properties":{"inclusive_amount":{"type":"number","description":"세금 포함 금액"},"exclusive_amount":{"type":"number","description":"세금 제외 금액"}}}}},"CancellationPolicy":{"type":"object","properties":{"type":{"type":"string","enum":["flexible","moderate","strict","non_refundable"]},"free_cancellation_before":{"type":"string","format":"date-time","nullable":true}}},"Booking":{"type":"object","description":"예약 레코드. data envelope 내부에 DB 컬럼이 camelCase 키로 그대로 직렬화됩니다. 금액(totalAmount/netAmount/saleAmount/refundAmount/cancellationFee)은 bigint 컬럼이며 JSON 직렬화 시 문자열로 표현됩니다.","properties":{"id":{"type":"string","format":"uuid"},"userId":{"type":"string","format":"uuid"},"appId":{"type":"string","format":"uuid"},"hubBookingNumber":{"type":"string","nullable":true},"channelBookingNumber":{"type":"string","nullable":true,"description":"파트너 내부 예약 번호"},"propertyId":{"type":"string"},"propertyName":{"type":"string","nullable":true},"roomType":{"type":"string","nullable":true},"ratePlan":{"type":"string","nullable":true},"checkin":{"type":"string","format":"date"},"checkout":{"type":"string","format":"date"},"guestsAdult":{"type":"integer"},"guestsChild":{"type":"integer"},"bookerName":{"type":"string"},"bookerEmail":{"type":"string","format":"email","nullable":true},"guestFirstName":{"type":"string","nullable":true},"guestLastName":{"type":"string","nullable":true},"guestPhone":{"type":"string","nullable":true},"guestCountry":{"type":"string","nullable":true},"specialRequests":{"type":"string","nullable":true},"totalAmount":{"type":"string","description":"환불 기준 금액 (입금가, bigint)"},"netAmount":{"type":"string","description":"입금가 (bigint)"},"saleAmount":{"type":"string","nullable":true,"description":"채널 판매가 (정보용, bigint)"},"currency":{"type":"string","example":"KRW"},"status":{"type":"string","enum":["pending","confirmed","cancelling","cancelled","completed","failed","checked_in","checked_out","no_show"]},"cancellationPolicy":{"type":"string","enum":["flexible","moderate","strict","non_refundable"],"nullable":true},"cancellationDeadline":{"type":"string","format":"date-time","nullable":true},"refundAmount":{"type":"string","nullable":true},"cancellationFee":{"type":"string","nullable":true},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"}}},"TaxInvoice":{"type":"object","properties":{"id":{"type":"string"},"invoice_number":{"type":"string"},"period":{"type":"string","example":"2026-03"},"issue_date":{"type":"string","format":"date"},"supply_amount":{"type":"string","description":"공급가액"},"tax_amount":{"type":"string","description":"세액"},"total_amount":{"type":"string","description":"합계금액"},"currency":{"type":"string"},"status":{"type":"string"},"supplier_name":{"type":"string"},"supplier_biz_number":{"type":"string"},"buyer_name":{"type":"string"},"buyer_biz_number":{"type":"string"},"created_at":{"type":"string","format":"date-time"}}}}},"paths":{"/oauth/token":{"post":{"summary":"OAuth 2.0 액세스 토큰 발급 (S2B)","description":"client_credentials grant 로 access_token 을 발급합니다. application/x-www-form-urlencoded 또는 JSON body 를 모두 허용합니다. 이 엔드포인트는 인증 체인에서 제외되며(클라이언트 자격증명으로 자체 인증), {data,meta} envelope 가 아닌 OAuth 표준 응답을 반환합니다. IP당 20 req/60s rate limit 이 적용됩니다.","operationId":"issueAccessToken","tags":["OAuth"],"security":[],"requestBody":{"required":true,"content":{"application/x-www-form-urlencoded":{"schema":{"$ref":"#/components/schemas/OAuthTokenRequest"}},"application/json":{"schema":{"$ref":"#/components/schemas/OAuthTokenRequest"}}}},"responses":{"200":{"description":"토큰 발급 성공 ({data,meta} envelope 아님, Cache-Control: no-store)","content":{"application/json":{"schema":{"type":"object","required":["access_token","token_type","expires_in","scope"],"properties":{"access_token":{"type":"string","example":"oat_a1b2c3...","description":"불투명 액세스 토큰 (oat_ 접두사)"},"token_type":{"type":"string","example":"bearer"},"expires_in":{"type":"integer","example":1800,"description":"만료까지 남은 초 (30분)"},"scope":{"type":"string","example":"properties:read reservations:write","description":"공백 구분 발급 스코프 목록"}}}}}},"400":{"description":"invalid_request / unsupported_grant_type / invalid_scope","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OAuthError"}}}},"401":{"description":"invalid_client (자격증명 불일치 또는 앱 정지)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OAuthError"}}}},"429":{"description":"rate_limit_exceeded (IP당 20 req/60s 초과)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OAuthError"}}}}}}},"/channels/me":{"get":{"summary":"내 채널 정보 조회","description":"현재 API Key에 연결된 채널(파트너) 정보를 반환합니다. 티어, 수수료율, Rate Limit, 은행 계좌 정보를 포함합니다.","operationId":"getChannel","tags":["Channel"],"responses":{"200":{"description":"채널 정보","content":{"application/json":{"schema":{"type":"object","properties":{"user_id":{"type":"string"},"name":{"type":"string"},"company":{"type":"string","nullable":true},"tier":{"type":"string","enum":["sandbox","starter"]},"commission_rate":{"type":"number","description":"수수료율 (%)"},"rate_limit":{"type":"object","properties":{"sandbox":{"type":"integer","description":"Sandbox 환경 분당 요청 수"},"production":{"type":"integer","description":"Production 환경 분당 요청 수"}}},"bank_account":{"type":"object","nullable":true,"properties":{"bank_name":{"type":"string"},"bank_code":{"type":"string"},"account_number":{"type":"string","description":"마스킹된 계좌번호 (****XXXX)"},"account_holder":{"type":"string"}}},"default_currency":{"type":"string","example":"KRW"},"tier_updated_at":{"type":"string","format":"date-time","nullable":true},"created_at":{"type":"string","format":"date-time"}}}}}},"401":{"description":"인증 실패","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/properties":{"get":{"summary":"숙소 목록 조회","description":"계약된 숙소 목록(Hub passthrough)을 반환합니다. 현재 핸들러는 쿼리 파라미터를 Hub로 전달하지 않으므로 페이지네이션/필터 파라미터를 받지 않습니다.","operationId":"listProperties","tags":["Properties"],"responses":{"200":{"description":"숙소 목록 ({data,meta} envelope, data 는 Hub 숙소 목록)","content":{"application/json":{"schema":{"type":"object"}}}},"401":{"description":"인증 실패","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"502":{"description":"업스트림 오류","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/properties/{id}":{"get":{"summary":"숙소 상세 조회","description":"특정 숙소의 상세 정보를 반환합니다.","operationId":"getProperty","tags":["Properties"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer"},"description":"숙소 ID (정수)"}],"responses":{"200":{"description":"숙소 상세 정보","content":{"application/json":{"schema":{"type":"object"}}}},"401":{"description":"인증 실패","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"숙소 없음","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"502":{"description":"업스트림 오류","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/properties/{id}/roomtypes":{"get":{"summary":"객실 타입 목록 조회","description":"특정 숙소의 객실 타입 목록을 반환합니다.","operationId":"listRoomTypes","tags":["Properties"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer"},"description":"숙소 ID (정수)"}],"responses":{"200":{"description":"객실 타입 목록","content":{"application/json":{"schema":{"type":"object"}}}},"401":{"description":"인증 실패","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"숙소 없음","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"502":{"description":"업스트림 오류","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/properties/{id}/rateplans":{"get":{"summary":"요금제 목록 조회","description":"특정 숙소의 요금제 목록을 반환합니다.","operationId":"listRatePlans","tags":["Properties"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer"},"description":"숙소 ID (정수)"},{"name":"roomtype_id","in":"query","schema":{"type":"string"},"description":"특정 객실 타입으로 필터 (선택)"}],"responses":{"200":{"description":"요금제 목록","content":{"application/json":{"schema":{"type":"object"}}}},"401":{"description":"인증 실패","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"숙소 없음","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"502":{"description":"업스트림 오류","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/search/availability":{"get":{"summary":"가용성 검색 (멀티 숙소)","description":"체크인/아웃 날짜 및 인원 기준으로 여러 숙소의 가용성과 최저가를 반환합니다.","operationId":"searchAvailability","tags":["Search"],"parameters":[{"name":"checkin","in":"query","required":true,"schema":{"type":"string","format":"date"},"description":"체크인 날짜 (YYYY-MM-DD)"},{"name":"checkout","in":"query","required":true,"schema":{"type":"string","format":"date"},"description":"체크아웃 날짜 (YYYY-MM-DD)"},{"name":"adults","in":"query","schema":{"type":"integer","minimum":1},"description":"성인 수 (occupancy와 함께 사용 불가)"},{"name":"occupancy","in":"query","schema":{"type":"array","items":{"type":"string"}},"style":"form","explode":true,"description":"객실별 인원 (adults와 함께 사용 불가)"},{"name":"children","in":"query","schema":{"type":"integer","minimum":0},"description":"소아 수"},{"name":"rooms","in":"query","schema":{"type":"integer","minimum":1},"description":"객실 수"},{"name":"currency","in":"query","schema":{"type":"string","default":"KRW"},"description":"통화 코드 (ISO 4217)"},{"name":"property_id","in":"query","schema":{"type":"string"},"description":"특정 숙소 ID로 필터"},{"name":"city","in":"query","schema":{"type":"string"},"description":"도시 필터"},{"name":"star_rating_min","in":"query","schema":{"type":"number"},"description":"최소 성급 필터"},{"name":"price_min","in":"query","schema":{"type":"number"},"description":"최소 가격 필터 (1박 기준)"},{"name":"price_max","in":"query","schema":{"type":"number"},"description":"최대 가격 필터 (1박 기준)"},{"name":"sort_by","in":"query","schema":{"type":"string","enum":["price_asc","price_desc","star_rating"]},"description":"정렬 기준"},{"name":"page","in":"query","schema":{"type":"integer","default":1}},{"name":"per_page","in":"query","schema":{"type":"integer","default":20,"maximum":100}}],"responses":{"200":{"description":"가용성 검색 결과","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"type":"object"}},"search_context":{"type":"object"},"pagination":{"$ref":"#/components/schemas/Pagination"}}}}}},"400":{"description":"잘못된 요청","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"인증 실패","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/search/availability/{propertyId}":{"get":{"summary":"가용성 검색 (단일 숙소)","description":"특정 숙소의 모든 객실 타입 및 요금제별 가용성을 반환합니다. 각 요금에 price_check_token이 포함됩니다.","operationId":"searchPropertyAvailability","tags":["Search"],"parameters":[{"name":"propertyId","in":"path","required":true,"schema":{"type":"integer"},"description":"숙소 ID"},{"name":"checkin","in":"query","required":true,"schema":{"type":"string","format":"date"}},{"name":"checkout","in":"query","required":true,"schema":{"type":"string","format":"date"}},{"name":"adults","in":"query","required":true,"schema":{"type":"integer","minimum":1}},{"name":"children","in":"query","schema":{"type":"integer","minimum":0}},{"name":"children_ages","in":"query","schema":{"type":"string"},"description":"소아 나이 (쉼표 구분, 예: 5,8)"},{"name":"rooms","in":"query","schema":{"type":"integer","minimum":1}},{"name":"currency","in":"query","schema":{"type":"string","default":"KRW"}},{"name":"roomtype_id","in":"query","schema":{"type":"string"},"description":"price_check_token을 발급할 객실 타입 선택 (선택, rooms[].id)"},{"name":"rateplan_id","in":"query","schema":{"type":"string"},"description":"price_check_token을 발급할 요금제 선택 (선택, rooms[].rates[].rate_plan_id). 미지정 시 첫 요금제 기준"}],"responses":{"200":{"description":"숙소별 가용성 및 price_check_token 포함 요금 목록","content":{"application/json":{"schema":{"type":"object"}}}},"400":{"description":"잘못된 요청","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"인증 실패","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"숙소 없음","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/search/rates":{"get":{"summary":"요금 검색","description":"특정 숙소의 상세 요금 정보를 반환합니다 (2단계 검색).","operationId":"searchRates","tags":["Search"],"parameters":[{"name":"property_id","in":"query","required":true,"schema":{"type":"string"},"description":"숙소 ID"},{"name":"checkin","in":"query","schema":{"type":"string","format":"date"}},{"name":"checkout","in":"query","schema":{"type":"string","format":"date"}},{"name":"adults","in":"query","schema":{"type":"integer","minimum":1}},{"name":"currency","in":"query","schema":{"type":"string","default":"KRW"}}],"responses":{"200":{"description":"요금 검색 결과","content":{"application/json":{"schema":{"type":"object"}}}},"400":{"description":"잘못된 요청","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"인증 실패","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/search/price-check":{"get":{"summary":"가격 확인 및 book_token 발급","description":"price_check_token으로 실시간 가격을 재확인하고 예약에 사용할 book_token을 발급합니다. 가격 변동이 있으면 status가 price_changed로 반환됩니다.","operationId":"priceCheck","tags":["Search"],"parameters":[{"name":"token","in":"query","required":true,"schema":{"type":"string"},"description":"search/availability/{propertyId} 응답의 price_check_token"}],"responses":{"200":{"description":"가격 확인 결과","content":{"application/json":{"schema":{"type":"object","properties":{"status":{"type":"string","enum":["matched","price_changed","sold_out"]},"pricing":{"$ref":"#/components/schemas/Pricing","nullable":true},"cancellation_policy":{"type":"object","nullable":true},"book_token":{"type":"string","nullable":true,"description":"예약 생성에 사용할 토큰"}}}}}},"400":{"description":"잘못된 토큰","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"인증 실패","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"410":{"description":"토큰 만료","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/bookings":{"post":{"summary":"예약 생성","description":"book_token을 사용하여 예약을 생성합니다. 청구 금액은 book_token에 서명된 서버 가격(inclusive_amount)으로 강제되며, 클라이언트가 보낸 금액은 무시됩니다. live 환경에서는 잔액에서 예약 금액이 차감됩니다. body는 flat 구조입니다(중첩 rooms[]/booker 아님).","operationId":"createBooking","tags":["Bookings"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["book_token","booker_name"],"properties":{"book_token":{"type":"string","description":"price-check에서 발급된 단일 사용 book_token (필수)"},"booker_name":{"type":"string","description":"예약자 이름 (필수)"},"booker_email":{"type":"string","format":"email","description":"예약자 이메일"},"guest_first_name":{"type":"string","description":"투숙객 이름"},"guest_last_name":{"type":"string","description":"투숙객 성"},"guest_phone":{"type":"string","description":"투숙객 연락처"},"guest_country":{"type":"string","description":"투숙객 국가 코드"},"guests_adult":{"type":"integer","minimum":1,"description":"성인 수. 생략 시 book_token의 값 사용"},"guests_child":{"type":"integer","minimum":0,"description":"소아 수"},"property_name":{"type":"string","description":"숙소명 (표시용, 선택)"},"room_type":{"type":"string","description":"객실 타입명 (표시용, 선택)"},"rate_plan":{"type":"string","description":"요금제명 (표시용, 선택)"},"special_requests":{"type":"string","description":"특별 요청 사항"},"sale_amount":{"type":"integer","minimum":1,"description":"채널의 고객 노출 판매가 (정보용, 양수 정수). ONDA는 보관/청구/환불하지 않으며 청구액에 영향 없음"},"channel_booking_number":{"type":"string","description":"파트너 내부 예약 번호"}}}}}},"responses":{"201":{"description":"예약 생성 완료","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Booking"}}}},"400":{"description":"유효성 검사 실패","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"인증 실패","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"402":{"description":"잔액 부족","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"book_token 무효","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"502":{"description":"예약 처리 실패 (업스트림)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"get":{"summary":"예약 목록 조회","description":"내 채널의 예약 목록을 반환합니다. 다양한 필터와 페이지네이션을 지원합니다.","operationId":"listBookings","tags":["Bookings"],"parameters":[{"name":"page","in":"query","schema":{"type":"integer","default":1}},{"name":"per_page","in":"query","schema":{"type":"integer","default":20,"maximum":100}},{"name":"status","in":"query","schema":{"type":"string","enum":["confirmed","cancelled","pending"]}},{"name":"checkin_from","in":"query","schema":{"type":"string","format":"date"},"description":"체크인 시작일 필터 (YYYY-MM-DD)"},{"name":"checkin_to","in":"query","schema":{"type":"string","format":"date"},"description":"체크인 종료일 필터 (YYYY-MM-DD)"},{"name":"created_from","in":"query","schema":{"type":"string","format":"date"},"description":"예약 생성일 시작 필터 (YYYY-MM-DD)"},{"name":"created_to","in":"query","schema":{"type":"string","format":"date"},"description":"예약 생성일 종료 필터 (YYYY-MM-DD)"},{"name":"affiliate_reference_id","in":"query","schema":{"type":"string"},"description":"파트너 예약 번호 필터"}],"responses":{"200":{"description":"예약 목록","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Booking"}},"pagination":{"$ref":"#/components/schemas/Pagination"}}}}}},"401":{"description":"인증 실패","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/bookings/{id}":{"get":{"summary":"예약 상세 조회","operationId":"getBooking","tags":["Bookings"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"예약 ID"}],"responses":{"200":{"description":"예약 상세 정보","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Booking"}}}},"401":{"description":"인증 실패","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"예약 없음","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/bookings/{id}/cancellation-fee":{"get":{"summary":"취소 수수료 조회","description":"실제 취소 없이 현재 시점의 취소 수수료를 미리 확인합니다.","operationId":"getBookingCancellationFee","tags":["Bookings"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"예약 ID"}],"responses":{"200":{"description":"취소 수수료 정보","content":{"application/json":{"schema":{"type":"object","properties":{"booking_id":{"type":"string"},"cancellation_fee":{"type":"number","description":"취소 수수료 (원화)"},"refund_amount":{"type":"number","description":"환불 예정 금액"},"currency":{"type":"string"}}}}}},"401":{"description":"인증 실패","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"예약 없음","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/bookings/{id}/cancellation-policy":{"get":{"summary":"취소 정책 조회","operationId":"getBookingCancellationPolicy","tags":["Bookings"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"예약 ID"}],"responses":{"200":{"description":"취소 정책","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CancellationPolicy"}}}},"401":{"description":"인증 실패","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"예약 없음","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/bookings/{id}/cancel":{"put":{"summary":"예약 취소","description":"예약을 취소합니다. 취소 정책에 따라 수수료가 발생할 수 있습니다.","operationId":"cancelBooking","tags":["Bookings"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"예약 ID"}],"responses":{"200":{"description":"취소 완료","content":{"application/json":{"schema":{"type":"object","properties":{"booking_id":{"type":"string"},"status":{"type":"string","example":"cancelled"},"cancellation_fee":{"type":"number"},"refund_amount":{"type":"number"}}}}}},"401":{"description":"인증 실패","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"예약 없음","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"이미 취소된 예약","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/bookings/{id}/voucher":{"get":{"summary":"예약 확인서 조회 (미구현)","description":"⚠️ 현재 미구현 — 항상 501 NOT_IMPLEMENTED 를 반환합니다. 향후 릴리스에서 제공 예정.","operationId":"getBookingVoucher","tags":["Bookings"],"deprecated":true,"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"예약 ID"}],"responses":{"401":{"description":"인증 실패","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"예약 없음","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"501":{"description":"미구현 (NOT_IMPLEMENTED)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/tax-invoices":{"get":{"summary":"세금계산서 목록 조회 (미구현)","description":"⚠️ 현재 미구현 — 항상 501 NOT_IMPLEMENTED 를 반환합니다. 세금계산서 도메인 서비스는 portal-api iter 11 에서 제공 예정. 아래 year/month 파라미터와 TaxInvoice 스키마는 향후 응답 형태(예정)입니다.","operationId":"listTaxInvoices","tags":["Billing"],"deprecated":true,"parameters":[{"name":"year","in":"query","schema":{"type":"integer","example":2026},"description":"조회 연도 (구현 예정)"},{"name":"month","in":"query","schema":{"type":"integer","minimum":1,"maximum":12},"description":"조회 월 (구현 예정)"}],"responses":{"401":{"description":"인증 실패","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"501":{"description":"미구현 (NOT_IMPLEMENTED)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/content/files/catalog":{"get":{"summary":"숙소 카탈로그 파일 다운로드","description":"전체 숙소 카탈로그를 JSON 또는 CSV 형식으로 다운로드합니다.","operationId":"getCatalogFile","tags":["Content"],"parameters":[{"name":"format","in":"query","schema":{"type":"string","enum":["json","csv"],"default":"json"},"description":"다운로드 형식"},{"name":"updated_since","in":"query","schema":{"type":"string","format":"date-time"},"description":"이 시각 이후 변경된 항목만 포함 (ISO 8601)"}],"responses":{"200":{"description":"카탈로그 파일 데이터","content":{"application/json":{"schema":{"type":"object"}}}},"400":{"description":"잘못된 format 값","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"인증 실패","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"502":{"description":"업스트림 오류","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/content/files/content":{"get":{"summary":"숙소 콘텐츠 파일 다운로드","description":"숙소 콘텐츠(이미지, 설명 등) 데이터를 다운로드합니다.","operationId":"getContentFile","tags":["Content"],"parameters":[{"name":"format","in":"query","schema":{"type":"string","enum":["json","csv"],"default":"json"}},{"name":"updated_since","in":"query","schema":{"type":"string","format":"date-time"}}],"responses":{"200":{"description":"콘텐츠 파일 데이터","content":{"application/json":{"schema":{"type":"object"}}}},"400":{"description":"잘못된 format 값","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"인증 실패","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"502":{"description":"업스트림 오류","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}}},"tags":[{"name":"OAuth","description":"OAuth 2.0 client_credentials 토큰 발급 (S2B)"},{"name":"Channel","description":"채널(파트너) 정보 관리"},{"name":"Properties","description":"숙소 및 객실/요금제 조회"},{"name":"Search","description":"가용성 및 요금 검색"},{"name":"Bookings","description":"예약 생성 및 관리"},{"name":"Billing","description":"세금계산서 조회"},{"name":"Content","description":"숙소 콘텐츠 파일 다운로드"}]}