SaaS API기업 서비스 이용 계약서
PATCH /ai/admin/business-contracts/{businessId}/review
관리자 — 기업이 서명한 계약서를 검수 승인 또는 거절 (단일 엔드포인트)
계약서 검수 처리 (관리자)
기업이 step=SIGN까지 완료한 계약서를 어드민이 검수하여 승인 또는 거절 처리합니다.
승인/거절을 하나의 엔드포인트로 통합하고 decision 쿼리 파라미터로 분기합니다.
거절 시 reason은 선택 입력입니다(전달 시 계약서 row와 감사 로그에 기록됨).
대상은 최신 SIGNED + approvalStatus=PENDING_APPROVAL 계약서 1건이며, 해당 계약이 없으면 BIZ_CONTRACT_NOT_FOUND를 반환합니다.
| 항목 | 값 |
|---|---|
| 메서드 | PATCH |
| 경로 | /ai/admin/business-contracts/{businessId}/review |
| 인증 | 관리자 |
요청
| 파라미터 | 위치 | 타입 | 필수 | 설명 |
|---|---|---|---|---|
businessId | Path | String | 예 | 기업 회원 ID |
adminId | Query | String | 예 | 처리 관리자 ID (감사 로그 기록용) |
decision | Query | Enum | 예 | APPROVED 또는 REJECTED |
reason | Query | String | 아니오 | 거절 사유 (선택 입력. decision=REJECTED일 때만 의미 있음, 감사 로그/계약서 row에 기록) |
# 승인
PATCH /ai/admin/business-contracts/biz_user_001/review?adminId=admin_kim&decision=APPROVED
# 거절 (reason 선택)
PATCH /ai/admin/business-contracts/biz_user_001/review?adminId=admin_kim&decision=REJECTED&reason=인감%20파일%20불량
# 거절 (reason 생략 가능)
PATCH /ai/admin/business-contracts/biz_user_001/review?adminId=admin_kim&decision=REJECTED처리 결과
decision=APPROVED
TB_BUSINESS_CONTRACT.approval_status = APPROVEDapproved_by = {adminId},approved_at = now()TB_BUSINESS.contract_sign_status = SIGNED(EXCEPTION 계정은 그대로 유지)- 감사 로그:
APPROVED이벤트 기록
decision=REJECTED
TB_BUSINESS_CONTRACT.status = REJECTED(계약서 row 자체가 종결 상태로 전환)TB_BUSINESS_CONTRACT.approval_status = REJECTEDapproved_by = {adminId},approved_at = now(),rejection_reason = {reason}(reason미전달 시 NULL)TB_BUSINESS_CONTRACT.voided_pdf_url에 원본 PDF + 빨간 VOID 워터마크 합성본 URL 저장- 원본
final_pdf_url은 절대 변경되지 않음 (감사 추적용 보존) - S3 키:
contract/business/voided/{businessId}/... - 합성 실패 시 거절 자체는 성공 처리,
voided_pdf_url만 NULL
- 원본
TB_BUSINESS.contract_sign_status = NONE(EXCEPTION 계정은 그대로 유지)- 감사 로그:
REJECTED이벤트 (reason/voidedPdfUrl있을 때만notes에 기록) - 재계약을 받으려면
POST /ai/admin/business-contracts/{businessId}/send로 재발송 → 새 row 가 PENDING 으로 생성됨 (REJECTED row 는 진행 중 계약 후보에서 자동 제외)
contract_sign_status = SIGNED 진입 경로는 이 API의 APPROVED 분기 단 하나입니다. sign 직후엔 PENDING, 거절 시 NONE이며, 어드민이 명시적으로 승인하지 않는 한 캠페인 생성이 불가능합니다.
응답 (200 OK)
승인
{
"status": 200,
"code": null,
"message": "계약서 검수가 승인되었습니다.",
"data": {
"contractStatus": "SIGNED",
"contractSignStatus": "SIGNED",
"approvalStatus": "APPROVED",
"stampImageUrl": "https://glowb-input.s3.ap-southeast-1.amazonaws.com/contract/business/stamp/...",
"finalPdfUrl": "https://glowb-input.s3.ap-southeast-1.amazonaws.com/contract/business/pdf/...",
"signedAt": "2026-05-11T18:06:00",
"approvedAt": "2026-05-11T18:30:00"
}
}거절
{
"status": 200,
"code": null,
"message": "계약서 검수가 거절되었습니다.",
"data": {
"contractStatus": "REJECTED",
"contractSignStatus": "NONE",
"approvalStatus": "REJECTED",
"rejectionReason": "인감 파일 불량",
"voidedPdfUrl": "https://glowb-input.s3.ap-southeast-1.amazonaws.com/contract/business/voided/biz_user_001/...",
"approvedAt": "2026-05-11T18:30:00"
}
}VOID PDF 합성 실패 시:
{
...
"contractStatus": "REJECTED",
"approvalStatus": "REJECTED",
"voidedPdfUrl": null
}에러 응답
| 코드 | 설명 |
|---|---|
BIZ_C007 | 기업 정보를 찾을 수 없음 |
BIZ_CONTRACT_NOT_FOUND | 검수 대기 중인 계약서가 없음 (이미 처리되었거나 sign 미완료) |
BIZ_CONTRACT_INVALID_STATE | decision이 APPROVED/REJECTED 외 값 |