새로운 예약 생성 (V2)
POST/schedule/open/v2/commands/reserve
여러 예약 일정으로 새로운 예약을 생성합니다. (신규 내원객)
- 내원객 정보를 함께 전달하면 자동으로 내원객를 생성하거나 기존 내원객를 찾습니다.
에러 응답
visitorName이 빈 값이거나 공백으로만 이루어져 있을 경우
{
"status": 400,
"message": "InvalidCommandException",
"className": "InvalidCommandException",
"errorProperties": [{"key": "visitorName", "reason": "NotAvailable"}]
}
occupiedResources가 비어있을 경우
{
"status": 400,
"message": "InvalidCommandException",
"className": "InvalidCommandException",
"errorProperties": [{"key": "occupiedResources", "reason": "Required"}]
}
예약 일정의 날짜가 서로 다를 경우
{
"status": 400,
"message": "InvalidCommandException",
"className": "InvalidCommandException",
"errorProperties": [{"key": "occupiedResources[n].startDateTimeUtc", "reason": "NotAvailable"}]
}
zoneId에 해당하는 구역이 없을 경우
{
"status": 400,
"message": "InvalidRequestException",
"className": "InvalidRequestException",
"errorProperties": [{"key": "zoneId", "reason": "NotFound"}]
}
예약 일정의 구역(zoneId)이 예약 그룹에 속하지 않을 경우
{
"status": 400,
"message": "InvalidRequestException",
"className": "InvalidRequestException",
"errorProperties": [{"key": "occupiedResources[n].zoneId", "reason": "NotFound"}]
}
occupiedResources[n]의 예약 일정 설정이 누락된 경우
예약 일정 설정 은 예약을 통해 병원의 어떤 자원을 점유하는지에 대한 설정입니다. 아래 설정들은 서로 배타적인(oneof) 관계이며, 반드시 하나만 설정되어야 합니다.
-
reservationGroup (예약 그룹 기반 리소스 점유 설정)
{
"status": 400,
"message": "InvalidCommandException",
"className": "InvalidCommandException",
"errorProperties": [{"key": "occupiedResources[n].configuration", "reason": "Required"}]
}
동일한 내원객에 대해 시간이 겹치는 예약이 있을 경우
{
"status": 400,
"message": "InvalidRequestException",
"className": "InvalidRequestException",
"errorProperties": [{"key": "startDateTime", "reason": "NotAvailable"}]
}
Request
### Content-Type별 요청의 JSON Schema
{
"application/json": {
"schema": {
"required": [
"visitorName",
"visitorPhone",
"zoneId",
"occupiedResources"
],
"type": "object",
"properties": {
"visitorName": {
"type": "string",
"description": "내원객 이름"
},
"visitorPhone": {
"allOf": [
{
"required": [
"countryCode",
"phoneNumber"
],
"type": "object",
"properties": {
"countryCode": {
"type": "string",
"description": "국제전화 국가 번호n 예: 82, 81, 1, 44 ... [참고](https://ko.wikipedia.org/wiki/%EA%B5%AD%EC%A0%9C%EC%A0%84%ED%99%94_%EA%B5%AD%EA%B0%80_%EB%B2%88%ED%98%B8)"
},
"phoneNumber": {
"type": "string",
"description": "전화번호n 예: 10123456789"
}
},
"title": "protos.Phone"
}
],
"description": "내원객 전화번호"
},
"visitorEmail": {
"type": "string",
"description": "내원객 이메일",
"format": "email"
},
"visitorNationality": {
"type": "string",
"description": "내원객 국적 (ISO 3166-1 alpha-2)"
},
"visitorLanguage": {
"type": "string",
"description": "내원객 언어n 지원 목록: ko, ja, en, zh-CN, zh-yue, es, th, ru, id, ms, vi, mn, uz, nl, de, pt, etc"
},
"visitorBirthDayUtc": {
"type": "string",
"description": "내원객 생년월일",
"format": "date-time"
},
"visitorSnsInfo": {
"allOf": [
{
"type": "object",
"properties": {
"snsType": {
"enum": [
"etc",
"kakaotalk",
"line",
"instagram",
"whatsapp",
"wechat"
],
"type": "string",
"format": "enum"
},
"accountId": {
"type": "string"
}
},
"title": "protos.visitor.SnsInfo"
}
],
"description": "내원객 SNS 정보"
},
"visitorPassportNumber": {
"type": "string",
"description": "내원객 여권번호"
},
"visitorPassportSurname": {
"type": "string",
"description": "내원객 여권 영문 성"
},
"visitorPassportGivenNames": {
"type": "string",
"description": "내원객 여권 영문 이름"
},
"zoneId": {
"type": "string",
"description": "접수 구역 ID (내원객이 방문할 구역)",
"format": "object-id"
},
"occupiedResources": {
"type": "array",
"items": {
"required": [
"startDateTimeUtc",
"endDateTimeUtc"
],
"type": "object",
"properties": {
"startDateTimeUtc": {
"type": "string",
"description": "점유 시작 시각 (UTC ISO 8601)",
"format": "date-time"
},
"endDateTimeUtc": {
"type": "string",
"description": "점유 종료 시각 (UTC ISO 8601)",
"format": "date-time"
},
"reservationGroup": {
"allOf": [
{
"required": [
"reservationGroupId",
"zoneId"
],
"type": "object",
"properties": {
"reservationGroupId": {
"type": "string",
"description": "예약 그룹 ID",
"format": "object-id"
},
"zoneId": {
"type": "string",
"description": "점유할 구역 ID",
"format": "object-id"
},
"doctor": {
"allOf": [
{
"required": [
"id",
"name"
],
"type": "object",
"properties": {
"id": {
"type": "string",
"description": "계정 ID",
"format": "object-id"
},
"name": {
"type": "string",
"description": "계정 이름"
}
},
"title": "protos.schedule.Doctor"
}
],
"description": "리소스 담당 의사"
}
},
"description": "예약 그룹 점유 리소스 상세 설정",
"title": "protos.open.OccupiedReservationGroupResource"
}
],
"description": "예약 그룹 기반 리소스 점유 설정"
}
},
"description": "V2 점유 리소스 모델 (추상적 모델)n 점유 시간 정보를 공통으로 가지며, 구체적인 리소스 구성은 configuration(oneof)을 통해 정의됩니다.",
"title": "protos.open.OccupiedResource"
},
"description": "예약 일정 목록"
},
"consultationRequired": {
"type": "boolean",
"description": "상담 필요 여부"
},
"sedationRequired": {
"type": "boolean",
"description": "수면 마취 필요 여부"
},
"funnelDetail": {
"type": "string",
"description": "상세 유입 경로"
},
"requestedProcedures": {
"type": "array",
"items": {
"required": [
"type"
],
"type": "object",
"properties": {
"type": {
"enum": [
"RESERVATION_REQUESTED_PROCEDURE_TYPE_UNSPECIFIED",
"OPTION",
"TICKET"
],
"type": "string",
"description": "요청 시술 유형 (OPTION: 상품 옵션, TICKET: 시술권)",
"format": "enum"
},
"optionConfiguration": {
"allOf": [
{
"required": [
"optionId",
"optionTitle",
"price"
],
"type": "object",
"properties": {
"optionId": {
"type": "string",
"description": "상품 옵션 ID"
},
"optionTitle": {
"type": "string",
"description": "상품 옵션 이름"
},
"productTitle": {
"type": "string",
"description": "상품 이름"
},
"promotionTitle": {
"type": "string",
"description": "프로모션 이름"
},
"price": {
"allOf": [
{
"type": "object",
"properties": {
"amount": {
"type": "integer",
"format": "int32"
},
"currency": {
"type": "string"
},
"reason": {
"type": "object",
"properties": {
"type": {
"enum": [
"RESERVATION_REQUESTED_OPTION_PRICE_REASON_TYPE_UNSPECIFIED",
"GENERAL",
"PROMOTION",
"VISITOR_TYPE"
],
"type": "string",
"format": "enum"
},
"promotionId": {
"type": "string"
},
"visitorTypeId": {
"type": "string"
}
},
"title": "protos.schedule.ReservationRequestedOptionPriceReason"
}
},
"title": "protos.schedule.ReservationRequestedOptionPrice"
}
],
"description": "가격 정보"
},
"medicalService": {
"allOf": [
{
"type": "object",
"properties": {
"id": {
"type": "string"
},
"title": {
"type": "string"
},
"translsMap": {
"type": "object",
"additionalProperties": {
"type": "object",
"properties": {
"translation": {
"type": "object",
"additionalProperties": {
"type": "string"
}
}
},
"title": "protos.Transls"
},
"description": "# 다국어 지원대상 필드n - title"
},
"status": {
"enum": [
"MedicalServiceStatus_UNKNOWN",
"DRAFT",
"PUBLISHED"
],
"type": "string",
"format": "enum"
},
"deleted": {
"type": "boolean"
},
"configuration": {
"type": "object",
"properties": {
"code": {
"type": "string"
},
"procedure": {
"type": "object",
"properties": {
"id": {
"type": "string"
},
"name": {
"type": "string"
},
"searchPhoneticName": {
"type": "string",
"description": "백엔드 내부에서 검색을 위해 존재하는 필드"
}
},
"title": "protos.procedure.medical_service.MedicalServiceProcedure"
},
"machines": {
"type": "array",
"items": {
"type": "object",
"properties": {
"id": {
"type": "string"
},
"name": {
"type": "string"
},
"searchPhoneticName": {
"type": "string",
"description": "백엔드 내부에서 검색을 위해 존재하는 필드"
}
},
"title": "protos.procedure.medical_service.MedicalServiceMachine"
}
},
"medicines": {
"type": "array",
"items": {
"type": "object",
"properties": {
"id": {
"type": "string"
},
"name": {
"type": "string"
},
"searchPhoneticName": {
"type": "string",
"description": "백엔드 내부에서 검색을 위해 존재하는 필드"
}
},
"title": "protos.procedure.medical_service.MedicalServiceMedicine"
}
},
"unit": {
"type": "object",
"properties": {
"type": {
"enum": [
"UnitType_UNKNOWN",
"UNIT",
"CC",
"VIAL",
"PEN",
"STRING",
"SHOT",
"PAD",
"MINUTE",
"KJ",
"QUANTITY",
"DOT",
"J",
"MG",
"G",
"PULSE",
"BOTTLE",
"SYRINGE",
"PASS",
"IU",
"KHZ",
"MHZ"
],
"type": "string",
"format": "enum"
},
"value": {
"type": "number",
"format": "double"
}
},
"title": "protos.procedure.Unit"
},
"healthcareReimbursement": {
"enum": [
"HealthcareReimbursement_UNKNOWN",
"REIMBURSABLE",
"NON_REIMBURSABLE"
],
"type": "string",
"format": "enum"
},
"taxation": {
"enum": [
"Taxation_UNKNOWN",
"TAXABLE",
"TAX_FREE",
"MIXED"
],
"type": "string",
"format": "enum"
}
},
"title": "protos.procedure.medical_service.MedicalServiceConfiguration"
},
"draftedDateTimeUtc": {
"type": "string"
},
"updatedDateTimeUtc": {
"type": "string"
},
"priceAmount": {
"type": "object",
"properties": {
"value": {
"type": "integer",
"format": "int32"
},
"currency": {
"type": "string"
}
},
"title": "protos.procedure.PriceAmount"
},
"description": {
"type": "string"
},
"caution": {
"type": "string"
},
"recommendedInterval": {
"type": "integer",
"format": "int32"
},
"contributionConstant": {
"type": "integer",
"format": "int32"
},
"durationTime": {
"type": "number",
"format": "double"
}
},
"title": "protos.procedure.medical_service.MedicalService"
}
],
"description": "진료 항목"
},
"translsMap": {
"type": "object",
"additionalProperties": {
"type": "object",
"properties": {
"translation": {
"type": "object",
"additionalProperties": {
"type": "string"
}
}
},
"title": "protos.Transls"
},
"description": "# 다국어 지원대상 필드n - optionTitlen - productTitle"
}
},
"title": "protos.schedule.ReservationRequestedOptionConfiguration"
}
],
"description": "상품 옵션 설정 (type이 OPTION인 경우)"
},
"ticketConfiguration": {
"allOf": [
{
"required": [
"ticketId",
"ticketTitle",
"optionTitle"
],
"type": "object",
"properties": {
"ticketId": {
"type": "string",
"description": "시술권 ID"
},
"ticketTitle": {
"type": "string",
"description": "시술권 이름"
},
"optionTitle": {
"type": "string",
"description": "옵션 이름"
},
"medicalService": {
"allOf": [
{
"type": "object",
"properties": {
"id": {
"type": "string"
},
"title": {
"type": "string"
},
"translsMap": {
"type": "object",
"additionalProperties": {
"type": "object",
"properties": {
"translation": {
"type": "object",
"additionalProperties": {
"type": "string"
}
}
},
"title": "protos.Transls"
},
"description": "# 다국어 지원대상 필드n - title"
},
"status": {
"enum": [
"MedicalServiceStatus_UNKNOWN",
"DRAFT",
"PUBLISHED"
],
"type": "string",
"format": "enum"
},
"deleted": {
"type": "boolean"
},
"configuration": {
"type": "object",
"properties": {
"code": {
"type": "string"
},
"procedure": {
"type": "object",
"properties": {
"id": {
"type": "string"
},
"name": {
"type": "string"
},
"searchPhoneticName": {
"type": "string",
"description": "백엔드 내부에서 검색을 위해 존재하는 필드"
}
},
"title": "protos.procedure.medical_service.MedicalServiceProcedure"
},
"machines": {
"type": "array",
"items": {
"type": "object",
"properties": {
"id": {
"type": "string"
},
"name": {
"type": "string"
},
"searchPhoneticName": {
"type": "string",
"description": "백엔드 내부에서 검색을 위해 존재하는 필드"
}
},
"title": "protos.procedure.medical_service.MedicalServiceMachine"
}
},
"medicines": {
"type": "array",
"items": {
"type": "object",
"properties": {
"id": {
"type": "string"
},
"name": {
"type": "string"
},
"searchPhoneticName": {
"type": "string",
"description": "백엔드 내부에서 검색을 위해 존재하는 필드"
}
},
"title": "protos.procedure.medical_service.MedicalServiceMedicine"
}
},
"unit": {
"type": "object",
"properties": {
"type": {
"enum": [
"UnitType_UNKNOWN",
"UNIT",
"CC",
"VIAL",
"PEN",
"STRING",
"SHOT",
"PAD",
"MINUTE",
"KJ",
"QUANTITY",
"DOT",
"J",
"MG",
"G",
"PULSE",
"BOTTLE",
"SYRINGE",
"PASS",
"IU",
"KHZ",
"MHZ"
],
"type": "string",
"format": "enum"
},
"value": {
"type": "number",
"format": "double"
}
},
"title": "protos.procedure.Unit"
},
"healthcareReimbursement": {
"enum": [
"HealthcareReimbursement_UNKNOWN",
"REIMBURSABLE",
"NON_REIMBURSABLE"
],
"type": "string",
"format": "enum"
},
"taxation": {
"enum": [
"Taxation_UNKNOWN",
"TAXABLE",
"TAX_FREE",
"MIXED"
],
"type": "string",
"format": "enum"
}
},
"title": "protos.procedure.medical_service.MedicalServiceConfiguration"
},
"draftedDateTimeUtc": {
"type": "string"
},
"updatedDateTimeUtc": {
"type": "string"
},
"priceAmount": {
"type": "object",
"properties": {
"value": {
"type": "integer",
"format": "int32"
},
"currency": {
"type": "string"
}
},
"title": "protos.procedure.PriceAmount"
},
"description": {
"type": "string"
},
"caution": {
"type": "string"
},
"recommendedInterval": {
"type": "integer",
"format": "int32"
},
"contributionConstant": {
"type": "integer",
"format": "int32"
},
"durationTime": {
"type": "number",
"format": "double"
}
},
"title": "protos.procedure.medical_service.MedicalService"
}
],
"description": "진료 항목"
},
"productTitle": {
"type": "string",
"description": "상품 이름"
},
"translsMap": {
"type": "object",
"additionalProperties": {
"type": "object",
"properties": {
"translation": {
"type": "object",
"additionalProperties": {
"type": "string"
}
}
},
"title": "protos.Transls"
},
"description": "# 다국어 지원대상 필드n - ticketTitlen - optionTitlen - productTitle"
}
},
"title": "protos.schedule.ReservationRequestedTicketConfiguration"
}
],
"description": "시술권 설정 (type이 TICKET인 경우)"
}
},
"title": "protos.schedule.ReservationRequestedProcedure"
},
"description": "희망 시술 목록"
},
"reservationMemo": {
"type": "string",
"description": "예약 메모"
},
"visitorConnectedInformation": {
"allOf": [
{
"type": "object",
"properties": {
"line": {
"allOf": [
{
"type": "object",
"properties": {
"id": {
"type": "string"
},
"channelId": {
"type": "string"
},
"liffId": {
"type": "string"
},
"displayName": {
"type": "string"
}
},
"title": "protos.open.VisitorConnectedInformation_Line"
}
],
"description": "Line 연동 정보"
},
"unni": {
"allOf": [
{
"type": "object",
"properties": {
"id": {
"type": "string"
},
"nickname": {
"type": "string"
}
},
"title": "protos.open.VisitorConnectedInformation_Unni"
}
],
"description": "강남언니 연동 정보"
}
},
"description": "내원객 연동 정보",
"title": "protos.open.VisitorConnectedInformation"
}
],
"description": "내원객 연동 정보"
}
},
"description": "여러 예약 일정으로 새로운 예약을 생성합니다. (신규 내원객 정보 기반)nn ### 내원객 중복 검색 정책nn 요청에 포함된 내원객 정보로 기존 내원객을 검색하여, 일치하는 내원객이 있으면 해당 내원객으로 예약을 생성합니다.n 일치하는 내원객이 없으면 새로운 내원객을 생성한 후 예약을 생성합니다.nn 중복 검색은 다음 조건들을 **우선순위 순서대로** 확인하며, 먼저 일치하는 조건이 있으면 해당 내원객을 사용합니다:nn | 우선순위 | 검색 조건 |n |---------|----------|n | 1 | `visitorName` + `visitorPhone` |n | 2 | `visitorPassportNumber` |n | 3 | `visitorSnsInfo` |n | 4 | `visitorEmail` |n | 5 | `visitorName` + `visitorBirthDayUtc` |nn > **참고**: 각 조건은 독립적으로 검색되며, 모든 필드가 AND로 결합되지 않습니다.",
"title": "protos.open.OpenReserveCommandV2"
}
}
}
Responses
- 200
OK
### Status Code별 응답의 JSON Schema
{
"200": {
"description": "OK",
"content": {
"application/json": {
"schema": {
"required": [
"scheduleId"
],
"type": "object",
"properties": {
"scheduleId": {
"type": "string",
"description": "생성된 스케줄 ID",
"format": "uuid"
}
},
"description": "V2 예약 생성 응답",
"title": "protos.open.OpenReserveCommandV2Response"
}
}
}
}
}