콘텐츠 검수 API
검수 단계 제출물 및 피드백 관리 API
콘텐츠 검수 API
검수 단계 제출물 및 피드백 관리 API입니다.
Base URL: /ai/influence/contents
인증 정보
| 항목 | 값 |
|---|---|
| 인증 필요 | 예 |
| 인증 방식 | JWT Bearer Token |
엔드포인트 목록
제출물 관리
| 메서드 | 경로 | 설명 | 인증 |
|---|---|---|---|
GET | /ai/influence/contents/{itemId} | 제출물 조회 (ID) | 필요 |
GET | /ai/influence/contents/review/{reviewId}/type/{itemType} | 제출물 조회 (검수라운드+타입) | 필요 |
GET | /ai/influence/contents/review/{reviewId} | 검수 라운드별 제출물 목록 | 필요 |
POST | /ai/influence/contents | 제출물 신규 생성 | 필요 |
PUT | /ai/influence/contents/{itemId} | 제출물 수정 | 필요 |
PUT | /ai/influence/contents/{itemId}/editor | 에디터 상태 저장 | 필요 |
PATCH | /ai/influence/contents/{itemId}/submit | 제출 상태 변경 | 필요 |
피드백
| 메서드 | 경로 | 설명 | 인증 |
|---|---|---|---|
PATCH | /ai/influence/contents/feedbacks/{feedbackId}/resolve | 피드백 해결 상태 변경 | 필요 |
PATCH | /ai/influence/contents/feedbacks/{feedbackId}/check | 피드백 체크 상태 변경 (임시 저장) | 필요 |
일괄 제출
| 메서드 | 경로 | 설명 | 인증 |
|---|---|---|---|
PUT | /ai/influence/contents/review/{reviewId}/submit | 검수 라운드 일괄 제출 | 필요 |
히스토리
| 메서드 | 경로 | 설명 | 인증 |
|---|---|---|---|
GET | /ai/influence/contents/{itemId}/history | 제출물 히스토리 조회 | 필요 |
GET | /ai/influence/contents/{itemId}/history/compare | 버전 비교 | 필요 |
최종 제작물
| 메서드 | 경로 | 설명 | 인증 |
|---|---|---|---|
GET | /ai/influence/contents/{applicationId}/final-submission | 최종 제작물 조회 | 필요 |
POST | /ai/influence/contents/{applicationId}/final-submission | 최종 제작물 저장/제출 | 필요 |
PATCH | /ai/influence/contents/{applicationId}/final-submission | 최종 제작물 재제출 | 필요 |
API 상세
제출물 조회 (ID)
제출물 ID로 제출물 상세를 조회합니다. editorState, 피드백 목록을 포함합니다.
HTTP 요청
GET /ai/influence/contents/{itemId}
Authorization: Bearer {access_token}Path Parameters
| 파라미터 | 타입 | 필수 | 설명 |
|---|---|---|---|
itemId | long | 예 | 제출물 ID |
제출물 조회 (검수라운드+타입)
검수 라운드 ID와 제출물 타입으로 조회합니다. 이전에 저장한 내용이 있으면 불러옵니다.
HTTP 요청
GET /ai/influence/contents/review/{reviewId}/type/{itemType}
Authorization: Bearer {access_token}Path Parameters
| 파라미터 | 타입 | 필수 | 설명 |
|---|---|---|---|
reviewId | long | 예 | 검수 라운드 ID |
itemType | SubmissionItemType | 예 | 제출물 타입 |
제출물 타입 (SubmissionItemType)
| 타입 | 설명 |
|---|---|
VIDEO | 영상 |
SCRIPT | 스크립트 |
HASHTAG | 해시태그 |
CAPTION | 캡션 |
검수 라운드별 제출물 목록 조회
검수 라운드에서 제출해야 할 모든 타입 목록과 각 타입별 저장된 내용을 조회합니다.
HTTP 요청
GET /ai/influence/contents/review/{reviewId}
Authorization: Bearer {access_token}Path Parameters
| 파라미터 | 타입 | 필수 | 설명 |
|---|---|---|---|
reviewId | long | 예 | 검수 라운드 ID |
응답
성공 응답 (200 OK)
{
"status": 200,
"code": null,
"message": "조회 성공",
"data": {
"reviewId": 88,
"reviewRound": 1,
"requiredHashtags": "#브랜드명 #협찬",
"submissionItems": [
{
"itemType": "VIDEO",
"item": {
"id": 1,
"itemType": "VIDEO",
"filePath": "https://s3.../video.mp4",
"editorState": {...},
"status": "REVIEWING",
"isSubmitted": true
}
},
{
"itemType": "HASHTAG",
"item": null
}
],
"unreflectedFeedbackIds": [1, 2, 3],
"hasAdditionalReviewRequest": true,
"needsResubmission": false
}
}Response Body 스키마
| 필드명 | 타입 | 설명 |
|---|---|---|
reviewId | long | 검수 라운드 ID |
reviewRound | int | 검수 라운드 (1: 1차, 2: 2차) |
requiredHashtags | string | 캠페인 필수 해시태그 |
submissionItems | array | 제출물 타입별 목록 |
submissionItems[].itemType | string | 제출물 타입 |
submissionItems[].item | object | 저장된 제출물 (없으면 null) |
unreflectedFeedbackIds | array<long> | 반영되지 않은 피드백 ID 목록 (nullable) |
hasAdditionalReviewRequest | boolean | 추가 검수 요청 여부 |
needsResubmission | boolean | 크리에이터가 지금 수정/재제출해야 하는지 여부 |
unreflectedFeedbackIds 필드
기업이 "피드백 미반영" 검수 추가 요청 시 지정한 피드백 ID 목록입니다.
- 값이 있으면: 해당 피드백들을 하이라이트 표시하여 크리에이터가 재반영해야 함을 안내
- 값이
null이면: 일반 피드백 목록으로 표시
hasAdditionalReviewRequest 필드
기업이 추가 검수 요청을 했는지 여부를 나타냅니다.
true: 기업이 검수 추가 요청을 한 상태 (maxFeedbackCount > 1)false: 일반 검수 진행 중 (maxFeedbackCount = 1)
이 값이 true이면 크리에이터에게 추가 검수 요청이 있음을 안내할 수 있습니다.
needsResubmission 필드
크리에이터가 현재 제출물을 수정하거나 재제출해야 하는지를 나타냅니다.
true: 재제출 필요 (제출물이 REJECTED 상태이거나 미제출)false: 제출 완료, 기업 검수 대기 중 또는 승인 완료 (REVIEWING/APPROVED)
프론트엔드 활성화 조건: needsResubmission === true일 때만 편집/제출 버튼 활성화
제출물 신규 생성
새 제출물을 생성합니다.
HTTP 요청
POST /ai/influence/contents
Authorization: Bearer {access_token}
Content-Type: application/jsonRequest Body
{
"reviewId": 1,
"itemType": "VIDEO",
"editorState": {...},
"isSubmit": false
}Request Body 스키마
| 필드명 | 타입 | 필수 | 설명 |
|---|---|---|---|
reviewId | long | 예 | 검수 라운드 ID |
itemType | string | 예 | 제출물 타입 |
editorState | object | 아니오 | Lexical 에디터 상태 JSON |
isSubmit | boolean | 예 | true면 제출, false면 임시저장 |
제출물 수정
기존 제출물을 수정합니다.
HTTP 요청
PUT /ai/influence/contents/{itemId}
Authorization: Bearer {access_token}
Content-Type: application/jsonRequest Body
{
"editorState": {...},
"isSubmit": true
}에디터 상태 자동 저장
Lexical 에디터 상태(JSON)만 저장합니다. 자동 저장용입니다.
HTTP 요청
PUT /ai/influence/contents/{itemId}/editor
Authorization: Bearer {access_token}
Content-Type: application/jsonRequest Body
{
"editorState": {...}
}제출 상태 변경
저장 상태를 제출로 변경하거나 제출을 취소합니다.
HTTP 요청
PATCH /ai/influence/contents/{itemId}/submit
Authorization: Bearer {access_token}
Content-Type: application/jsonRequest Body
{
"isSubmit": true
}피드백 해결 상태 변경
피드백의 해결 완료 상태를 토글합니다.
HTTP 요청
PATCH /ai/influence/contents/feedbacks/{feedbackId}/resolve
Authorization: Bearer {access_token}
Content-Type: application/jsonRequest Body
{
"isResolved": true
}피드백 체크 상태 변경 (임시 저장)
크리에이터가 피드백을 확인/반영했음을 임시로 체크합니다. 제출 시 isResolved로 자동 전환됩니다.
checkedByCreator vs isResolved 차이점
checkedByCreator: 크리에이터가 피드백을 확인하고 반영 중임을 임시로 표시 (저장 용도)isResolved: 피드백이 최종적으로 해결 완료된 상태 (일괄 제출 시 자동 설정)
HTTP 요청
PATCH /ai/influence/contents/feedbacks/{feedbackId}/check
Authorization: Bearer {access_token}
Content-Type: application/jsonPath Parameters
| 파라미터 | 타입 | 필수 | 설명 |
|---|---|---|---|
feedbackId | long | 예 | 피드백 ID |
Request Body
{
"isChecked": true
}Request Body 스키마
| 필드명 | 타입 | 필수 | 설명 |
|---|---|---|---|
isChecked | boolean | 예 | true: 체크, false: 체크 해제 |
응답
성공 응답 (200 OK)
{
"status": 200,
"code": null,
"message": "체크 상태 변경 완료",
"data": {
"id": 1,
"feedbackType": "TEXT",
"content": "해시태그 수정 필요",
"position": null,
"isResolved": false,
"checkedByCreator": true,
"createdAt": "2025-01-14T10:00:00"
}
}검수 라운드 일괄 제출
검수 라운드의 모든 제출물 내용을 저장하고 일괄 제출합니다. 신규 제출과 재제출 모두 이 API를 사용합니다.
주요 동작
- 각 제출물의 내용(filePath, editorState, comment)을 저장
- 모든 제출물을 제출 상태(
isSubmitted=true)로 변경 - 해당 검수 라운드의 모든 미해결 피드백을 해결완료(
isResolved=true) 처리 - 재제출 시 이전 버전은 히스토리로 자동 저장
HTTP 요청
PUT /ai/influence/contents/review/{reviewId}/submit
Authorization: Bearer {access_token}
Content-Type: application/jsonPath Parameters
| 파라미터 | 타입 | 필수 | 설명 |
|---|---|---|---|
reviewId | long | 예 | 검수 라운드 ID |
Request Body
{
"items": [
{
"itemId": 1,
"itemType": "VIDEO",
"filePath": "https://s3.../video.mp4",
"editorState": null,
"comment": "수정된 영상입니다"
},
{
"itemId": 2,
"itemType": "CAPTION",
"filePath": null,
"editorState": {"root": {...}},
"comment": null
},
{
"itemId": null,
"itemType": "HASHTAG",
"filePath": null,
"editorState": {"requiredHashtags": ["#브랜드"], "additionalHashtags": ["#추가"]},
"comment": null
}
]
}Request Body 스키마
| 필드명 | 타입 | 필수 | 설명 |
|---|---|---|---|
items | array | 예 | 제출할 제출물 목록 |
items[].itemId | long | 조건부 | 제출물 ID (기존 항목 수정 시 필수, 신규 시 null) |
items[].itemType | string | 조건부 | 제출물 타입 (신규 생성 시 필수) |
items[].filePath | string | 조건부 | S3 파일 URL (VIDEO, PHOTO 타입은 필수) |
items[].editorState | object | 아니오 | Lexical 에디터 상태 JSON (SCRIPT, CAPTION, HASHTAG 타입용) |
items[].comment | string | 아니오 | 코멘트 (선택) |
VIDEO/PHOTO 타입 필수 조건
VIDEO 또는 PHOTO 타입으로 제출할 때는 반드시 filePath에 업로드된 파일 URL이 있어야 합니다.
파일 없이 제출하면 에러가 반환됩니다.
- VIDEO 타입: "영상 파일을 업로드해주세요."
- PHOTO 타입: "사진 파일을 업로드해주세요."
itemId 사용 규칙
- 기존 제출물 수정:
itemId필수,itemType무시됨 - 신규 제출물 생성:
itemId= null,itemType필수
같은 타입의 제출물이 여러 개 있을 수 있으므로 (히스토리 관리), 반드시 itemId로 식별해야 합니다.
응답
성공 응답 (200 OK)
{
"status": 200,
"code": null,
"message": "일괄 제출 완료",
"data": {
"reviewId": 88,
"items": [
{
"id": 1,
"reviewId": 88,
"itemType": "VIDEO",
"filePath": "https://s3.../video.mp4",
"editorState": null,
"comment": "수정된 영상입니다",
"status": "REVIEWING",
"isSubmitted": true,
"submittedAt": "2025-01-14T15:30:00",
"currentVersion": 2,
"feedbacks": []
},
{
"id": 2,
"reviewId": 88,
"itemType": "CAPTION",
"filePath": null,
"editorState": {"root": {...}},
"comment": null,
"status": "REVIEWING",
"isSubmitted": true,
"submittedAt": "2025-01-14T15:30:00",
"currentVersion": 1,
"feedbacks": []
}
],
"resolvedFeedbackCount": 3
}
}Response Body 스키마
| 필드명 | 타입 | 설명 |
|---|---|---|
reviewId | long | 검수 라운드 ID |
items | array | 제출된 제출물 목록 |
resolvedFeedbackCount | int | 자동으로 해결완료 처리된 피드백 수 |
에러 응답
| 상황 | 상태 코드 | 메시지 |
|---|---|---|
| VIDEO 파일 없음 | 400 | 영상 파일을 업로드해주세요. |
| PHOTO 파일 없음 | 400 | 사진 파일을 업로드해주세요. |
| 제출물 타입 누락 | 400 | 신규 생성 시 제출물 타입은 필수입니다. |
| 제출물 없음 | 400 | 제출할 제출물이 없습니다. |
PUT /items/{itemId} vs PUT /review/{reviewId}/submit 차이점
| 항목 | PUT /items/{itemId} | PUT /review/{reviewId}/submit |
|---|---|---|
| 대상 | 단일 제출물 | 검수 라운드 전체 |
| 피드백 해결 | 수동 처리 필요 | 자동 일괄 해결 |
| 제출 상태 | isSubmit에 따라 결정 | 무조건 제출 처리 |
| 용도 | 개별 저장/제출 | 최종 일괄 제출 |
제출물 히스토리 조회
제출물의 수정 히스토리를 조회합니다. 현재 버전과 모든 이전 버전 목록을 반환합니다.
HTTP 요청
GET /ai/influence/contents/{itemId}/history
Authorization: Bearer {access_token}버전 비교
두 버전 간의 변경 내용을 비교합니다. afterVersion이 없으면 현재 버전과 비교합니다.
HTTP 요청
GET /ai/influence/contents/{itemId}/history/compare?beforeVersion={before}&afterVersion={after}
Authorization: Bearer {access_token}Query Parameters
| 파라미터 | 타입 | 필수 | 설명 |
|---|---|---|---|
beforeVersion | int | 예 | 비교 기준 버전 |
afterVersion | int | 아니오 | 비교 대상 버전 (없으면 현재 버전) |
최종 제작물 조회
업로드/정산 단계에서 최종 제작물을 조회합니다.
HTTP 요청
GET /ai/influence/contents/{applicationId}/final-submission
Authorization: Bearer {access_token}응답
성공 응답 (200 OK)
{
"status": 200,
"code": null,
"message": "조회 성공",
"data": {
"id": 1,
"applicationId": 123,
"contentLink": "https://instagram.com/p/...",
"partnershipCode": "ABC123",
"cleanFilePath": "https://s3.../clean.mp4",
"finalFilePath": "https://s3.../final.mp4",
"isSubmitted": true,
"submittedAt": "2024-01-15T10:30:00",
"requiredTypes": ["CONTENT_LINK", "PARTNERSHIP_CODE", "CLEAN_FILE", "FINAL_FILE"],
"hasReRequest": true,
"reRequestTypes": ["CONTENT_LINK", "CLEAN_FILE"],
"reRequestedAt": "2024-01-20T14:00:00"
}
}재요청 관련 필드
| 필드 | 타입 | 설명 |
|---|---|---|
hasReRequest | boolean | 재요청 존재 여부 |
reRequestTypes | array<string> | 재요청 항목 목록 |
reRequestedAt | datetime | 재요청 일시 |
재요청이 있는 경우
hasReRequest가 true이면 기업에서 해당 항목들에 대해 재제출을 요청한 것입니다.
reRequestTypes에 포함된 항목들을 다시 제출해야 합니다.
최종 제작물 저장/제출
업로드/정산 단계에서 최종 제작물을 저장하거나 제출합니다.
HTTP 요청
POST /ai/influence/contents/{applicationId}/final-submission
Authorization: Bearer {access_token}
Content-Type: application/jsonRequest Body
{
"uploadLink": "https://instagram.com/p/...",
"partnershipCode": "ABC123",
"files": [
{
"fileUrl": "https://s3.../video.mp4",
"fileName": "final_video.mp4",
"fileType": "VIDEO"
}
],
"isSubmit": true
}파일 업로드는 별도 S3 업로드 API를 사용한 후 URL을 전달합니다.
최종 제작물 재제출
이미 제출한 최종 제작물을 수정하여 재제출합니다. 재요청이 있는 경우 재요청 항목을 클리어하고 재제출 처리합니다.
HTTP 요청
PATCH /ai/influence/contents/{applicationId}/final-submission
Authorization: Bearer {access_token}
Content-Type: application/jsonPath Parameters
| 파라미터 | 타입 | 필수 | 설명 |
|---|---|---|---|
applicationId | long | 예 | 신청 ID |
Request Body
{
"contentLink": "https://instagram.com/p/...",
"partnershipCode": "ABC123",
"cleanFilePath": "https://s3.../clean.mp4",
"finalFilePath": "https://s3.../final.mp4"
}Request Body 스키마
| 필드명 | 타입 | 필수 | 설명 |
|---|---|---|---|
contentLink | string | 아니오 | 업로드한 콘텐츠 링크 |
partnershipCode | string | 아니오 | 파트너십 코드 |
cleanFilePath | string | 아니오 | 클린본 파일 S3 URL |
finalFilePath | string | 아니오 | 최종본 파일 S3 URL |
재제출 조건
- 이미 제출된 상태(
isSubmitted=true)에서만 사용 가능 - 제출된 내용이 없으면 POST API로 최초 제출해야 함
- null이 아닌 필드만 업데이트됨
응답
성공 응답 (200 OK)
{
"status": 200,
"code": null,
"message": "재제출 완료",
"data": {
"id": 1,
"applicationId": 123,
"contentLink": "https://instagram.com/p/...",
"partnershipCode": "ABC123",
"cleanFilePath": "https://s3.../clean.mp4",
"finalFilePath": "https://s3.../final.mp4",
"isSubmitted": true,
"submittedAt": "2024-01-20T15:00:00",
"requiredTypes": ["CONTENT_LINK", "PARTNERSHIP_CODE", "CLEAN_FILE", "FINAL_FILE"],
"hasReRequest": false,
"reRequestTypes": null,
"reRequestedAt": null
}
}재요청 클리어
재제출 시 기존에 있던 재요청 항목(reRequestTypes)이 자동으로 클리어됩니다.
에러 응답
| 상황 | 상태 코드 | 메시지 |
|---|---|---|
| 제출물 없음 | 400 | 제출된 최종 제작물이 없습니다. 먼저 제출해주세요. |
| 미제출 상태 | 400 | 아직 제출되지 않은 상태입니다. 최초 제출은 POST API를 사용해주세요. |
사용 예시
제출물 생성
curl -X POST https://api.glowb.io/ai/influence/contents \
-H "Authorization: Bearer {token}" \
-H "Content-Type: application/json" \
-d '{
"reviewId": 1,
"itemType": "SCRIPT",
"editorState": {"root": {...}},
"isSubmit": false
}'