유료 구독에 연결된 API 키로 운영 일정 제출 API에 연동합니다. 테넌트 스케줄 기본값은 PATCH /v1/schedule-defaults로 저장하고, 직원별 주간 희망은 GET/PUT /v1/staff/{staffId}/weekly-shift-wish로 조회·전체 교체할 수 있습니다. 과금은 구독 및 계약에 따릅니다(API 호출 건수 기반 추가 과금 없음). 유료 권한, 검증 규칙, 오류 코드를 정리했으며 사이드바 검색으로 필드로 이동할 수 있습니다.
본 페이지는 API Gateway의 제품 REST API({stage}/v1/*, x-api-key 인증)만 다룹니다.
Next.js /api/* (Stripe webhook, OG 이미지, Web Vitals 등)는 웹 애플리케이션 내부용이며 본 개발자 API 범위에 포함되지 않습니다. 외부 연동에 사용하지 마세요.
구 UI 폐지에 따라 GET /v1/processing-history는 제공하지 않으며(본 페이지 엔드포인트 목록에도 없음).
본 HTTP API는 유료 제품의 일부입니다. 활성 상업 계약과 온보딩 후 조직에 발급된 키가 필요합니다.
과금은 구독 및 계약에 기반합니다. 유료 플랜의 청구는 가격표에 따라 등록 직원 수(석)에 비례하는 월액이 될 수 있습니다.
플레이그라운드/무료 한도는 유료 API 키에 적용되지 않습니다. 일정 기간, 직원 수, 15분 단위 사용 여부 등은 유료 권한으로 결정됩니다. 자세한 내용은 본 페이지의 한도 및 기본값을 참고하세요.
유료 구독으로 발급된 유효한 API 키를 요청에 포함해야 합니다. 로그인 후 계정 영역에서 키를 생성·교체·폐기할 수 있습니다.
키는 x-api-key 헤더로 전송합니다. 키는 조직에 연결되어 테넌트 식별 및 플랜 기반 이용 한도에 사용됩니다.
키 관리: API 관리
일정 조건을 JSON으로 제출합니다. 유료 연동 표면이며, API 액세스가 부여된 뒤 환경별로 기본 URL이 안내됩니다.
API 액세스 개통 시 또는 운영 담당자가 안내한 기본 URL을 사용하세요.
**BASE_URL**에는 액세스 개통 시 안내된 API 기본 URL(경로 접두사)을 넣습니다.
API 키는 **x-api-key** 헤더로 보냅니다. 조직(테넌트)은 키로 식별되므로 쿼리 문자열에 별도 테넌트 ID를 넘길 필요가 없습니다.
회사 정보 조회·갱신(GET/PATCH /v1/company)에는 유효한 유료 구독이 필요합니다. 테넌트에 결제가 구성되지 않은 경우 **503**(예: 코드 **STRIPE_NOT_CONFIGURED**)을 받을 수 있습니다.
Windows PowerShell: 줄 끝의 `\`는 **줄 이어쓰기가 아닙니다**. 한 줄로 쓰거나, 줄 끝을 **백틱(`)**으로 이어 주세요.
curl -sS -D - \ -H "x-api-key: YOUR_API_KEY" \ "BASE_URL/v1/schedule-results?limit=10" curl -sS -D - \ -H "x-api-key: YOUR_API_KEY" \ "BASE_URL/v1/company"
POST /v1/schedule과 동일한 기본 URL과 API 키를 사용합니다. 선택 쿼리: limit(1~100, 기본 50), cursor(이전 응답의 nextCursor 필드를 그대로 넘기는 불투명 토큰).
GET /v1/company 및 회사 정보 갱신에는 유효한 유료 구독이 필요합니다. 결제가 구성되지 않은 경우 **503 / STRIPE_NOT_CONFIGURED**가 될 수 있습니다.
| 메서드 | 경로 | 설명 |
|---|---|---|
| GET | {baseUrl}/v1/schedule-results | SCHEDULE_RESULT 부모 행 목록: conditionId, status, candidateCount, createdAt/updatedAt 등. DynamoDB 부모 행 페이지네이션. |
| GET | {baseUrl}/v1/schedule-results/history | 스케줄 결과 이력 검색(브라우저 이력 확인과 동일). 선택 from / to(ISO 8601, 기본 서비스 시작~현재), keyword, eventName(쉼표로 INSERT,MODIFY,REMOVE), limit, cursor. 최근·아카이브 자동 통합, items / nextCursor만 반환. |
| GET | {baseUrl}/v1/schedule-results/{conditionId} | conditionId로 SCHEDULE_RESULT 부모 행 1건 조회(JSON 속성, PK/SK 생략). |
| GET | {baseUrl}/v1/schedule-results/{conditionId}/resolution | 해결된 최적화 출력: status, candidates, confirmedAssignments(있을 때). status가 completed이고 아직 확정되지 않았으면 이 GET에서 rank-1이 자동 확정될 수 있습니다(부작용). 수동 확정은 POST …/confirm-assignments를 사용하세요. |
| GET | {baseUrl}/v1/schedule-results/{conditionId}/review | 수동 확정용 리뷰 페이로드(후보, requiredByCellKey, 직원 allowedCellKeys 등). |
| GET | {baseUrl}/v1/schedule-results/{conditionId}/emergency-shift-context | 긴급 시프트 컨텍스트(달력일, 직원, 슬롯 목록). 유료 구독 필요. 조건이 없으면 null. |
| GET | {baseUrl}/v1/schedule-conditions | SCHEDULE_CONDITION 부모 행 목록(conditionId, 날짜, 선택적 publicApiCancelledAt). |
| GET | {baseUrl}/v1/schedule-conditions/{conditionId} | 조건 부모 행과 reqDays, staffSnapshots(PK/SK 제외). |
| GET | {baseUrl}/v1/audit-logs | 감사 로그 항목 목록(최신순; cursor 페이지네이션). |
| GET | {baseUrl}/v1/schedule-defaults | 테넌트 스케줄 기본값 행(SCHEDULE_DEFAULTS) 또는 미저장 시 null. |
| GET | {baseUrl}/v1/schedule-actual/{conditionId} | 실적 시프트 SCHEDULE_ACTUAL 행 또는 없으면 null. |
| GET | {baseUrl}/v1/staff/{staffId}/weekly-shift-wish | 스태프 주간 희망 행 또는 없으면 null. |
| GET | {baseUrl}/v1/company | API 키의 customerId에 해당하는 Stripe Customer 필드(이름, 이메일, 전화, 주소)를 반환합니다. |
| GET | {baseUrl}/v1/users | 테넌트 사용자 목록(선택: limit, cursor, userName, permissionProfileId, scope fullAccess|nonFullAccess). |
| GET | {baseUrl}/v1/users/{userId} | 경로의 userId로 사용자 1명을 조회합니다. |
| GET | {baseUrl}/v1/staff | 테넌트의 활성 직원 목록(표시 이름 정렬). |
| GET | {baseUrl}/v1/staff/{staffId} | staffId로 직원 1명 조회(laborLawCompliance, laborFlsaExempt, 개인 상한, laborConstraintMask 등 노무 상세 포함. 소프트 삭제 시 404). |
동일한 API 키로 JSON 본문을 보냅니다. PATCH /v1/company는 회사명 등 필드를 빈 문자열로 바꾸는 것을 거부합니다(웹 앱과 동일). PATCH /v1/schedule-defaults는 테넌트 전역 기본값(requirementsByCellKey, 계획 기간 등)을 저장하며, 유료 항목은 구독 권한에 따릅니다. PUT /v1/staff/{staffId}/weekly-shift-wish는 해당 직원의 주간 희망 그리드를 전체 교체합니다(검증 참고). DELETE /v1/users/{userId}는 조직에 사용자가 남지 않거나 마지막 관리자 규칙에 해당하면 409를 반환합니다. POST /v1/staff는 명단이 계약 상한을 넘으면 409 STAFF_LIMIT를 반환합니다.
POST /v1/users에는 userName, email, permissionProfileId(테넌트 권한 프로필 UUID)가 필요합니다. 선택: locale, password. 공개 API는 인증 코드 메일을 생략합니다. PATCH 사용자: 변경할 필드만 포함. POST /v1/staff는 JSON { "displayName": "..." }만. PATCH /v1/staff/{staffId}는 displayName, laborLawCompliance, laborFlsaExempt, personalMaxWeeklyMinutes / personalMaxMonthlyMinutes / personalMaxThreeMonthMinutes(정수 또는 null로 해제), laborConstraintMask(객체 또는 null, laborLawCompliance가 true일 때만)를 임의 조합(노무 항목은 유료 구독 필요). POST /v1/schedule-results/{conditionId}/emergency-shift: absentStaffIds·absentDatesYmd 및/또는 absentSlots(유료·참조 시프트 완료 전제). POST …/confirm-assignments: assignments 배열 및 선택적 relaxAvailability. PATCH /v1/schedule-defaults는 PUBLIC_API_SCHEDULE_REQUEST_BODY.md §12. PUT /v1/staff/{staffId}/weekly-shift-wish: scheduleStartDate, scheduleEndDate, timeRangeStart, timeRangeEnd, wishByCellKey.
| 메서드 | 경로 | 설명 |
|---|---|---|
| PATCH | {baseUrl}/v1/company | 회사(청구 고객) 프로필 필드를 업데이트합니다. |
| PATCH | {baseUrl}/v1/schedule-defaults | 테넌트 스케줄 기본값을 저장합니다(본문은 schedule-defaults-actions의 saveSchema와 일치). 유료 항목은 구독 권한에 따릅니다. |
| POST | {baseUrl}/v1/users | 사용자를 생성합니다. 201과 user JSON을 반환합니다. |
| PATCH | {baseUrl}/v1/users/{userId} | 사용자 필드 업데이트(userName, email, permissionProfileId, locale). |
| DELETE | {baseUrl}/v1/users/{userId} | 사용자를 삭제합니다. 활성 사용자가 없거나 마지막 관리자 규칙이면 409. |
| POST | {baseUrl}/v1/staff | 직원을 생성합니다(displayName). 201과 staff JSON을 반환합니다. |
| POST | {baseUrl}/v1/schedule-results/{conditionId}/emergency-shift | 완료된 참조 시프트를 복제하고 결근을 반영한 새 condition 생성(201과 conditionId). 유료 구독 필요. |
| POST | {baseUrl}/v1/schedule-results/{conditionId}/confirm-assignments | 수동 편집 배정을 검증하고 확정 배정 저장(200과 { ok: true }). |
| PATCH | {baseUrl}/v1/staff/{staffId} | 표시명 및 노무 상세(laborLawCompliance, laborFlsaExempt, 개인 상한, laborConstraintMask) 업데이트. |
| DELETE | {baseUrl}/v1/staff/{staffId} | 직원을 소프트 삭제합니다(deletedAt 설정). |
| DELETE | {baseUrl}/v1/schedule-conditions/{conditionId} | 조건을 취소로 표시(publicApiCancelledAt); 자식 행은 삭제하지 않음. |
| PUT | {baseUrl}/v1/schedule-actual/{conditionId} | 실적 배정 JSON { "assignments": [ ... ] } 저장(조건 그리드에 대해 검증). |
| PUT | {baseUrl}/v1/staff/{staffId}/weekly-shift-wish | 주간 희망 전체 교체: 전체 그리드(1~7일), 셀별 wishByCellKey(NONE|LOW|HIGH); 슬롯 길이는 테넌트 기본값 따름. |
| POST | {baseUrl}/v1/users/{userId}/restore | 논리 삭제된 사용자 복원. |
| 헤더 | 설명 |
|---|---|
| x-api-key | 유료 구독에 연결된 API 키(테넌트 및 플랜 한도 식별). |
| Content-Type | application/json |
일부 응답 헤더(요청 ID 등)는 추적용 메타데이터이며 API 키 자체가 아닙니다. 회사·사용자 데이터가 포함된 JSON **본문**은 기밀로 다루세요.
계약에 따른 일반적인 검증 한도(15분 단위, 일정 기간, 등록 직원 수 및 관련 상한).
| 설정 | 유료 API(일반적) |
|---|---|
| 과금 모델 | Stripe 구독; 제품 요금은 일반적으로 가격 페이지와 같이 등록 직원(시트) 수에 비례합니다(API 호출 건당 과금 아님). |
| maxScheduleDays | 표준 유료 2주 상세 계획에서 제출당 최대 14일(계약으로 더 넓히는 경우만). |
| maxStaffPerSchedule | POST /v1/schedule의 staff 배열 최대 500행(PUBLIC_SCHEDULE_MAX_STAFF; 본문의 인라인 staffId). |
| maxRosterStaff | POST /v1/staff 명부 등록 최대 30명(STAFF_ROSTER_MAX_PAID); 초과 시 409 STAFF_LIMIT. |
| allowedGranularities | [60, 15] — 15분 슬롯은 유료 기능, 60분(시간)도 지원. |
| maxPayloadBytes | 524288(512 KiB) UTF-8, 더 높은 상한이 없는 한. |
| strictUnknownRootKeys | true — 알 수 없는 최상위 또는 staff 키는 거부 |
셀당 필요 인원은 0~15의 정수입니다. 요청 빈도 한도를 초과하면 오류 응답이 반환될 수 있습니다.
엄격 모드가 켜져 있으면 다음 최상위 키만 허용됩니다. 그 외는 UNKNOWN_FIELD입니다.
페이로드는 유료 공개 일정 요청 모델을 따릅니다: 달력 날짜, 시간대, 슬롯 그리드(유료 API에서 60분 또는 15분), 셀별 필요 인원, 직원 가용성. 노동법 관할, 유료 최적화 플래그, 직원 단위 노동 필드는 JSON에 포함되지 않으며, 저장 시 서버가 부모 SCHEDULE_CONDITION 행에 기본값을 씁니다(「노동법 및 유료 옵션」 참고). DynamoDB 키와 내부 엔티티 유형은 본문에 넣지 마세요.
| 필드 | 타입 | 필수 | 비고 |
|---|---|---|---|
| timeZone | string | 예 | 날짜와 슬롯 해석에 사용하는 IANA 시간대. |
| scheduleStartDate / scheduleEndDate | string (YYYY-MM-DD) | 예 | 포함 달력 범위, 시작 ≤ 종료. |
| timeRangeStart / timeRangeEnd | string (HH:mm) | 예 | 슬롯 열을 정의하는 시계 범위, 최소 1개 슬롯 생성. |
| slotGranularityMinutes | 60 | 15 | 예 | 유료 API: 60(시간) 또는 15(15분). allowedGranularities에 포함. |
| requirementsByCell | object | 예 | 키 = 계산된 그리드의 cellKey, 값 = 0~15 정수. |
| staff | array | 예 | 비어 있지 않음, 최대 크기는 한도 참고, 각 항목: staffId, displayName, 선택 availableCells. |
아래 섹션은 `app/lib/public-schedule-api/validate.ts` 검증과 `sanitize.ts` 처리를 반영하며, 옵션이 없으면 `PUBLIC_SCHEDULE_SUBMIT_DEFAULTS`의 유료 기본값을 사용합니다. JSON 숫자는 실제 숫자로 보내세요(문자열 아님). 검증 후 `build-schedule-transact-items.ts`가 요청 키가 아닌 부모 행 필드(유료 최적화 복사, 노동법 관할, 모델 버전)를 추가합니다 — 「노동법 및 유료 옵션」 참고.
string | 생략 · 필수: 아니요 — 선택
허용 값
동작
대표 오류
TYPE_ERROR지원하지 않는 apiVersion 값.string · 필수: 예
허용 값
동작
대표 오류
INVALID_TIME_ZONE누락, 빈 값, 또는 유효하지 않은 IANA 구역.string, string · 필수: 예 — 둘 다
허용 값
동작
대표 오류
INVALID_DATE_RANGE형식 오류, 잘못된 날짜, 빈 범위 등.SCHEDULE_SPAN_TOO_LONGmaxScheduleDays 초과.string, string · 필수: 예 — 둘 다
허용 값
동작
대표 오류
INVALID_TIME_RANGE값 누락 또는 범위에 슬롯 0개.number(JSON 숫자) · 필수: 예
허용 값
동작
대표 오류
INVALID_GRANULARITY60/15가 아니거나 플랜에서 불허.Record<string, number> · 필수: 예
허용 값
동작
대표 오류
INVALID_REQUIREMENTS객체가 아니거나 키의 숫자가 잘못됨.UNKNOWN_CELL_KEY계산된 날짜×슬롯 그리드 밖 키.array · 필수: 예 — 비어 있지 않은 배열
허용 값
동작
대표 오류
INVALID_STAFF빈 배열, 초과, 잘못된 객체, 정리 실패 등.UNKNOWN_FIELD엄격 모드에서 staff 객체에 알 수 없는 키.DUPLICATE_STAFF_IDstaffId 중복.string[] | 생략 · 필수: 아니요 — 선택
허용 값
SHORTFALL 검사
대표 오류
INVALID_AVAILABLE_CELL알 수 없는 셀 키 또는 빈 항목.SHORTFALL_CELLS필요 인원 대비 가용 인원 부족.해당 없음 — 서버에 저장 · 요청에 포함: 아니요 — 이 키는 보내지 않음
부모 행에 저장되는 내용
문서
허용되지 않은 키를 보낸 경우
UNKNOWN_FIELD엄격 모드가 알 수 없는 루트 또는 staff 속성을 거부.`sanitize.ts` 구현대로 검증 전후에 적용됩니다. INVALID_STAFF 거부 이유를 설명합니다.
staffId
displayName
셀 키(requirements / availableCells)
202 Accepted
본문이 검증을 통과하고 조건이 기록되었으며, 최적화는 비동기로 계속될 수 있습니다. 핸들러가 conditionId 등이 포함된 JSON을 반환할 수 있습니다.
검증 오류는 안정적인 `code`가 있는 구조화된 정보를 반환합니다. 검증 전에 JSON 파싱(INVALID_JSON, PAYLOAD_TOO_LARGE). 저장 실패는 DYNAMODB_ERROR로 나올 수 있습니다. PATCH /v1/schedule-defaults는 실패 시 HTTP 400과 SCHEDULE_DEFAULTS_SAVE_FAILED(상세는 details)를 반환할 수 있습니다.
| 코드 | 의미 |
|---|---|
| INVALID_JSON | 본문이 유효한 JSON이 아님. |
| PAYLOAD_TOO_LARGE | UTF-8 바이트 길이가 maxPayloadBytes(기본 512 KiB) 초과. |
| TYPE_ERROR | 잘못된 JSON 타입 또는 지원하지 않는 apiVersion 문자열. |
| UNKNOWN_FIELD | 엄격 모드: 루트 또는 staff 객체에 허용되지 않은 속성. |
| INVALID_TIME_ZONE | timeZone 누락 또는 유효한 IANA 이름이 아님. |
| INVALID_DATE_RANGE | YYYY-MM-DD가 아님, 잘못된 범위, 빈 열거. |
| SCHEDULE_SPAN_TOO_LONG | 시작~종료 사이 일수가 maxScheduleDays 초과. |
| INVALID_TIME_RANGE | 시간 범위 누락 또는 슬롯 0개. |
| INVALID_GRANULARITY | slotGranularityMinutes가 60/15가 아니거나 플랜에서 불허. |
| INVALID_REQUIREMENTS | requirementsByCell이 객체가 아니거나 값이 0~15 정수가 아님. |
| UNKNOWN_CELL_KEY | 계산된 일정 그리드에 없는 키. |
| INVALID_STAFF | staff가 비어 있음, 너무 큼, 잘못된 행, 정리 실패 등. |
| DUPLICATE_STAFF_ID | staffId 중복. |
| INVALID_AVAILABLE_CELL | availableCells의 빈 항목 또는 알 수 없는 항목. |
| SHORTFALL_CELLS | 필요 인원 대비 가용 인원 부족. |
| DYNAMODB_ERROR | 검증 후 일시적 또는 저장 오류(핸들러에 따라 다름). |
| SCHEDULE_DEFAULTS_SAVE_FAILED | PATCH /v1/schedule-defaults: 검증 또는 비즈니스 규칙 실패(error.details 참고). |
| LABOR_COMPLIANCE_REQUIRED | PATCH /v1/staff/{staffId}: laborLawCompliance가 false일 때 laborConstraintMask를 보냄. |
{
"apiVersion": "2026-04-01",
"timeZone": "Asia/Tokyo",
"scheduleStartDate": "2026-04-07",
"scheduleEndDate": "2026-04-13",
"timeRangeStart": "08:00",
"timeRangeEnd": "20:00",
"slotGranularityMinutes": 60,
"requirementsByCell": {
"2026-04-07__slot-0": 2
},
"staff": [
{
"staffId": "550e8400-e29b-41d4-a716-446655440000",
"displayName": "Example",
"availableCells": ["2026-04-07__slot-0"]
}
]
}추가 참고. 제품 플랜 및 유료 기능: docs/architecture/NURSE_SCHEDULING_SERVICE_SPECIFICATION.md. POST /v1/schedule 본문: docs/data-and-api/PUBLIC_API_SCHEDULE_REQUEST_BODY.md §1–§11. 테넌트 기본값 PATCH 본문: 동일 문서 §12. 코드: app/lib/public-schedule-api/, app/features/schedule-settings/schedule-defaults-actions.ts, app/lib/public-api-write/weekly-shift-wish-tenant.ts. 배포: docs/aws/CDK_DEPLOY.md.