Glowb Dev Docs
SaaS API기업용 콘텐츠 검수

POST /ai/business/contents/submission-reminder

콘텐츠 제출 독촉 이메일 발송

콘텐츠 제출 독촉 이메일 발송

광고주가 진행표에서 콘텐츠 제출이 지연된 크리에이터에게 독촉 이메일을 발송합니다.

동작 구조

  • 메일 렌더링과 실제 발송은 node-server가 담당합니다 (React Email 템플릿, 다국어 문구, Resend)
  • 발송 이력과 횟수 제한도 node-server가 관리합니다 (TB_REMINDER_EMAIL_LOG)
  • 이 API는 인증된 진입점 역할을 하고 node-server로 위임합니다
  • 발송자는 요청 본문이 아니라 인증 토큰에서 확인합니다

HTTP 요청

POST /ai/business/contents/submission-reminder
Authorization: Bearer {access_token}
Content-Type: application/json

권한

권한접근
ROLE_BUSINESS가능
ROLE_AGENCY가능 (에이전시 본인은 ROLE_BUSINESS도 함께 부여됨)
ROLE_AGENCY_CLIENT가능 (고객사 화이트리스트 Bucket 1에 등록)
ROLE_ADMIN가능

Request Body

{
  "applicationId": 19630,
  "campaignId": "1584",
  "campaignName": "테스트 캠페인",
  "email": "creator@example.com",
  "creatorName": "홍길동",
  "delayDays": 3,
  "reminderPhase": "DRAFT_SUBMISSION",
  "dashboardUrl": "https://biz.glowb.io/ko/corp/dashboard/1584"
}
필드타입필수설명
applicationIdlong예캠페인 신청 ID
campaignIdstring예캠페인 번호
campaignNamestring아니오비어 있으면 서버가 캠페인에서 채웁니다
emailstring예수신 크리에이터 이메일
creatorNamestring아니오크리에이터 이름
delayDaysint아니오지연 일수. 메일 본문에 노출되며 기본값은 1입니다
reminderPhasestring예독촉 단계 (아래 표 참고)
dashboardUrlstring아니오메일 내 대시보드 바로가기 URL

memberId는 받지 않습니다. 발송자는 인증 토큰의 로그인 ID를 사용합니다.

독촉 단계 (reminderPhase)

값설명
DRAFT_SUBMISSION초안/스크립트 제출 단계
VIDEO_PRODUCTION제작물 제출 단계
FINAL_SUBMISSION최종 제출물 단계

발송 횟수 제한은 단계별로 따로 계산됩니다.

독촉 대상 판정 — 호출 전에 확인할 것

이 API는 호출되면 보냅니다. 마감이 지났는지, 크리에이터에게 제출 의무가 시작됐는지는 검사하지 않습니다. 누구에게 보낼지는 화면에서 판정해야 하고, 그 판정에 필요한 값은 이미 다른 API가 내려주고 있습니다.

반드시 트리거 확정 여부를 먼저 보세요

제출 마감일은 선정 시점에 임시(placeholder) 값으로 먼저 깔립니다. 배송완료·계약 서명완료 같은 트리거가 발동해야 실제 일자로 확정됩니다(ScheduleTriggerType 참고).

날짜만 보고 판정하면, 아직 제출 의무가 시작되지도 않은 크리에이터가 "지연"으로 잡힙니다. 임시 마감은 이미 지나 있는 경우가 대부분이라 실제로 그렇게 됩니다.

확인 위치필드호출 횟수
진행표 GET /ai/progress-table/item/{collabId}items[].submissionTimeline.script.deadlines.submissionDeadlineConfirmed
(2차 검수면 .content)
캠페인당 1회
검수 상세 GET /ai/business/contents/review/{reviewId}/detailhasTriggered검수 라운드당 1회

두 값은 같은 사실을 가리킵니다. 같은 TB_APPLICATION_SCHEDULE row의 trigger_type이 채워졌는지를 읽으며, 1차 검수는 SCRIPT_SUBMISSION_DEADLINE, 2차 검수는 CONTENT_SUBMISSION_DEADLINE을 봅니다. 이름만 다르니 편한 쪽을 쓰면 됩니다.

여러 명을 한 화면에서 판정한다면 진행표 쪽을 쓰세요

진행표는 캠페인당 1회 호출로 모든 크리에이터의 값을 함께 내려줍니다. 검수 상세는 행마다 호출해야 하므로, 목록 화면에서 같은 목적으로 쓰면 호출 수가 인원수만큼 늘어납니다.

캠페인 일정(TB_CAMPAIGN_SCHEDULE)을 지연 판정에 쓰지 마세요

캠페인 일정은 캠페인 전체의 계획값이라 크리에이터 개인의 마감과 다릅니다. 특히 DRAFT_SUBMISSION 단계는 이름과 달리 실제 의미가 제품 배송이고, VIDEO_PRODUCTION은 회사측 검수 구간입니다. 개인 마감의 대체값으로 쓰면 안 됩니다.

이미 제출했거나 검수 중이면 제외

최종 제출이 끝났거나 최신 검수가 REVIEWING이면 독촉 대상이 아닙니다. 이 API는 그 상태도 검사하지 않으므로 화면에서 걸러야 합니다.

응답

성공 응답 (200 OK)

{
  "status": 200,
  "code": null,
  "message": "독촉 이메일이 발송되었습니다.",
  "data": {
    "success": true,
    "error": null,
    "sentCount": 1,
    "maxCount": 3
  }
}

발송이 거부된 경우 (HTTP 200)

발송 거부·실패도 HTTP 상태는 200으로 내려오며, data에는 기존과 같이 success: false와 사유(data.error)가 담깁니다. 여기에 더해 응답 봉투의 status·code·args에 규격 에러 코드가 실립니다(아래 실패 사유 코드 참고). 봉투의 status는 규격 코드의 상태값(409·400·503·502)이지만 HTTP 상태 코드는 200 그대로입니다.

당일 중복 발송:

{
  "status": 409,
  "code": "SUBMISSION_REMINDER_ALREADY_SENT_TODAY",
  "message": "오늘 이미 독촉 메일을 보냈습니다. 내일 다시 시도해주세요.",
  "data": {
    "success": false,
    "error": "ALREADY_SENT_TODAY",
    "sentCount": null,
    "maxCount": null
  }
}

단계별 한도 초과:

{
  "status": 409,
  "code": "SUBMISSION_REMINDER_LIMIT_REACHED",
  "message": "이 단계의 독촉 메일은 최대 3회까지 보낼 수 있습니다.",
  "args": { "sentCount": 3, "maxCount": 3 },
  "data": {
    "success": false,
    "error": "MAX_REMINDERS_REACHED",
    "sentCount": 3,
    "maxCount": 3
  }
}

node-server 호출 실패:

{
  "status": 502,
  "code": "SUBMISSION_REMINDER_UPSTREAM_FAILED",
  "message": "독촉 메일 발송 서버와 통신하지 못했습니다. 잠시 후 다시 시도해주세요.",
  "data": {
    "success": false,
    "error": "SUBMISSION_REMINDER_UPSTREAM_FAILED",
    "sentCount": null,
    "maxCount": null
  }
}

Response 스키마

필드타입설명
successboolean발송 성공 여부
errorstring실패 사유 코드. 성공 시 null
sentCountint해당 단계에서 지금까지 발송된 횟수 (nullable)
maxCountint단계별 발송 한도 (nullable)

실패 사유 코드

data.error봉투 code봉투 status설명
ALREADY_SENT_TODAYSUBMISSION_REMINDER_ALREADY_SENT_TODAY409오늘 이미 같은 단계로 발송했습니다 (KST 기준 하루 1회)
MAX_REMINDERS_REACHEDSUBMISSION_REMINDER_LIMIT_REACHED409해당 단계의 발송 한도(3회)를 모두 사용했습니다. args.sentCount, args.maxCount
SUBMISSION_REMINDER_FIELD_REQUIREDSUBMISSION_REMINDER_FIELD_REQUIRED400필수 필드가 누락되었습니다. args.field에 누락된 필드명
SUBMISSION_REMINDER_UNAVAILABLESUBMISSION_REMINDER_UNAVAILABLE503서버에 node-server 주소가 설정되지 않아 독촉 메일을 보낼 수 없습니다
SUBMISSION_REMINDER_UPSTREAM_FAILEDSUBMISSION_REMINDER_UPSTREAM_FAILED502node-server 호출 실패, 또는 node-server가 그 밖의 사유로 발송에 실패했습니다

ALREADY_SENT_TODAY·MAX_REMINDERS_REACHED 두 사유는 data.error에 node-server 값을 그대로 둡니다(기존 프론트 분기 유지). 그 밖의 node-server 실패 사유는 data.error를 SUBMISSION_REMINDER_UPSTREAM_FAILED로 정규화하며, node-server 원문 메시지는 서버 로그에만 남습니다. 새로 구현하는 화면은 봉투의 code로 분기하는 것을 권장합니다.

발송 이력이 node-server에 단일 기록되므로, 이 API로 보낸 건과 기존 경로로 보낸 건의 횟수가 합산되어 계산됩니다. 한도가 이중으로 집계되지 않습니다.

발송 횟수 조회

POST /ai/business/contents/submission-reminder/counts
Authorization: Bearer {access_token}
Content-Type: application/json
{ "applicationIds": [19630, 19585] }

응답 (200 OK)

{
  "status": 200,
  "code": null,
  "message": "독촉 발송 횟수 조회가 완료되었습니다.",
  "data": [
    {
      "applicationId": 19630,
      "reminderPhase": "DRAFT_SUBMISSION",
      "count": 1,
      "sentToday": true
    }
  ]
}
필드타입설명
applicationIdlong신청 번호
reminderPhasestring독촉 단계
countint해당 단계에서 지금까지 발송된 횟수
sentTodayboolean오늘(KST) 발송 여부

발송 이력이 없는 신청은 결과에 포함되지 않습니다. 조회에 실패해도 빈 배열을 돌려주며 오류를 던지지 않습니다.

횟수 조회는 반드시 이 API로 하세요

발송과 조회가 서로 다른 경로를 타면 다른 환경의 이력을 읽게 됩니다. 실제로 발송은 test node-server에 기록되고 조회는 prod node-server를 읽어, 독촉을 보냈는데도 화면에 횟수와 "오늘 발송함" 표기가 뜨지 않는 일이 있었습니다.

이 API는 발송과 같은 진입점을 쓰므로 항상 같은 곳을 봅니다.

API 테스트

On this page